]> www.pilppa.org Git - linux-2.6-omap-h63xx.git/commitdiff
Merge branch 'upstream-linus' of master.kernel.org:/pub/scm/linux/kernel/git/jgarzik...
authorLinus Torvalds <torvalds@g5.osdl.org>
Wed, 9 Nov 2005 16:34:36 +0000 (08:34 -0800)
committerLinus Torvalds <torvalds@g5.osdl.org>
Wed, 9 Nov 2005 16:34:36 +0000 (08:34 -0800)
660 files changed:
Documentation/connector/cn_test.c
Documentation/dvb/bt8xx.txt
Documentation/dvb/cards.txt
Documentation/dvb/contributors.txt
Documentation/dvb/get_dvb_firmware
Documentation/fb/fbcon.txt [new file with mode: 0644]
Documentation/feature-removal-schedule.txt
Documentation/filesystems/ext2.txt
Documentation/md.txt
Documentation/s390/Debugging390.txt
Documentation/sched-arch.txt [new file with mode: 0644]
Documentation/video4linux/API.html
Documentation/video4linux/CARDLIST.bttv
Documentation/video4linux/CARDLIST.cx88
Documentation/video4linux/CARDLIST.em28xx [new file with mode: 0644]
Documentation/video4linux/CARDLIST.saa7134
Documentation/video4linux/CARDLIST.tuner
Documentation/video4linux/README.cx88
Documentation/video4linux/README.saa7134
Documentation/video4linux/bttv/Cards
Documentation/video4linux/bttv/README
Documentation/video4linux/bttv/Sound-FAQ
Documentation/video4linux/bttv/Tuners
Documentation/video4linux/lifeview.txt
arch/alpha/kernel/process.c
arch/arm/Kconfig
arch/arm/boot/compressed/misc.c
arch/arm/common/scoop.c
arch/arm/kernel/armksyms.c
arch/arm/kernel/entry-armv.S
arch/arm/kernel/irq.c
arch/arm/kernel/process.c
arch/arm/kernel/smp.c
arch/arm/mach-omap1/leds-h2p2-debug.c
arch/arm/mach-pxa/corgi.c
arch/arm/mach-pxa/poodle.c
arch/arm/mach-pxa/spitz.c
arch/arm/mach-pxa/time.c
arch/arm/mach-pxa/tosa.c
arch/arm/mach-realview/core.c
arch/arm/mach-realview/platsmp.c
arch/arm/mach-s3c2410/Kconfig
arch/arm/mach-s3c2410/mach-bast.c
arch/arm/mach-s3c2410/mach-vr1000.c
arch/arm/mach-sa1100/time.c
arch/arm/plat-omap/ocpi.c
arch/arm26/kernel/process.c
arch/cris/arch-v10/drivers/pcf8563.c
arch/cris/arch-v10/kernel/fasttimer.c
arch/cris/arch-v32/drivers/nandflash.c
arch/cris/arch-v32/drivers/pcf8563.c
arch/cris/arch-v32/kernel/smp.c
arch/cris/kernel/process.c
arch/frv/kernel/process.c
arch/h8300/kernel/process.c
arch/i386/kernel/apm.c
arch/i386/kernel/process.c
arch/i386/kernel/setup.c
arch/i386/kernel/smpboot.c
arch/ia64/ia32/ia32_ioctl.c
arch/ia64/kernel/mca_drv.c
arch/ia64/kernel/process.c
arch/ia64/kernel/smpboot.c
arch/ia64/sn/pci/pcibr/pcibr_provider.c
arch/ia64/sn/pci/pcibr/pcibr_reg.c
arch/m32r/kernel/process.c
arch/m32r/kernel/smpboot.c
arch/m68k/kernel/process.c
arch/mips/au1000/common/setup.c
arch/mips/configs/ddb5476_defconfig
arch/mips/configs/jmr3927_defconfig
arch/mips/configs/ocelot_3_defconfig
arch/mips/configs/pnx8550-v2pci_defconfig
arch/mips/configs/rbhma4500_defconfig
arch/mips/kernel/ioctl32.c
arch/mips/kernel/process.c
arch/mips/kernel/smp.c
arch/mips/tx4938/toshiba_rbtx4938/irq.c
arch/parisc/kernel/asm-offsets.c
arch/parisc/kernel/process.c
arch/parisc/kernel/smp.c
arch/powerpc/Kconfig
arch/powerpc/configs/g5_defconfig
arch/powerpc/kernel/misc_64.S
arch/powerpc/kernel/process.c
arch/powerpc/kernel/prom.c
arch/powerpc/kernel/prom_init.c
arch/powerpc/kernel/rtas.c
arch/powerpc/kernel/setup-common.c
arch/powerpc/kernel/setup_32.c
arch/powerpc/kernel/setup_64.c
arch/powerpc/kernel/signal_32.c
arch/powerpc/kernel/signal_64.c
arch/powerpc/kernel/smp.c
arch/powerpc/kernel/time.c
arch/powerpc/kernel/traps.c
arch/powerpc/kernel/vio.c
arch/powerpc/lib/locks.c
arch/powerpc/mm/fault.c
arch/powerpc/mm/hash_utils_64.c
arch/powerpc/mm/init_64.c
arch/powerpc/mm/mem.c
arch/powerpc/mm/numa.c
arch/powerpc/mm/pgtable_64.c
arch/powerpc/oprofile/op_model_power4.c
arch/powerpc/platforms/iseries/irq.c
arch/powerpc/platforms/iseries/pci.c
arch/powerpc/platforms/iseries/setup.c
arch/powerpc/platforms/iseries/smp.c
arch/powerpc/platforms/powermac/Makefile
arch/powerpc/platforms/powermac/cpufreq_32.c [moved from arch/powerpc/platforms/powermac/cpufreq.c with 99% similarity]
arch/powerpc/platforms/powermac/cpufreq_64.c [new file with mode: 0644]
arch/powerpc/platforms/powermac/setup.c
arch/powerpc/platforms/pseries/iommu.c
arch/powerpc/platforms/pseries/lpar.c
arch/powerpc/platforms/pseries/plpar_wrappers.h
arch/powerpc/platforms/pseries/ras.c
arch/powerpc/platforms/pseries/setup.c
arch/powerpc/sysdev/i8259.c
arch/powerpc/sysdev/u3_iommu.c
arch/ppc/configs/mpc834x_sys_defconfig
arch/ppc/kernel/idle.c
arch/ppc/kernel/misc.S
arch/ppc/kernel/smp.c
arch/ppc/kernel/traps.c
arch/ppc/platforms/83xx/mpc834x_sys.c
arch/ppc/platforms/85xx/stx_gp3.h
arch/ppc/syslib/Makefile
arch/ppc/syslib/m8xx_wdt.c
arch/ppc/syslib/mpc83xx_devices.c
arch/ppc/syslib/mpc83xx_sys.c
arch/ppc/syslib/prom.c
arch/ppc/syslib/prom_init.c
arch/ppc/xmon/xmon.c
arch/ppc64/Kconfig
arch/ppc64/Kconfig.debug
arch/ppc64/kernel/idle.c
arch/ppc64/kernel/machine_kexec.c
arch/ppc64/kernel/misc.S
arch/ppc64/kernel/pci.c
arch/ppc64/kernel/prom.c
arch/ppc64/kernel/prom_init.c
arch/ppc64/kernel/rtas_pci.c
arch/ppc64/kernel/udbg.c
arch/s390/appldata/appldata_base.c
arch/s390/kernel/debug.c
arch/s390/kernel/process.c
arch/s390/kernel/smp.c
arch/s390/mm/fault.c
arch/sh/kernel/process.c
arch/sh/kernel/smp.c
arch/sh64/kernel/process.c
arch/sparc/kernel/process.c
arch/sparc64/kernel/ioctl32.c
arch/sparc64/kernel/process.c
arch/sparc64/kernel/smp.c
arch/sparc64/mm/fault.c
arch/v850/kernel/process.c
arch/x86_64/ia32/ia32_ioctl.c
arch/x86_64/kernel/process.c
arch/x86_64/kernel/smpboot.c
arch/xtensa/kernel/process.c
drivers/acpi/processor_idle.c
drivers/block/amiflop.c
drivers/block/floppy.c
drivers/block/pktcdvd.c
drivers/block/swim3.c
drivers/bluetooth/bpa10x.c
drivers/bluetooth/hci_usb.c
drivers/char/drm/ati_pcigart.c
drivers/char/ip2.c
drivers/char/mwave/tp3780i.c
drivers/char/mxser.c
drivers/char/specialix.c
drivers/char/sysrq.c
drivers/char/tpm/tpm.h
drivers/char/viocons.c
drivers/char/viotape.c
drivers/cpufreq/cpufreq.c
drivers/firmware/dell_rbu.c
drivers/ide/ppc/pmac.c
drivers/infiniband/ulp/srp/ib_srp.c
drivers/input/input.c
drivers/isdn/divert/divert_init.c
drivers/isdn/divert/divert_procfs.c
drivers/isdn/divert/isdn_divert.c
drivers/isdn/hisax/hisax_fcpcipnp.c
drivers/isdn/hisax/st5481_init.c
drivers/isdn/hysdn/hycapi.c
drivers/isdn/hysdn/hysdn_init.c
drivers/isdn/hysdn/hysdn_net.c
drivers/isdn/hysdn/hysdn_procconf.c
drivers/isdn/hysdn/hysdn_proclog.c
drivers/isdn/i4l/isdn_common.c
drivers/isdn/icn/icn.h
drivers/isdn/isdnloop/isdnloop.h
drivers/isdn/sc/includes.h
drivers/macintosh/Kconfig
drivers/macintosh/Makefile
drivers/macintosh/smu.c
drivers/macintosh/via-pmu.c
drivers/macintosh/windfarm.h [new file with mode: 0644]
drivers/macintosh/windfarm_core.c [new file with mode: 0644]
drivers/macintosh/windfarm_cpufreq_clamp.c [new file with mode: 0644]
drivers/macintosh/windfarm_lm75_sensor.c [new file with mode: 0644]
drivers/macintosh/windfarm_pid.c [new file with mode: 0644]
drivers/macintosh/windfarm_pid.h [new file with mode: 0644]
drivers/macintosh/windfarm_pm81.c [new file with mode: 0644]
drivers/macintosh/windfarm_pm91.c [new file with mode: 0644]
drivers/macintosh/windfarm_smu_controls.c [new file with mode: 0644]
drivers/macintosh/windfarm_smu_sensors.c [new file with mode: 0644]
drivers/md/bitmap.c
drivers/md/md.c
drivers/md/multipath.c
drivers/md/raid1.c
drivers/md/raid10.c
drivers/md/raid5.c
drivers/md/raid6main.c
drivers/media/common/ir-common.c
drivers/media/dvb/b2c2/flexcop-fe-tuner.c
drivers/media/dvb/b2c2/flexcop-misc.c
drivers/media/dvb/b2c2/flexcop-reg.h
drivers/media/dvb/b2c2/flexcop.c
drivers/media/dvb/bt8xx/Kconfig
drivers/media/dvb/bt8xx/dst.c
drivers/media/dvb/bt8xx/dst_ca.c
drivers/media/dvb/bt8xx/dst_common.h
drivers/media/dvb/bt8xx/dvb-bt8xx.c
drivers/media/dvb/bt8xx/dvb-bt8xx.h
drivers/media/dvb/dvb-core/demux.h
drivers/media/dvb/dvb-core/dvb_demux.c
drivers/media/dvb/dvb-core/dvb_frontend.c
drivers/media/dvb/dvb-core/dvb_frontend.h
drivers/media/dvb/dvb-usb/a800.c
drivers/media/dvb/dvb-usb/dibusb-mb.c
drivers/media/dvb/dvb-usb/dibusb.h
drivers/media/dvb/dvb-usb/dvb-usb-ids.h
drivers/media/dvb/dvb-usb/dvb-usb-urb.c
drivers/media/dvb/frontends/Kconfig
drivers/media/dvb/frontends/Makefile
drivers/media/dvb/frontends/dvb-pll.c
drivers/media/dvb/frontends/dvb-pll.h
drivers/media/dvb/frontends/lgdt330x.c
drivers/media/dvb/frontends/lgdt330x.h
drivers/media/dvb/frontends/nxt200x.c [new file with mode: 0644]
drivers/media/dvb/frontends/nxt200x.h [new file with mode: 0644]
drivers/media/dvb/frontends/or51132.c
drivers/media/dvb/frontends/or51211.c
drivers/media/dvb/frontends/stv0299.c
drivers/media/dvb/frontends/stv0299.h
drivers/media/dvb/frontends/tda1004x.c
drivers/media/dvb/pluto2/pluto2.c
drivers/media/dvb/ttpci/av7110.c
drivers/media/dvb/ttpci/budget-av.c
drivers/media/dvb/ttpci/budget-ci.c
drivers/media/dvb/ttpci/budget-patch.c
drivers/media/dvb/ttpci/budget.c
drivers/media/dvb/ttusb-budget/dvb-ttusb-budget.c
drivers/media/video/Kconfig
drivers/media/video/Makefile
drivers/media/video/arv.c
drivers/media/video/bt832.c
drivers/media/video/bt832.h
drivers/media/video/bttv-cards.c
drivers/media/video/bttv-driver.c
drivers/media/video/bttv-gpio.c
drivers/media/video/bttv-i2c.c
drivers/media/video/bttv-if.c
drivers/media/video/bttv-risc.c
drivers/media/video/bttv.h
drivers/media/video/bttvp.h
drivers/media/video/cs53l32a.c [new file with mode: 0644]
drivers/media/video/cx88/Kconfig [new file with mode: 0644]
drivers/media/video/cx88/Makefile
drivers/media/video/cx88/cx88-blackbird.c
drivers/media/video/cx88/cx88-cards.c
drivers/media/video/cx88/cx88-core.c
drivers/media/video/cx88/cx88-dvb.c
drivers/media/video/cx88/cx88-i2c.c
drivers/media/video/cx88/cx88-input.c
drivers/media/video/cx88/cx88-mpeg.c
drivers/media/video/cx88/cx88-reg.h
drivers/media/video/cx88/cx88-tvaudio.c
drivers/media/video/cx88/cx88-video.c
drivers/media/video/cx88/cx88.h
drivers/media/video/em28xx/Kconfig [new file with mode: 0644]
drivers/media/video/em28xx/Makefile [new file with mode: 0644]
drivers/media/video/em28xx/em28xx-cards.c [new file with mode: 0644]
drivers/media/video/em28xx/em28xx-core.c [new file with mode: 0644]
drivers/media/video/em28xx/em28xx-i2c.c [new file with mode: 0644]
drivers/media/video/em28xx/em28xx-input.c [new file with mode: 0644]
drivers/media/video/em28xx/em28xx-video.c [new file with mode: 0644]
drivers/media/video/em28xx/em28xx.h [new file with mode: 0644]
drivers/media/video/ir-kbd-gpio.c
drivers/media/video/ir-kbd-i2c.c
drivers/media/video/msp3400.c
drivers/media/video/mt20xx.c
drivers/media/video/saa6588.c
drivers/media/video/saa711x.c [new file with mode: 0644]
drivers/media/video/saa7134/Kconfig [new file with mode: 0644]
drivers/media/video/saa7134/Makefile
drivers/media/video/saa7134/saa6752hs.c
drivers/media/video/saa7134/saa7134-alsa.c [new file with mode: 0644]
drivers/media/video/saa7134/saa7134-cards.c
drivers/media/video/saa7134/saa7134-core.c
drivers/media/video/saa7134/saa7134-dvb.c
drivers/media/video/saa7134/saa7134-empress.c
drivers/media/video/saa7134/saa7134-i2c.c
drivers/media/video/saa7134/saa7134-input.c
drivers/media/video/saa7134/saa7134-oss.c
drivers/media/video/saa7134/saa7134-reg.h
drivers/media/video/saa7134/saa7134-ts.c
drivers/media/video/saa7134/saa7134-tvaudio.c
drivers/media/video/saa7134/saa7134-video.c
drivers/media/video/saa7134/saa7134.h
drivers/media/video/tda7432.c
drivers/media/video/tda8290.c
drivers/media/video/tda9875.c
drivers/media/video/tda9887.c
drivers/media/video/tea5767.c
drivers/media/video/tuner-core.c
drivers/media/video/tuner-simple.c
drivers/media/video/tvaudio.c
drivers/media/video/tveeprom.c
drivers/media/video/tvmixer.c
drivers/media/video/tvp5150.c [new file with mode: 0644]
drivers/media/video/tvp5150_reg.h [new file with mode: 0644]
drivers/media/video/v4l1-compat.c
drivers/media/video/video-buf.c
drivers/media/video/wm8775.c [new file with mode: 0644]
drivers/media/video/zr36016.c
drivers/media/video/zr36050.c
drivers/media/video/zr36060.c
drivers/message/fusion/mptbase.c
drivers/message/fusion/mptbase.h
drivers/message/fusion/mptctl.c
drivers/message/fusion/mptctl.h
drivers/message/fusion/mptlan.h
drivers/misc/hdpuftrs/hdpu_cpustate.c
drivers/misc/hdpuftrs/hdpu_nexus.c
drivers/misc/ibmasm/ibmasm.h
drivers/mtd/chips/cfi_cmdset_0020.c
drivers/mtd/devices/pmc551.c
drivers/mtd/maps/ebony.c
drivers/mtd/maps/ocotea.c
drivers/mtd/maps/walnut.c
drivers/mtd/nand/au1550nd.c
drivers/mtd/nand/autcpu12.c
drivers/mtd/onenand/onenand_base.c
drivers/mtd/rfd_ftl.c
drivers/net/Kconfig
drivers/net/Makefile
drivers/net/b44.c
drivers/net/cassini.c
drivers/net/dm9000.c
drivers/net/fs_enet/fs_enet.h
drivers/net/gianfar.c
drivers/net/gianfar.h
drivers/net/gianfar_ethtool.c
drivers/net/gianfar_mii.c
drivers/net/hp100.c
drivers/net/ibmveth.c
drivers/net/ioc3-eth.c
drivers/net/irda/donauboe.c
drivers/net/iseries_veth.c
drivers/net/mac8390.c
drivers/net/mv643xx_eth.h
drivers/net/ppp_async.c
drivers/net/ppp_generic.c
drivers/net/ppp_mppe.c [new file with mode: 0644]
drivers/net/ppp_mppe.h [new file with mode: 0644]
drivers/net/s2io.c
drivers/net/sk98lin/h/skdrv1st.h
drivers/net/sk_mca.c
drivers/net/sk_mca.h
drivers/net/starfire.c
drivers/net/via-velocity.c
drivers/net/wireless/hostap/hostap.c
drivers/net/wireless/hostap/hostap_hw.c
drivers/net/wireless/hostap/hostap_pci.c
drivers/net/wireless/hostap/hostap_plx.c
drivers/net/wireless/ipw2100.h
drivers/net/wireless/ipw2200.c
drivers/net/wireless/ipw2200.h
drivers/net/wireless/orinoco.h
drivers/net/wireless/prism54/isl_38xx.c
drivers/net/wireless/prism54/isl_38xx.h
drivers/net/wireless/prism54/isl_ioctl.c
drivers/net/wireless/prism54/islpci_dev.c
drivers/net/wireless/prism54/islpci_dev.h
drivers/net/wireless/prism54/islpci_eth.c
drivers/net/wireless/prism54/islpci_hotplug.c
drivers/pcmcia/au1000_pb1x00.c
drivers/pcmcia/au1000_xxs1500.c
drivers/pcmcia/pxa2xx_sharpsl.c
drivers/s390/char/keyboard.h
drivers/s390/cio/qdio.h
drivers/s390/crypto/z90main.c
drivers/s390/net/claw.c
drivers/s390/net/fsm.h
drivers/s390/s390mach.h
drivers/sbus/char/openprom.c
drivers/scsi/3w-xxxx.h
drivers/scsi/a2091.c
drivers/scsi/aic7xxx/aic79xx_osm.h
drivers/scsi/aic7xxx/aic7xxx_osm.h
drivers/scsi/amiga7xx.c
drivers/scsi/bvme6000.c
drivers/scsi/gvp11.c
drivers/scsi/ibmmca.c
drivers/scsi/ips.h
drivers/scsi/megaraid/mega_common.h
drivers/scsi/megaraid/megaraid_mm.h
drivers/scsi/megaraid/megaraid_sas.c
drivers/scsi/mvme147.c
drivers/scsi/mvme16x.c
drivers/scsi/nsp32.h
drivers/scsi/pci2000.h
drivers/scsi/scsi_debug.c
drivers/scsi/sg.c
drivers/scsi/sgiwd93.c
drivers/scsi/wd33c93.c
drivers/telephony/ixj.h
drivers/usb/gadget/dummy_hcd.c
drivers/usb/gadget/lh7a40x_udc.h
drivers/usb/gadget/pxa2xx_udc.c
drivers/usb/gadget/rndis.c
drivers/usb/host/hc_crisv10.c
drivers/usb/media/pwc/pwc-if.c
drivers/usb/media/pwc/pwc.h
drivers/usb/media/w9968cf.c
drivers/usb/misc/sisusbvga/sisusb.c
drivers/usb/misc/sisusbvga/sisusb.h
drivers/usb/misc/sisusbvga/sisusb_con.c
drivers/usb/misc/sisusbvga/sisusb_init.c
drivers/video/Kconfig
drivers/video/amba-clcd.c
drivers/video/backlight/backlight.c
drivers/video/backlight/lcd.c
drivers/video/cfbimgblt.c
drivers/video/console/Kconfig
drivers/video/console/Makefile
drivers/video/console/bitblit.c
drivers/video/console/fbcon.c
drivers/video/console/fbcon.h
drivers/video/console/fbcon_ccw.c [new file with mode: 0644]
drivers/video/console/fbcon_cw.c [new file with mode: 0644]
drivers/video/console/fbcon_rotate.c [new file with mode: 0644]
drivers/video/console/fbcon_rotate.h [new file with mode: 0644]
drivers/video/console/fbcon_ud.c [new file with mode: 0644]
drivers/video/console/tileblit.c
drivers/video/fbmem.c
drivers/video/fbsysfs.c
drivers/video/intelfb/intelfbdrv.c
drivers/video/intelfb/intelfbhw.c
drivers/video/modedb.c
drivers/video/savage/savagefb_driver.c
drivers/video/vga16fb.c
drivers/video/vgastate.c
fs/9p/vfs_file.c
fs/adfs/adfs.h
fs/binfmt_misc.c
fs/compat_ioctl.c
fs/exec.c
fs/ext2/CHANGES [deleted file]
fs/ext2/balloc.c
fs/ext2/ialloc.c
fs/ext2/super.c
fs/ext3/balloc.c
fs/ext3/ialloc.c
fs/ext3/super.c
fs/fat/inode.c
fs/hfs/hfs_fs.h
fs/hfs/inode.c
fs/hfsplus/bnode.c
fs/hfsplus/dir.c
fs/hfsplus/extents.c
fs/hfsplus/hfsplus_fs.h
fs/hfsplus/inode.c
fs/hfsplus/super.c
fs/hfsplus/wrapper.c
fs/hostfs/hostfs_kern.c
fs/hpfs/file.c
fs/hugetlbfs/inode.c
fs/inotify.c
fs/namei.c
fs/namespace.c
fs/ncpfs/ioctl.c
fs/open.c
fs/proc/proc_devtree.c
fs/reiserfs/file.c
fs/udf/file.c
fs/xfs/linux-2.6/xfs_linux.h
fs/xfs/xfs.h
fs/xfs/xfs_dmapi.h
include/asm-arm/arch-s3c2410/uncompress.h
include/asm-arm/hardirq.h
include/asm-arm/hardware/scoop.h
include/asm-arm/smp.h
include/asm-powerpc/ide.h [moved from include/asm-ppc/ide.h with 83% similarity]
include/asm-powerpc/machdep.h
include/asm-powerpc/pmc.h
include/asm-powerpc/ppc-pci.h
include/asm-powerpc/prom.h
include/asm-powerpc/reg.h
include/asm-powerpc/smp.h
include/asm-powerpc/smu.h
include/asm-powerpc/xmon.h
include/asm-ppc/btext.h
include/asm-ppc/io.h
include/asm-ppc/kgdb.h
include/asm-ppc/mpc83xx.h
include/asm-ppc/prom.h
include/asm-ppc64/ide.h [deleted file]
include/asm-ppc64/pci.h
include/asm-ppc64/ppcdebug.h [deleted file]
include/asm-ppc64/prom.h
include/asm-ppc64/udbg.h
include/asm-s390/debug.h
include/asm-s390/ebcdic.h
include/asm-s390/io.h
include/asm-s390/lowcore.h
include/asm-s390/mmu_context.h
include/asm-s390/pgtable.h
include/asm-s390/sigp.h
include/asm-s390/smp.h
include/linux/compat_ioctl.h
include/linux/cpu.h
include/linux/fb.h
include/linux/fs.h
include/linux/fs_enet_pd.h
include/linux/i2c-id.h
include/linux/if_ppp.h
include/linux/if_wanpipe_common.h
include/linux/istallion.h
include/linux/mtd/cfi.h
include/linux/mtd/mtd.h
include/linux/namei.h
include/linux/phonedev.h
include/linux/ppp-comp.h
include/linux/proc_fs.h
include/linux/raid/bitmap.h
include/linux/raid/md.h
include/linux/raid/md_k.h
include/linux/raid/raid1.h
include/linux/raid/raid5.h
include/linux/sched.h
include/linux/stallion.h
include/linux/sysctl.h
include/linux/videodev.h
include/linux/videodev2.h
include/media/audiochip.h
include/media/id.h [deleted file]
include/media/ir-common.h
include/media/ir-kbd-i2c.h [new file with mode: 0644]
include/media/saa7146_vv.h
include/media/tuner.h
include/media/video-buf.h
include/net/bluetooth/bluetooth.h
include/net/bluetooth/hci.h
include/net/bluetooth/hci_core.h
include/net/bluetooth/rfcomm.h
include/net/ipv6.h
include/net/sock.h
init/main.c
kernel/cpu.c
kernel/power/main.c
kernel/power/power.h
kernel/power/snapshot.c
kernel/power/swsusp.c
kernel/sched.c
kernel/softlockup.c
kernel/sysctl.c
net/802/p8023.c
net/ax25/af_ax25.c
net/ax25/ax25_in.c
net/ax25/ax25_route.c
net/bluetooth/af_bluetooth.c
net/bluetooth/hci_core.c
net/bluetooth/hci_event.c
net/bluetooth/hci_sock.c
net/bluetooth/hci_sysfs.c
net/bluetooth/hidp/core.c
net/bluetooth/l2cap.c
net/bluetooth/rfcomm/core.c
net/bluetooth/rfcomm/sock.c
net/bluetooth/sco.c
net/core/dev_mcast.c
net/core/sock.c
net/dccp/ipv4.c
net/dccp/proto.c
net/decnet/dn_table.c
net/ethernet/pe2.c
net/ipv4/af_inet.c
net/ipv4/fib_frontend.c
net/ipv4/ip_options.c
net/ipv4/ip_output.c
net/ipv4/ip_sockglue.c
net/ipv4/ipvs/ip_vs_app.c
net/ipv4/ipvs/ip_vs_core.c
net/ipv4/multipath_wrandom.c
net/ipv4/netfilter/ip_nat_snmp_basic.c
net/ipv4/tcp_ipv4.c
net/ipv6/addrconf.c
net/ipv6/ip6_fib.c
net/ipv6/ip6_output.c
net/ipv6/ip6_tunnel.c
net/ipv6/ipcomp6.c
net/ipv6/ipv6_sockglue.c
net/ipv6/ipv6_syms.c
net/irda/discovery.c
net/irda/irias_object.c
net/rose/rose_route.c
net/sched/cls_fw.c
net/sched/cls_route.c
net/sched/cls_rsvp.h
net/sched/cls_tcindex.c
net/sched/cls_u32.c
net/sched/em_meta.c
net/sched/ematch.c
net/sctp/associola.c
net/sctp/sm_make_chunk.c
net/sunrpc/auth_gss/gss_krb5_seal.c
net/sunrpc/auth_gss/gss_krb5_unseal.c
net/sunrpc/auth_gss/gss_mech_switch.c
net/sunrpc/auth_gss/gss_spkm3_seal.c
net/sunrpc/auth_gss/gss_spkm3_token.c
net/sunrpc/auth_gss/gss_spkm3_unseal.c
net/sunrpc/rpc_pipe.c
net/sunrpc/svc.c
net/sunrpc/xdr.c
net/unix/af_unix.c
net/wanrouter/af_wanpipe.c
net/wanrouter/wanmain.c
net/xfrm/xfrm_state.c
scripts/kconfig/Makefile
scripts/kconfig/conf.c
scripts/kconfig/confdata.c
scripts/kconfig/expr.h
scripts/kconfig/lex.zconf.c_shipped
scripts/kconfig/lkc.h
scripts/kconfig/lkc_proto.h
scripts/kconfig/menu.c
scripts/kconfig/symbol.c
scripts/kconfig/zconf.gperf [new file with mode: 0644]
scripts/kconfig/zconf.hash.c_shipped [new file with mode: 0644]
scripts/kconfig/zconf.l
scripts/kconfig/zconf.tab.c_shipped
scripts/kconfig/zconf.tab.h_shipped [deleted file]
scripts/kconfig/zconf.y
security/selinux/hooks.c
security/selinux/selinuxfs.c
security/selinux/ss/mls.c
sound/drivers/vx/vx_hwdep.c
sound/oss/Kconfig
sound/oss/msnd.c
sound/oss/os.h
sound/oss/rme96xx.c
sound/oss/sh_dac_audio.c
sound/ppc/pmac.h

index b7de82e9c0e014aeff8fecfb3e7b271821b4598c..3e73231695b3107eb743452836e8d0b24d17af85 100644 (file)
@@ -25,7 +25,7 @@
 #include <linux/skbuff.h>
 #include <linux/timer.h>
 
-#include "connector.h"
+#include <linux/connector.h>
 
 static struct cb_id cn_test_id = { 0x123, 0x456 };
 static char cn_test_name[] = "cn_test";
@@ -104,7 +104,7 @@ static int cn_test_want_notify(void)
        req->first = cn_test_id.val + 20;
        req->range = 10;
 
-       NETLINK_CB(skb).dst_groups = ctl->group;
+       NETLINK_CB(skb).dst_group = ctl->group;
        //netlink_broadcast(nls, skb, 0, ctl->group, GFP_ATOMIC);
        netlink_unicast(nls, skb, 0, 0);
 
index cb63b7a93c82f02e47c79076bbf2723f0bec77d2..df6c05453cb517266448c5f2e81e1fc0627f4097 100644 (file)
@@ -1,5 +1,5 @@
-How to get the Nebula, PCTV and Twinhan DST cards working
-=========================================================
+How to get the Nebula, PCTV, FusionHDTV Lite and Twinhan DST cards working
+==========================================================================
 
 This class of cards has a bt878a as the PCI interface, and
 require the bttv driver.
@@ -26,27 +26,31 @@ Furthermore you need to enable
 
 In general you need to load the bttv driver, which will handle the gpio and
 i2c communication for us, plus the common dvb-bt8xx device driver.
-The frontends for Nebula (nxt6000), Pinnacle PCTV (cx24110) and
-TwinHan (dst) are loaded automatically by the dvb-bt8xx device driver.
+The frontends for Nebula (nxt6000), Pinnacle PCTV (cx24110), TwinHan (dst),
+FusionHDTV DVB-T Lite (mt352) and FusionHDTV5 Lite (lgdt330x) are loaded
+automatically by the dvb-bt8xx device driver.
 
-3a) Nebula / Pinnacle PCTV
---------------------------
+3a) Nebula / Pinnacle PCTV / FusionHDTV Lite
+---------------------------------------------
 
    $ modprobe bttv (normally bttv is being loaded automatically by kmod)
-   $ modprobe dvb-bt8xx (or just place dvb-bt8xx in /etc/modules for automatic loading)
+   $ modprobe dvb-bt8xx
+
+(or just place dvb-bt8xx in /etc/modules for automatic loading)
 
 
 3b) TwinHan and Clones
 --------------------------
 
-   $ modprobe bttv i2c_hw=1 card=0x71
+   $ modprobe bttv card=0x71
    $ modprobe dvb-bt8xx
    $ modprobe dst
 
 The value 0x71 will override the PCI type detection for dvb-bt8xx,
-which  is necessary for TwinHan cards.
+which  is necessary for TwinHan cards. Omission of this parameter might result
+in a system lockup.
 
-If you're having an older card (blue color circuit) and card=0x71 locks
+If you're having an older card (blue color PCB) and card=0x71 locks up
 your machine, try using 0x68, too. If that does not work, ask on the
 mailing list.
 
@@ -64,11 +68,47 @@ verbose=0 means complete disabling of messages
 dst_addons takes values 0 and 0x20. A value of 0 means it is a FTA card.
 0x20 means it has a Conditional Access slot.
 
-The autodected values are determined bythe cards 'response
-string' which you can see in your logs e.g.
+The autodetected values are determined by the cards 'response string'
+which you can see in your logs e.g.
 
 dst_get_device_id: Recognise [DSTMCI]
 
+If you need to sent in bug reports on the dst, please do send in a complete
+log with the verbose=4 module parameter. For general usage, the default setting
+of verbose=1 is ideal.
+
+
+4) Multiple cards
+--------------------------
+
+If you happen to be running multiple cards, it would be advisable to load
+the bttv module with the card id. This would help to solve any module loading
+problems that you might face.
+
+For example, if you have a Twinhan and Clones card along with a FusionHDTV5 Lite
+
+       $ modprobe bttv card=0x71 card=0x87
+
+Here the order of the card id is important and should be the same as that of the
+physical order of the cards. Here card=0x71 represents the Twinhan and clones
+and card=0x87 represents Fusion HDTV5 Lite. These arguments can also be
+specified in decimal, rather than hex:
+
+       $ modprobe bttv card=113 card=135
+
+Some examples of card-id's
+
+Pinnacle Sat           0x5e  (94)
+Nebula Digi TV         0x68  (104)
+PC HDTV                        0x70  (112)
+Twinhan                        0x71  (113)
+FusionHDTV DVB-T Lite  0x80  (128)
+FusionHDTV5 Lite       0x87  (135)
+
+For a full list of card-id's, see the V4L Documentation within the kernel
+source:  linux/Documentation/video4linux/CARDLIST.bttv
+
+If you have problems with this please do ask on the mailing list.
 
 --
 Authors: Richard Walker, Jamie Honan, Michael Hunold, Manu Abraham
index efdc4ee9d40c116395374377c5ea932323967d52..19329cf7b09798462293f70928bca66e89b80f5a 100644 (file)
@@ -41,6 +41,12 @@ o Frontends drivers:
    - dib3000mb : DiBcom 3000-MB demodulator
   DVB-S/C/T:
    - dst               : TwinHan DST Frontend
+  ATSC:
+   - nxt200x           : Nxtwave NXT2002 & NXT2004
+   - or51211           : or51211 based (pcHDTV HD2000 card)
+   - or51132           : or51132 based (pcHDTV HD3000 card)
+   - bcm3510           : Broadcom BCM3510
+   - lgdt330x          : LG Electronics DT3302 & DT3303
 
 
 o Cards based on the Phillips saa7146 multimedia PCI bridge chip:
@@ -62,6 +68,10 @@ o Cards based on the Conexant Bt8xx PCI bridge:
   - Nebula Electronics DigiTV
   - TwinHan DST
   - Avermedia DVB-T
+  - ChainTech digitop DST-1000 DVB-S
+  - pcHDTV HD-2000 TV
+  - DViCO FusionHDTV DVB-T Lite
+  - DViCO FusionHDTV5 Lite
 
 o Technotrend / Hauppauge DVB USB devices:
   - Nova USB
@@ -83,3 +93,30 @@ o DiBcom DVB-T USB based devices:
   - DiBcom USB2.0 DVB-T reference device (non-public)
 
 o Experimental support for the analog module of the Siemens DVB-C PCI card
+
+o Cards based on the Conexant cx2388x PCI bridge:
+  - ADS Tech Instant TV DVB-T PCI
+  - ATI HDTV Wonder
+  - digitalnow DNTV Live! DVB-T
+  - DViCO FusionHDTV DVB-T1
+  - DViCO FusionHDTV DVB-T Plus
+  - DViCO FusionHDTV3 Gold-Q
+  - DViCO FusionHDTV3 Gold-T
+  - DViCO FusionHDTV5 Gold
+  - Hauppauge Nova-T DVB-T
+  - KWorld/VStream XPert DVB-T
+  - pcHDTV HD3000 HDTV
+  - TerraTec Cinergy 1400 DVB-T
+  - WinFast DTV1000-T
+
+o Cards based on the Phillips saa7134 PCI bridge:
+  - Medion 7134
+  - Pinnacle PCTV 300i DVB-T + PAL
+  - LifeView FlyDVB-T DUO
+  - Typhoon DVB-T Duo Digital/Analog Cardbus
+  - Philips TOUGH DVB-T reference design
+  - Philips EUROPA V3 reference design
+  - Compro Videomate DVB-T300
+  - Compro Videomate DVB-T200
+  - AVerMedia AVerTVHD MCE A180
+
index c9d5ce3707012e05fab9b7f18a4f7eaef66fe44d..2cbd2d0f6fdf73475d9623fbdcf9075094373d4e 100644 (file)
@@ -75,5 +75,22 @@ Ernst Peinlich <e.peinlich@inode.at>
 Peter Beutner <p.beutner@gmx.net>
   for the IR code for the ttusb-dec driver
 
+Wilson Michaels <wilsonmichaels@earthlink.net>
+  for the lgdt330x frontend driver, and various bugfixes
+
+Michael Krufky <mkrufky@m1k.net>
+  for maintaining v4l/dvb inter-tree dependencies
+
+Taylor Jacob <rtjacob@earthlink.net>
+  for the nxt2002 frontend driver
+
+Jean-Francois Thibert <jeanfrancois@sagetv.com>
+  for the nxt2004 frontend driver
+
+Kirk Lapray <kirk.lapray@gmail.com>
+  for the or51211 and or51132 frontend drivers, and
+  for merging the nxt2002 and nxt2004 modules into a
+  single nxt200x frontend driver.
+
 (If you think you should be in this list, but you are not, drop a
  line to the DVB mailing list)
index a750f0101d9de7d15f47a13e0cc7240b3299ba1f..be6eb4c759915ff4c56db77c8448e14da3b3aaca 100644 (file)
@@ -22,7 +22,7 @@ use File::Temp qw/ tempdir /;
 use IO::Handle;
 
 @components = ( "sp8870", "sp887x", "tda10045", "tda10046", "av7110", "dec2000t",
-               "dec2540t", "dec3000s", "vp7041", "dibusb", "nxt2002",
+               "dec2540t", "dec3000s", "vp7041", "dibusb", "nxt2002", "nxt2004",
                "or51211", "or51132_qam", "or51132_vsb");
 
 # Check args
@@ -252,6 +252,23 @@ sub nxt2002 {
     $outfile;
 }
 
+sub nxt2004 {
+    my $sourcefile = "AVerTVHD_MCE_A180_Drv_v1.2.2.16.zip";
+    my $url = "http://www.aver.com/support/Drivers/$sourcefile";
+    my $hash = "111cb885b1e009188346d72acfed024c";
+    my $outfile = "dvb-fe-nxt2004.fw";
+    my $tmpdir = tempdir(DIR => "/tmp", CLEANUP => 1);
+
+    checkstandard();
+
+    wgetfile($sourcefile, $url);
+    unzip($sourcefile, $tmpdir);
+    verify("$tmpdir/3xHybrid.sys", $hash);
+    extract("$tmpdir/3xHybrid.sys", 465304, 9584, $outfile);
+
+    $outfile;
+}
+
 sub or51211 {
     my $fwfile = "dvb-fe-or51211.fw";
     my $url = "http://linuxtv.org/downloads/firmware/$fwfile";
diff --git a/Documentation/fb/fbcon.txt b/Documentation/fb/fbcon.txt
new file mode 100644 (file)
index 0000000..08dce0f
--- /dev/null
@@ -0,0 +1,152 @@
+The Framebuffer Console
+=======================
+
+       The framebuffer console (fbcon), as its name implies, is a text
+console running on top of the framebuffer device. It has the functionality of
+any standard text console driver, such as the VGA console, with the added
+features that can be attributed to the graphical nature of the framebuffer.
+
+        In the x86 architecture, the framebuffer console is optional, and
+some even treat it as a toy. For other architectures, it is the only available
+display device, text or graphical.
+
+        What are the features of fbcon?  The framebuffer console supports
+high resolutions, varying font types, display rotation, primitive multihead,
+etc. Theoretically, multi-colored fonts, blending, aliasing, and any feature
+made available by the underlying graphics card are also possible.
+
+A. Configuration
+
+       The framebuffer console can be enabled by using your favorite kernel
+configuration tool.  It is under Device Drivers->Graphics Support->Support for
+framebuffer devices->Framebuffer Console Support. Select 'y' to compile
+support statically, or 'm' for module support.  The module will be fbcon.
+
+       In order for fbcon to activate, at least one framebuffer driver is
+required, so choose from any of the numerous drivers available. For x86
+systems, they almost universally have VGA cards, so vga16fb and vesafb will
+always be available. However, using a chipset-specific driver will give you
+more speed and features, such as the ability to change the video mode
+dynamically.
+
+       To display the penguin logo, choose any logo available in Logo
+Configuration->Boot up logo.
+
+       Also, you will need to select at least one compiled-in fonts, but if
+you don't do anything, the kernel configuration tool will select one for you,
+usually an 8x16 font.
+
+GOTCHA: A common bug report is enabling the framebuffer without enabling the
+framebuffer console.  Depending on the driver, you may get a blanked or
+garbled display, but the system still boots to completion.  If you are
+fortunate to have a driver that does not alter the graphics chip, then you
+will still get a VGA console.
+
+B. Loading
+
+Possible scenarios:
+
+1. Driver and fbcon are compiled statically
+
+        Usually, fbcon will automatically take over your console. The notable
+        exception is vesafb.  It needs to be explicitly activated with the
+        vga= boot option parameter.
+
+2. Driver is compiled statically, fbcon is compiled as a module
+
+        Depending on the driver, you either get a standard console, or a
+        garbled display, as mentioned above.  To get a framebuffer console,
+        do a 'modprobe fbcon'.
+
+3. Driver is compiled as a module, fbcon is compiled statically
+
+        You get your standard console.  Once the driver is loaded with
+        'modprobe xxxfb', fbcon automatically takes over the console with
+        the possible exception of using the fbcon=map:n option. See below.
+
+4. Driver and fbcon are compiled as a module.
+
+        You can load them in any order. Once both are loaded, fbcon will take
+        over the console.
+
+C. Boot options
+
+         The framebuffer console has several, largely unknown, boot options
+         that can change its behavior.
+
+1. fbcon=font:<name>
+
+        Select the initial font to use. The value 'name' can be any of the
+        compiled-in fonts: VGA8x16, 7x14, 10x18, VGA8x8, MINI4x6, RomanLarge,
+        SUN8x16, SUN12x22, ProFont6x11, Acorn8x8, PEARL8x8.
+
+       Note, not all drivers can handle font with widths not divisible by 8,
+        such as vga16fb.
+
+2. fbcon=scrollback:<value>[k]
+
+        The scrollback buffer is memory that is used to preserve display
+        contents that has already scrolled past your view.  This is accessed
+        by using the Shift-PageUp key combination.  The value 'value' is any
+        integer. It defaults to 32KB.  The 'k' suffix is optional, and will
+        multiply the 'value' by 1024.
+
+3. fbcon=map:<0123>
+
+        This is an interesting option. It tells which driver gets mapped to
+        which console. The value '0123' is a sequence that gets repeated until
+        the total length is 64 which is the number of consoles available. In
+        the above example, it is expanded to 012301230123... and the mapping
+        will be:
+
+               tty | 1 2 3 4 5 6 7 8 9 ...
+               fb  | 0 1 2 3 0 1 2 3 0 ...
+
+               ('cat /proc/fb' should tell you what the fb numbers are)
+
+       One side effect that may be useful is using a map value that exceeds
+       the number of loaded fb drivers. For example, if only one driver is
+       available, fb0, adding fbcon=map:1 tells fbcon not to take over the
+       console.
+
+       Later on, when you want to map the console the to the framebuffer
+       device, you can use the con2fbmap utility.
+
+4. fbcon=vc:<n1>-<n2>
+
+       This option tells fbcon to take over only a range of consoles as
+       specified by the values 'n1' and 'n2'. The rest of the consoles
+       outside the given range will still be controlled by the standard
+       console driver.
+
+       NOTE: For x86 machines, the standard console is the VGA console which
+       is typically located on the same video card.  Thus, the consoles that
+       are controlled by the VGA console will be garbled.
+
+4. fbcon=rotate:<n>
+
+        This option changes the orientation angle of the console display. The
+        value 'n' accepts the following:
+
+             0 - normal orientation (0 degree)
+             1 - clockwise orientation (90 degrees)
+             2 - upside down orientation (180 degrees)
+             3 - counterclockwise orientation (270 degrees)
+
+       The angle can be changed anytime afterwards by 'echoing' the same
+       numbers to any one of the 2 attributes found in
+       /sys/class/graphics/fb{x}
+
+               con_rotate     - rotate the display of the active console
+               con_rotate_all - rotate the display of all consoles
+
+       Console rotation will only become available if Console Rotation
+       Support is compiled in your kernel.
+
+       NOTE: This is purely console rotation.  Any other applications that
+       use the framebuffer will remain at their 'normal'orientation.
+       Actually, the underlying fb driver is totally ignorant of console
+       rotation.
+
+---
+Antonino Daplas <adaplas@pol.net>
index decdf9917e0ddd4d809a673ef0dc5538f741b34f..429db4bf98eccd14ad2f0ebce7480a6f93c2a178 100644 (file)
@@ -25,6 +25,13 @@ Who: Adrian Bunk <bunk@stusta.de>
 
 ---------------------------
 
+What:  drivers depending on OBSOLETE_OSS_DRIVER
+When:  January 2006
+Why:   OSS drivers with ALSA replacements
+Who:   Adrian Bunk <bunk@stusta.de>
+
+---------------------------
+
 What:  RCU API moves to EXPORT_SYMBOL_GPL
 When:  April 2006
 Files: include/linux/rcupdate.h, kernel/rcupdate.c
@@ -60,6 +67,21 @@ Who: Jody McIntyre <scjody@steamballoon.com>
 
 ---------------------------
 
+What:  Video4Linux API 1 ioctls and video_decoder.h from Video devices.
+When:  July 2006
+Why:   V4L1 AP1 was replaced by V4L2 API. during migration from 2.4 to 2.6
+       series. The old API have lots of drawbacks and don't provide enough
+       means to work with all video and audio standards. The newer API is
+       already available on the main drivers and should be used instead.
+       Newer drivers should use v4l_compat_translate_ioctl function to handle
+       old calls, replacing to newer ones.
+       Decoder iocts are using internally to allow video drivers to
+       communicate with video decoders. This should also be improved to allow
+       V4L2 calls being translated into compatible internal ioctls.
+Who:   Mauro Carvalho Chehab <mchehab@brturbo.com.br>
+
+---------------------------
+
 What:  i2c sysfs name change: in1_ref, vid deprecated in favour of cpu0_vid
 When:  November 2005
 Files: drivers/i2c/chips/adm1025.c, drivers/i2c/chips/adm1026.c
@@ -111,3 +133,10 @@ Why:       This interface has been obsoleted by the new layer3-independent
        to link against API-compatible library on top of libnfnetlink_queue 
        instead of the current 'libipq'.
 Who:   Harald Welte <laforge@netfilter.org>
+
+---------------------------
+
+What:  EXPORT_SYMBOL(lookup_hash)
+When:  January 2006
+Why:   Too low-level interface.  Use lookup_one_len or lookup_create instead.
+Who:   Christoph Hellwig <hch@lst.de>
index d16334ec48ba02cc719d9072dd800f12d9ed17cb..a8edb376b04191654b6ab9a868c4cb529a65176b 100644 (file)
@@ -17,8 +17,6 @@ set using tune2fs(8). Kernel-determined defaults are indicated by (*).
 bsddf                  (*)     Makes `df' act like BSD.
 minixdf                                Makes `df' act like Minix.
 
-check                          Check block and inode bitmaps at mount time
-                               (requires CONFIG_EXT2_CHECK).
 check=none, nocheck    (*)     Don't do extra checking of bitmaps on mount
                                (check=normal and check=strict options removed)
 
index e2b536992a2798ccaf32133f9d6ed08879a6778d..23e6cce40f9c9855d1ac1621530e9e308e5a1c97 100644 (file)
@@ -116,3 +116,122 @@ and it's role in the array.
 
 Once started with RUN_ARRAY, uninitialized spares can be added with
 HOT_ADD_DISK.
+
+
+
+MD devices in sysfs
+-------------------
+md devices appear in sysfs (/sys) as regular block devices,
+e.g.
+   /sys/block/md0
+
+Each 'md' device will contain a subdirectory called 'md' which
+contains further md-specific information about the device.
+
+All md devices contain:
+  level
+     a text file indicating the 'raid level'.  This may be a standard
+     numerical level prefixed by "RAID-" - e.g. "RAID-5", or some
+     other name such as "linear" or "multipath".
+     If no raid level has been set yet (array is still being
+     assembled), this file will be empty.
+
+  raid_disks
+     a text file with a simple number indicating the number of devices
+     in a fully functional array.  If this is not yet known, the file
+     will be empty.  If an array is being resized (not currently
+     possible) this will contain the larger of the old and new sizes.
+
+As component devices are added to an md array, they appear in the 'md'
+directory as new directories named
+      dev-XXX
+where XXX is a name that the kernel knows for the device, e.g. hdb1.
+Each directory contains:
+
+      block
+        a symlink to the block device in /sys/block, e.g.
+            /sys/block/md0/md/dev-hdb1/block -> ../../../../block/hdb/hdb1
+
+      super
+        A file containing an image of the superblock read from, or
+        written to, that device.
+
+      state
+        A file recording the current state of the device in the array
+       which can be a comma separated list of
+             faulty   - device has been kicked from active use due to
+                         a detected fault
+             in_sync  - device is a fully in-sync member of the array
+             spare    - device is working, but not a full member.
+                        This includes spares that are in the process
+                        of being recoverred to
+       This list make grow in future.
+
+
+An active md device will also contain and entry for each active device
+in the array.  These are named
+
+    rdNN
+
+where 'NN' is the possition in the array, starting from 0.
+So for a 3 drive array there will be rd0, rd1, rd2.
+These are symbolic links to the appropriate 'dev-XXX' entry.
+Thus, for example,
+       cat /sys/block/md*/md/rd*/state
+will show 'in_sync' on every line.
+
+
+
+Active md devices for levels that support data redundancy (1,4,5,6)
+also have
+
+   sync_action
+     a text file that can be used to monitor and control the rebuild
+     process.  It contains one word which can be one of:
+       resync        - redundancy is being recalculated after unclean
+                       shutdown or creation
+       recover       - a hot spare is being built to replace a
+                       failed/missing device
+       idle          - nothing is happening
+       check         - A full check of redundancy was requested and is
+                       happening.  This reads all block and checks
+                       them. A repair may also happen for some raid
+                       levels.
+       repair        - A full check and repair is happening.  This is
+                       similar to 'resync', but was requested by the
+                       user, and the write-intent bitmap is NOT used to
+                      optimise the process.
+
+      This file is writable, and each of the strings that could be
+      read are meaningful for writing.
+
+       'idle' will stop an active resync/recovery etc.  There is no
+           guarantee that another resync/recovery may not be automatically
+          started again, though some event will be needed to trigger
+           this.
+       'resync' or 'recovery' can be used to restart the
+           corresponding operation if it was stopped with 'idle'.
+       'check' and 'repair' will start the appropriate process
+           providing the current state is 'idle'.
+
+   mismatch_count
+      When performing 'check' and 'repair', and possibly when
+      performing 'resync', md will count the number of errors that are
+      found.  The count in 'mismatch_cnt' is the number of sectors
+      that were re-written, or (for 'check') would have been
+      re-written.  As most raid levels work in units of pages rather
+      than sectors, this my be larger than the number of actual errors
+      by a factor of the number of sectors in a page.
+
+Each active md device may also have attributes specific to the
+personality module that manages it.
+These are specific to the implementation of the module and could
+change substantially if the implementation changes.
+
+These currently include
+
+  stripe_cache_size  (currently raid5 only)
+      number of entries in the stripe cache.  This is writable, but
+      there are upper and lower limits (32768, 16).  Default is 128.
+  strip_cache_active (currently raid5 only)
+      number of active entries in the stripe cache
index adbfe620c0615003c3628fac77c3d082d900aa09..844c03fe7921d62539b63c7748bfc120fb7b87e1 100644 (file)
@@ -871,7 +871,7 @@ by playing with the --adjust-vma parameter to objdump.
 
 
 
-extern inline void spin_lock(spinlock_t *lp)
+static inline void spin_lock(spinlock_t *lp)
 {
       a0:       18 34           lr      %r3,%r4
       a2:       a7 3a 03 bc     ahi     %r3,956
diff --git a/Documentation/sched-arch.txt b/Documentation/sched-arch.txt
new file mode 100644 (file)
index 0000000..941615a
--- /dev/null
@@ -0,0 +1,89 @@
+       CPU Scheduler implementation hints for architecture specific code
+
+       Nick Piggin, 2005
+
+Context switch
+==============
+1. Runqueue locking
+By default, the switch_to arch function is called with the runqueue
+locked. This is usually not a problem unless switch_to may need to
+take the runqueue lock. This is usually due to a wake up operation in
+the context switch. See include/asm-ia64/system.h for an example.
+
+To request the scheduler call switch_to with the runqueue unlocked,
+you must `#define __ARCH_WANT_UNLOCKED_CTXSW` in a header file
+(typically the one where switch_to is defined).
+
+Unlocked context switches introduce only a very minor performance
+penalty to the core scheduler implementation in the CONFIG_SMP case.
+
+2. Interrupt status
+By default, the switch_to arch function is called with interrupts
+disabled. Interrupts may be enabled over the call if it is likely to
+introduce a significant interrupt latency by adding the line
+`#define __ARCH_WANT_INTERRUPTS_ON_CTXSW` in the same place as for
+unlocked context switches. This define also implies
+`__ARCH_WANT_UNLOCKED_CTXSW`. See include/asm-arm/system.h for an
+example.
+
+
+CPU idle
+========
+Your cpu_idle routines need to obey the following rules:
+
+1. Preempt should now disabled over idle routines. Should only
+   be enabled to call schedule() then disabled again.
+
+2. need_resched/TIF_NEED_RESCHED is only ever set, and will never
+   be cleared until the running task has called schedule(). Idle
+   threads need only ever query need_resched, and may never set or
+   clear it.
+
+3. When cpu_idle finds (need_resched() == 'true'), it should call
+   schedule(). It should not call schedule() otherwise.
+
+4. The only time interrupts need to be disabled when checking
+   need_resched is if we are about to sleep the processor until
+   the next interrupt (this doesn't provide any protection of
+   need_resched, it prevents losing an interrupt).
+
+       4a. Common problem with this type of sleep appears to be:
+               local_irq_disable();
+               if (!need_resched()) {
+                       local_irq_enable();
+                       *** resched interrupt arrives here ***
+                       __asm__("sleep until next interrupt");
+               }
+
+5. TIF_POLLING_NRFLAG can be set by idle routines that do not
+   need an interrupt to wake them up when need_resched goes high.
+   In other words, they must be periodically polling need_resched,
+   although it may be reasonable to do some background work or enter
+   a low CPU priority.
+
+       5a. If TIF_POLLING_NRFLAG is set, and we do decide to enter
+           an interrupt sleep, it needs to be cleared then a memory
+           barrier issued (followed by a test of need_resched with
+           interrupts disabled, as explained in 3).
+
+arch/i386/kernel/process.c has examples of both polling and
+sleeping idle functions.
+
+
+Possible arch/ problems
+=======================
+
+Possible arch problems I found (and either tried to fix or didn't):
+
+h8300 - Is such sleeping racy vs interrupts? (See #4a).
+        The H8/300 manual I found indicates yes, however disabling IRQs
+        over the sleep mean only NMIs can wake it up, so can't fix easily
+        without doing spin waiting.
+
+ia64 - is safe_halt call racy vs interrupts? (does it sleep?) (See #4a)
+
+sh64 - Is sleeping racy vs interrupts? (See #4a)
+
+sparc - IRQs on at this point(?), change local_irq_save to _disable.
+      - TODO: needs secondary CPUs to disable preempt (See #1)
+
index 441407b12a9f49563f9132a44dbf830739041428..afbe9ae7ee9682c6b4377efc8b7e8a80d3fe1087 100644 (file)
@@ -8,7 +8,7 @@ V4L original API</a>
 </td><td>
 Obsoleted by V4L2 API
 </td></tr><tr><td>
-<A HREF=http://www.linuxtv.org/downloads/video4linux/API/V4L2_API.html>
+<A HREF=http://www.linuxtv.org/downloads/video4linux/API/V4L2_API>
 V4L2 API</a>
 </td><td>
 Should be used for new projects
index ec785f9f15a3168e5d95f230b19da743e7a588db..2404099996ac40d83a6e5512eb98498749c5bc83 100644 (file)
-card=0 -  *** UNKNOWN/GENERIC ***
-card=1 - MIRO PCTV
-card=2 - Hauppauge (bt848)
-card=3 - STB, Gateway P/N 6000699 (bt848)
-card=4 - Intel Create and Share PCI/ Smart Video Recorder III
-card=5 - Diamond DTV2000
-card=6 - AVerMedia TVPhone
-card=7 - MATRIX-Vision MV-Delta
-card=8 - Lifeview FlyVideo II (Bt848) LR26 / MAXI TV Video PCI2 LR26
-card=9 - IMS/IXmicro TurboTV
-card=10 - Hauppauge (bt878)
-card=11 - MIRO PCTV pro
-card=12 - ADS Technologies Channel Surfer TV (bt848)
-card=13 - AVerMedia TVCapture 98
-card=14 - Aimslab Video Highway Xtreme (VHX)
-card=15 - Zoltrix TV-Max
-card=16 - Prolink Pixelview PlayTV (bt878)
-card=17 - Leadtek WinView 601
-card=18 - AVEC Intercapture
-card=19 - Lifeview FlyVideo II EZ /FlyKit LR38 Bt848 (capture only)
-card=20 - CEI Raffles Card
-card=21 - Lifeview FlyVideo 98/ Lucky Star Image World ConferenceTV LR50
-card=22 - Askey CPH050/ Phoebe Tv Master + FM
-card=23 - Modular Technology MM201/MM202/MM205/MM210/MM215 PCTV, bt878
-card=24 - Askey CPH05X/06X (bt878) [many vendors]
-card=25 - Terratec TerraTV+ Version 1.0 (Bt848)/ Terra TValue Version 1.0/ Vobis TV-Boostar
-card=26 - Hauppauge WinCam newer (bt878)
-card=27 - Lifeview FlyVideo 98/ MAXI TV Video PCI2 LR50
-card=28 - Terratec TerraTV+ Version 1.1 (bt878)
-card=29 - Imagenation PXC200
-card=30 - Lifeview FlyVideo 98 LR50
-card=31 - Formac iProTV, Formac ProTV I (bt848)
-card=32 - Intel Create and Share PCI/ Smart Video Recorder III
-card=33 - Terratec TerraTValue Version Bt878
-card=34 - Leadtek WinFast 2000/ WinFast 2000 XP
-card=35 - Lifeview FlyVideo 98 LR50 / Chronos Video Shuttle II
-card=36 - Lifeview FlyVideo 98FM LR50 / Typhoon TView TV/FM Tuner
-card=37 - Prolink PixelView PlayTV pro
-card=38 - Askey CPH06X TView99
-card=39 - Pinnacle PCTV Studio/Rave
-card=40 - STB TV PCI FM, Gateway P/N 6000704 (bt878), 3Dfx VoodooTV 100
-card=41 - AVerMedia TVPhone 98
-card=42 - ProVideo PV951
-card=43 - Little OnAir TV
-card=44 - Sigma TVII-FM
-card=45 - MATRIX-Vision MV-Delta 2
-card=46 - Zoltrix Genie TV/FM
-card=47 - Terratec TV/Radio+
-card=48 - Askey CPH03x/ Dynalink Magic TView
-card=49 - IODATA GV-BCTV3/PCI
-card=50 - Prolink PV-BT878P+4E / PixelView PlayTV PAK / Lenco MXTV-9578 CP
-card=51 - Eagle Wireless Capricorn2 (bt878A)
-card=52 - Pinnacle PCTV Studio Pro
-card=53 - Typhoon TView RDS + FM Stereo / KNC1 TV Station RDS
-card=54 - Lifeview FlyVideo 2000 /FlyVideo A2/ Lifetec LT 9415 TV [LR90]
-card=55 - Askey CPH031/ BESTBUY Easy TV
-card=56 - Lifeview FlyVideo 98FM LR50
-card=57 - GrandTec 'Grand Video Capture' (Bt848)
-card=58 - Askey CPH060/ Phoebe TV Master Only (No FM)
-card=59 - Askey CPH03x TV Capturer
-card=60 - Modular Technology MM100PCTV
-card=61 - AG Electronics GMV1
-card=62 - Askey CPH061/ BESTBUY Easy TV (bt878)
-card=63 - ATI TV-Wonder
-card=64 - ATI TV-Wonder VE
-card=65 - Lifeview FlyVideo 2000S LR90
-card=66 - Terratec TValueRadio
-card=67 - IODATA GV-BCTV4/PCI
-card=68 - 3Dfx VoodooTV FM (Euro), VoodooTV 200 (USA)
-card=69 - Active Imaging AIMMS
-card=70 - Prolink Pixelview PV-BT878P+ (Rev.4C,8E)
-card=71 - Lifeview FlyVideo 98EZ (capture only) LR51
-card=72 - Prolink Pixelview PV-BT878P+9B (PlayTV Pro rev.9B FM+NICAM)
-card=73 - Sensoray 311
-card=74 - RemoteVision MX (RV605)
-card=75 - Powercolor MTV878/ MTV878R/ MTV878F
-card=76 - Canopus WinDVR PCI (COMPAQ Presario 3524JP, 5112JP)
-card=77 - GrandTec Multi Capture Card (Bt878)
-card=78 - Jetway TV/Capture JW-TV878-FBK, Kworld KW-TV878RF
-card=79 - DSP Design TCVIDEO
-card=80 - Hauppauge WinTV PVR
-card=81 - IODATA GV-BCTV5/PCI
-card=82 - Osprey 100/150 (878)
-card=83 - Osprey 100/150 (848)
-card=84 - Osprey 101 (848)
-card=85 - Osprey 101/151
-card=86 - Osprey 101/151 w/ svid
-card=87 - Osprey 200/201/250/251
-card=88 - Osprey 200/250
-card=89 - Osprey 210/220
-card=90 - Osprey 500
-card=91 - Osprey 540
-card=92 - Osprey 2000
-card=93 - IDS Eagle
-card=94 - Pinnacle PCTV Sat
-card=95 - Formac ProTV II (bt878)
-card=96 - MachTV
-card=97 - Euresys Picolo
-card=98 - ProVideo PV150
-card=99 - AD-TVK503
-card=100 - Hercules Smart TV Stereo
-card=101 - Pace TV & Radio Card
-card=102 - IVC-200
-card=103 - Grand X-Guard / Trust 814PCI
-card=104 - Nebula Electronics DigiTV
-card=105 - ProVideo PV143
-card=106 - PHYTEC VD-009-X1 MiniDIN (bt878)
-card=107 - PHYTEC VD-009-X1 Combi (bt878)
-card=108 - PHYTEC VD-009 MiniDIN (bt878)
-card=109 - PHYTEC VD-009 Combi (bt878)
-card=110 - IVC-100
-card=111 - IVC-120G
-card=112 - pcHDTV HD-2000 TV
-card=113 - Twinhan DST + clones
-card=114 - Winfast VC100
-card=115 - Teppro TEV-560/InterVision IV-560
-card=116 - SIMUS GVC1100
-card=117 - NGS NGSTV+
-card=118 - LMLBT4
-card=119 - Tekram M205 PRO
-card=120 - Conceptronic CONTVFMi
-card=121 - Euresys Picolo Tetra
-card=122 - Spirit TV Tuner
-card=123 - AVerMedia AVerTV DVB-T 771
-card=124 - AverMedia AverTV DVB-T 761
-card=125 - MATRIX Vision Sigma-SQ
-card=126 - MATRIX Vision Sigma-SLC
-card=127 - APAC Viewcomp 878(AMAX)
-card=128 - DViCO FusionHDTV DVB-T Lite
-card=129 - V-Gear MyVCD
-card=130 - Super TV Tuner
-card=131 - Tibet Systems 'Progress DVR' CS16
-card=132 - Kodicom 4400R (master)
-card=133 - Kodicom 4400R (slave)
-card=134 - Adlink RTV24
-card=135 - DViCO FusionHDTV 5 Lite
-card=136 - Acorp Y878F
+  0 ->  *** UNKNOWN/GENERIC ***
+  1 -> MIRO PCTV
+  2 -> Hauppauge (bt848)
+  3 -> STB, Gateway P/N 6000699 (bt848)
+  4 -> Intel Create and Share PCI/ Smart Video Recorder III
+  5 -> Diamond DTV2000
+  6 -> AVerMedia TVPhone
+  7 -> MATRIX-Vision MV-Delta
+  8 -> Lifeview FlyVideo II (Bt848) LR26 / MAXI TV Video PCI2 LR26
+  9 -> IMS/IXmicro TurboTV
+ 10 -> Hauppauge (bt878)                                   [0070:13eb,0070:3900,2636:10b4]
+ 11 -> MIRO PCTV pro
+ 12 -> ADS Technologies Channel Surfer TV (bt848)
+ 13 -> AVerMedia TVCapture 98                              [1461:0002,1461:0004,1461:0300]
+ 14 -> Aimslab Video Highway Xtreme (VHX)
+ 15 -> Zoltrix TV-Max                                      [a1a0:a0fc]
+ 16 -> Prolink Pixelview PlayTV (bt878)
+ 17 -> Leadtek WinView 601
+ 18 -> AVEC Intercapture
+ 19 -> Lifeview FlyVideo II EZ /FlyKit LR38 Bt848 (capture only)
+ 20 -> CEI Raffles Card
+ 21 -> Lifeview FlyVideo 98/ Lucky Star Image World ConferenceTV LR50
+ 22 -> Askey CPH050/ Phoebe Tv Master + FM                 [14ff:3002]
+ 23 -> Modular Technology MM201/MM202/MM205/MM210/MM215 PCTV, bt878 [14c7:0101]
+ 24 -> Askey CPH05X/06X (bt878) [many vendors]             [144f:3002,144f:3005,144f:5000,14ff:3000]
+ 25 -> Terratec TerraTV+ Version 1.0 (Bt848)/ Terra TValue Version 1.0/ Vobis TV-Boostar
+ 26 -> Hauppauge WinCam newer (bt878)
+ 27 -> Lifeview FlyVideo 98/ MAXI TV Video PCI2 LR50
+ 28 -> Terratec TerraTV+ Version 1.1 (bt878)               [153b:1127,1852:1852]
+ 29 -> Imagenation PXC200                                  [1295:200a]
+ 30 -> Lifeview FlyVideo 98 LR50                           [1f7f:1850]
+ 31 -> Formac iProTV, Formac ProTV I (bt848)
+ 32 -> Intel Create and Share PCI/ Smart Video Recorder III
+ 33 -> Terratec TerraTValue Version Bt878                  [153b:1117,153b:1118,153b:1119,153b:111a,153b:1134,153b:5018]
+ 34 -> Leadtek WinFast 2000/ WinFast 2000 XP               [107d:6606,107d:6609,6606:217d,f6ff:fff6]
+ 35 -> Lifeview FlyVideo 98 LR50 / Chronos Video Shuttle II [1851:1850,1851:a050]
+ 36 -> Lifeview FlyVideo 98FM LR50 / Typhoon TView TV/FM Tuner [1852:1852]
+ 37 -> Prolink PixelView PlayTV pro
+ 38 -> Askey CPH06X TView99                                [144f:3000,144f:a005,a04f:a0fc]
+ 39 -> Pinnacle PCTV Studio/Rave                           [11bd:0012,bd11:1200,bd11:ff00,11bd:ff12]
+ 40 -> STB TV PCI FM, Gateway P/N 6000704 (bt878), 3Dfx VoodooTV 100 [10b4:2636,10b4:2645,121a:3060]
+ 41 -> AVerMedia TVPhone 98                                [1461:0001,1461:0003]
+ 42 -> ProVideo PV951                                      [aa0c:146c]
+ 43 -> Little OnAir TV
+ 44 -> Sigma TVII-FM
+ 45 -> MATRIX-Vision MV-Delta 2
+ 46 -> Zoltrix Genie TV/FM                                 [15b0:4000,15b0:400a,15b0:400d,15b0:4010,15b0:4016]
+ 47 -> Terratec TV/Radio+                                  [153b:1123]
+ 48 -> Askey CPH03x/ Dynalink Magic TView
+ 49 -> IODATA GV-BCTV3/PCI                                 [10fc:4020]
+ 50 -> Prolink PV-BT878P+4E / PixelView PlayTV PAK / Lenco MXTV-9578 CP
+ 51 -> Eagle Wireless Capricorn2 (bt878A)
+ 52 -> Pinnacle PCTV Studio Pro
+ 53 -> Typhoon TView RDS + FM Stereo / KNC1 TV Station RDS
+ 54 -> Lifeview FlyVideo 2000 /FlyVideo A2/ Lifetec LT 9415 TV [LR90]
+ 55 -> Askey CPH031/ BESTBUY Easy TV
+ 56 -> Lifeview FlyVideo 98FM LR50                         [a051:41a0]
+ 57 -> GrandTec 'Grand Video Capture' (Bt848)              [4344:4142]
+ 58 -> Askey CPH060/ Phoebe TV Master Only (No FM)
+ 59 -> Askey CPH03x TV Capturer
+ 60 -> Modular Technology MM100PCTV
+ 61 -> AG Electronics GMV1                                 [15cb:0101]
+ 62 -> Askey CPH061/ BESTBUY Easy TV (bt878)
+ 63 -> ATI TV-Wonder                                       [1002:0001]
+ 64 -> ATI TV-Wonder VE                                    [1002:0003]
+ 65 -> Lifeview FlyVideo 2000S LR90
+ 66 -> Terratec TValueRadio                                [153b:1135,153b:ff3b]
+ 67 -> IODATA GV-BCTV4/PCI                                 [10fc:4050]
+ 68 -> 3Dfx VoodooTV FM (Euro), VoodooTV 200 (USA)         [121a:3000,10b4:2637]
+ 69 -> Active Imaging AIMMS
+ 70 -> Prolink Pixelview PV-BT878P+ (Rev.4C,8E)
+ 71 -> Lifeview FlyVideo 98EZ (capture only) LR51          [1851:1851]
+ 72 -> Prolink Pixelview PV-BT878P+9B (PlayTV Pro rev.9B FM+NICAM) [1554:4011]
+ 73 -> Sensoray 311                                        [6000:0311]
+ 74 -> RemoteVision MX (RV605)
+ 75 -> Powercolor MTV878/ MTV878R/ MTV878F
+ 76 -> Canopus WinDVR PCI (COMPAQ Presario 3524JP, 5112JP) [0e11:0079]
+ 77 -> GrandTec Multi Capture Card (Bt878)
+ 78 -> Jetway TV/Capture JW-TV878-FBK, Kworld KW-TV878RF   [0a01:17de]
+ 79 -> DSP Design TCVIDEO
+ 80 -> Hauppauge WinTV PVR                                 [0070:4500]
+ 81 -> IODATA GV-BCTV5/PCI                                 [10fc:4070,10fc:d018]
+ 82 -> Osprey 100/150 (878)                                [0070:ff00]
+ 83 -> Osprey 100/150 (848)
+ 84 -> Osprey 101 (848)
+ 85 -> Osprey 101/151
+ 86 -> Osprey 101/151 w/ svid
+ 87 -> Osprey 200/201/250/251
+ 88 -> Osprey 200/250                                      [0070:ff01]
+ 89 -> Osprey 210/220
+ 90 -> Osprey 500                                          [0070:ff02]
+ 91 -> Osprey 540                                          [0070:ff04]
+ 92 -> Osprey 2000                                         [0070:ff03]
+ 93 -> IDS Eagle
+ 94 -> Pinnacle PCTV Sat                                   [11bd:001c]
+ 95 -> Formac ProTV II (bt878)
+ 96 -> MachTV
+ 97 -> Euresys Picolo
+ 98 -> ProVideo PV150                                      [aa00:1460,aa01:1461,aa02:1462,aa03:1463,aa04:1464,aa05:1465,aa06:1466,aa07:1467]
+ 99 -> AD-TVK503
+100 -> Hercules Smart TV Stereo
+101 -> Pace TV & Radio Card
+102 -> IVC-200                                             [0000:a155,0001:a155,0002:a155,0003:a155,0100:a155,0101:a155,0102:a155,0103:a155]
+103 -> Grand X-Guard / Trust 814PCI                        [0304:0102]
+104 -> Nebula Electronics DigiTV                           [0071:0101]
+105 -> ProVideo PV143                                      [aa00:1430,aa00:1431,aa00:1432,aa00:1433,aa03:1433]
+106 -> PHYTEC VD-009-X1 MiniDIN (bt878)
+107 -> PHYTEC VD-009-X1 Combi (bt878)
+108 -> PHYTEC VD-009 MiniDIN (bt878)
+109 -> PHYTEC VD-009 Combi (bt878)
+110 -> IVC-100                                             [ff00:a132]
+111 -> IVC-120G                                            [ff00:a182,ff01:a182,ff02:a182,ff03:a182,ff04:a182,ff05:a182,ff06:a182,ff07:a182,ff08:a182,ff09:a182,ff0a:a182,ff0b:a182,ff0c:a182,ff0d:a182,ff0e:a182,ff0f:a182]
+112 -> pcHDTV HD-2000 TV                                   [7063:2000]
+113 -> Twinhan DST + clones                                [11bd:0026,1822:0001,270f:fc00]
+114 -> Winfast VC100                                       [107d:6607]
+115 -> Teppro TEV-560/InterVision IV-560
+116 -> SIMUS GVC1100                                       [aa6a:82b2]
+117 -> NGS NGSTV+
+118 -> LMLBT4
+119 -> Tekram M205 PRO
+120 -> Conceptronic CONTVFMi
+121 -> Euresys Picolo Tetra                                [1805:0105,1805:0106,1805:0107,1805:0108]
+122 -> Spirit TV Tuner
+123 -> AVerMedia AVerTV DVB-T 771                          [1461:0771]
+124 -> AverMedia AverTV DVB-T 761                          [1461:0761]
+125 -> MATRIX Vision Sigma-SQ
+126 -> MATRIX Vision Sigma-SLC
+127 -> APAC Viewcomp 878(AMAX)
+128 -> DViCO FusionHDTV DVB-T Lite                         [18ac:db10]
+129 -> V-Gear MyVCD
+130 -> Super TV Tuner
+131 -> Tibet Systems 'Progress DVR' CS16
+132 -> Kodicom 4400R (master)
+133 -> Kodicom 4400R (slave)
+134 -> Adlink RTV24
+135 -> DViCO FusionHDTV 5 Lite                             [18ac:d500]
+136 -> Acorp Y878F                                         [9511:1540]
+137 -> Conceptronic CTVFMi v2
+138 -> Prolink Pixelview PV-BT878P+ (Rev.2E)
+139 -> Prolink PixelView PlayTV MPEG2 PV-M4900
+140 -> Osprey 440                                          [0070:ff07]
+141 -> Asound Skyeye PCTV
index 03deb0726aa4476b2c141eb8e16bfb49b9c47704..a1017d1a85d4b83988865fc47af683023fa22ba6 100644 (file)
@@ -1,32 +1,37 @@
-card=0 - UNKNOWN/GENERIC
-card=1 - Hauppauge WinTV 34xxx models
-card=2 - GDI Black Gold
-card=3 - PixelView
-card=4 - ATI TV Wonder Pro
-card=5 - Leadtek Winfast 2000XP Expert
-card=6 - AverTV Studio 303 (M126)
-card=7 - MSI TV-@nywhere Master
-card=8 - Leadtek Winfast DV2000
-card=9 - Leadtek PVR 2000
-card=10 - IODATA GV-VCP3/PCI
-card=11 - Prolink PlayTV PVR
-card=12 - ASUS PVR-416
-card=13 - MSI TV-@nywhere
-card=14 - KWorld/VStream XPert DVB-T
-card=15 - DViCO FusionHDTV DVB-T1
-card=16 - KWorld LTV883RF
-card=17 - DViCO FusionHDTV 3 Gold-Q
-card=18 - Hauppauge Nova-T DVB-T
-card=19 - Conexant DVB-T reference design
-card=20 - Provideo PV259
-card=21 - DViCO FusionHDTV DVB-T Plus
-card=22 - digitalnow DNTV Live! DVB-T
-card=23 - pcHDTV HD3000 HDTV
-card=24 - Hauppauge WinTV 28xxx (Roslyn) models
-card=25 - Digital-Logic MICROSPACE Entertainment Center (MEC)
-card=26 - IODATA GV/BCTV7E
-card=27 - PixelView PlayTV Ultra Pro (Stereo)
-card=28 - DViCO FusionHDTV 3 Gold-T
-card=29 - ADS Tech Instant TV DVB-T PCI
-card=30 - TerraTec Cinergy 1400 DVB-T
-card=31 - DViCO FusionHDTV 5 Gold
+  0 -> UNKNOWN/GENERIC
+  1 -> Hauppauge WinTV 34xxx models                        [0070:3400,0070:3401]
+  2 -> GDI Black Gold                                      [14c7:0106,14c7:0107]
+  3 -> PixelView                                           [1554:4811]
+  4 -> ATI TV Wonder Pro                                   [1002:00f8]
+  5 -> Leadtek Winfast 2000XP Expert                       [107d:6611,107d:6613]
+  6 -> AverTV Studio 303 (M126)                            [1461:000b]
+  7 -> MSI TV-@nywhere Master                              [1462:8606]
+  8 -> Leadtek Winfast DV2000                              [107d:6620]
+  9 -> Leadtek PVR 2000                                    [107d:663b,107d:663C]
+ 10 -> IODATA GV-VCP3/PCI                                  [10fc:d003]
+ 11 -> Prolink PlayTV PVR
+ 12 -> ASUS PVR-416                                        [1043:4823]
+ 13 -> MSI TV-@nywhere
+ 14 -> KWorld/VStream XPert DVB-T                          [17de:08a6]
+ 15 -> DViCO FusionHDTV DVB-T1                             [18ac:db00]
+ 16 -> KWorld LTV883RF
+ 17 -> DViCO FusionHDTV 3 Gold-Q                           [18ac:d810]
+ 18 -> Hauppauge Nova-T DVB-T                              [0070:9002]
+ 19 -> Conexant DVB-T reference design                     [14f1:0187]
+ 20 -> Provideo PV259                                      [1540:2580]
+ 21 -> DViCO FusionHDTV DVB-T Plus                         [18ac:db10]
+ 22 -> pcHDTV HD3000 HDTV                                  [7063:3000]
+ 23 -> digitalnow DNTV Live! DVB-T                         [17de:a8a6]
+ 24 -> Hauppauge WinTV 28xxx (Roslyn) models               [0070:2801]
+ 25 -> Digital-Logic MICROSPACE Entertainment Center (MEC) [14f1:0342]
+ 26 -> IODATA GV/BCTV7E                                    [10fc:d035]
+ 27 -> PixelView PlayTV Ultra Pro (Stereo)
+ 28 -> DViCO FusionHDTV 3 Gold-T                           [18ac:d820]
+ 29 -> ADS Tech Instant TV DVB-T PCI                       [1421:0334]
+ 30 -> TerraTec Cinergy 1400 DVB-T                         [153b:1166]
+ 31 -> DViCO FusionHDTV 5 Gold                             [18ac:d500]
+ 32 -> AverMedia UltraTV Media Center PCI 550              [1461:8011]
+ 33 -> Kworld V-Stream Xpert DVD
+ 34 -> ATI HDTV Wonder                                     [1002:a101]
+ 35 -> WinFast DTV1000-T                                   [107d:665f]
+ 36 -> AVerTV 303 (M126)                                   [1461:000a]
diff --git a/Documentation/video4linux/CARDLIST.em28xx b/Documentation/video4linux/CARDLIST.em28xx
new file mode 100644 (file)
index 0000000..a0c7cad
--- /dev/null
@@ -0,0 +1,10 @@
+  0 -> Unknown EM2800 video grabber             (em2800)        [eb1a:2800]
+  1 -> Unknown EM2820/2840 video grabber        (em2820/em2840)
+  2 -> Terratec Cinergy 250 USB                 (em2820/em2840) [0ccd:0036]
+  3 -> Pinnacle PCTV USB 2                      (em2820/em2840) [2304:0208]
+  4 -> Hauppauge WinTV USB 2                    (em2820/em2840) [2040:4200]
+  5 -> MSI VOX USB 2.0                          (em2820/em2840) [eb1a:2820]
+  6 -> Terratec Cinergy 200 USB                 (em2800)
+  7 -> Leadtek Winfast USB II                   (em2800)
+  8 -> Kworld USB2800                           (em2800)
+  9 -> Pinnacle Dazzle DVC 90                   (em2820/em2840) [2304:0207]
index dc57225f39be5b973f74fe0e7f2b451bdc1c7821..57c9d631db56210359ee75cce70825b41e78e631 100644 (file)
@@ -6,10 +6,10 @@
   5 -> SKNet Monster TV                         [1131:4e85]
   6 -> Tevion MD 9717
   7 -> KNC One TV-Station RDS / Typhoon TV Tuner RDS [1131:fe01,1894:fe01]
-  8 -> Terratec Cinergy 400 TV                  [153B:1142]
+  8 -> Terratec Cinergy 400 TV                  [153b:1142]
   9 -> Medion 5044
  10 -> Kworld/KuroutoShikou SAA7130-TVPCI
- 11 -> Terratec Cinergy 600 TV                  [153B:1143]
+ 11 -> Terratec Cinergy 600 TV                  [153b:1143]
  12 -> Medion 7134                              [16be:0003]
  13 -> Typhoon TV+Radio 90031
  14 -> ELSA EX-VISION 300TV                     [1048:226b]
@@ -36,8 +36,8 @@
  35 -> AverMedia AverTV Studio 305              [1461:2115]
  36 -> UPMOST PURPLE TV                         [12ab:0800]
  37 -> Items MuchTV Plus / IT-005
- 38 -> Terratec Cinergy 200 TV                  [153B:1152]
- 39 -> LifeView FlyTV Platinum Mini             [5168:0212]
+ 38 -> Terratec Cinergy 200 TV                  [153b:1152]
+ 39 -> LifeView FlyTV Platinum Mini             [5168:0212,4e42:0212]
  40 -> Compro VideoMate TV PVR/FM               [185b:c100]
  41 -> Compro VideoMate TV Gold+                [185b:c100]
  42 -> Sabrent SBT-TVFM (saa7130)
@@ -46,7 +46,7 @@
  45 -> Avermedia AVerTV Studio 307              [1461:9715]
  46 -> AVerMedia Cardbus TV/Radio (E500)        [1461:d6ee]
  47 -> Terratec Cinergy 400 mobile              [153b:1162]
- 48 -> Terratec Cinergy 600 TV MK3              [153B:1158]
+ 48 -> Terratec Cinergy 600 TV MK3              [153b:1158]
  49 -> Compro VideoMate Gold+ Pal               [185b:c200]
  50 -> Pinnacle PCTV 300i DVB-T + PAL           [11bd:002d]
  51 -> ProVideo PV952                           [1540:9524]
  55 -> LifeView FlyDVB-T DUO                    [5168:0502,5168:0306]
  56 -> Avermedia AVerTV 307                     [1461:a70a]
  57 -> Avermedia AVerTV GO 007 FM               [1461:f31f]
- 58 -> ADS Tech Instant TV (saa7135)            [1421:0350,1421:0370]
+ 58 -> ADS Tech Instant TV (saa7135)            [1421:0350,1421:0370,1421:1370]
  59 -> Kworld/Tevion V-Stream Xpert TV PVR7134
  60 -> Typhoon DVB-T Duo Digital/Analog Cardbus [4e42:0502]
  61 -> Philips TOUGH DVB-T reference design     [1131:2004]
  62 -> Compro VideoMate TV Gold+II
  63 -> Kworld Xpert TV PVR7134
- 64 -> FlyTV mini Asus Digimatrix               [1043:0210,1043:0210]
+ 64 -> FlyTV mini Asus Digimatrix               [1043:0210]
  65 -> V-Stream Studio TV Terminator
  66 -> Yuan TUN-900 (saa7135)
+ 67 -> Beholder BeholdTV 409 FM                 [0000:4091]
+ 68 -> GoTView 7135 PCI                         [5456:7135]
+ 69 -> Philips EUROPA V3 reference design       [1131:2004]
+ 70 -> Compro Videomate DVB-T300                [185b:c900]
+ 71 -> Compro Videomate DVB-T200                [185b:c901]
+ 72 -> RTD Embedded Technologies VFG7350        [1435:7350]
+ 73 -> RTD Embedded Technologies VFG7330        [1435:7330]
+ 74 -> LifeView FlyTV Platinum Mini2            [14c0:1212]
+ 75 -> AVerMedia AVerTVHD MCE A180              [1461:1044]
+ 76 -> SKNet MonsterTV Mobile                   [1131:4ee9]
+ 77 -> Pinnacle PCTV 110i (saa7133)             [11bd:002e]
+ 78 -> ASUSTeK P7131 Dual                       [1043:4862]
+ 79 -> Sedna/MuchTV PC TV Cardbus TV/Radio (ITO25 Rev:2B)
+ 80 -> ASUS Digimatrix TV                       [1043:0210]
+ 81 -> Philips Tiger reference design           [1131:2018]
index f5876be658a64f3724df1ef71cc41b5786f15a38..ec840ca6f45501e215c52fe6b4a6540f7702512a 100644 (file)
@@ -53,7 +53,7 @@ tuner=51 - Philips PAL/SECAM_D (FM 1256 I-H3)
 tuner=52 - Thomson DDT 7610 (ATSC/NTSC)
 tuner=53 - Philips FQ1286
 tuner=54 - tda8290+75
-tuner=55 - LG PAL (TAPE series)
+tuner=55 - TCL 2002MB
 tuner=56 - Philips PAL/SECAM multi (FQ1216AME MK4)
 tuner=57 - Philips FQ1236A MK4
 tuner=58 - Ymec TVision TVF-8531MF/8831MF/8731MF
@@ -65,3 +65,5 @@ tuner=63 - Philips FMD1216ME MK3 Hybrid Tuner
 tuner=64 - LG TDVS-H062F/TUA6034
 tuner=65 - Ymec TVF66T5-B/DFF
 tuner=66 - LG NTSC (TALN mini series)
+tuner=67 - Philips TD1316 Hybrid Tuner
+tuner=68 - Philips TUV1236D ATSC/NTSC dual in
index 897ab834839adf005e195f182ed9a9db5a6ff80a..06a33a4f52fdfd074163b52d91317ec7d6df4008 100644 (file)
@@ -17,9 +17,9 @@ audio
        - The chip specs for the on-chip TV sound decoder are next
          to useless :-/
        - Neverless the builtin TV sound decoder starts working now,
-          at least for PAL-BG.  Other TV norms need other code ...
-          FOR ANY REPORTS ON THIS PLEASE MENTION THE TV NORM YOU ARE
-          USING.
+         at least for PAL-BG.  Other TV norms need other code ...
+         FOR ANY REPORTS ON THIS PLEASE MENTION THE TV NORM YOU ARE
+         USING.
        - Most tuner chips do provide mono sound, which may or may not
          be useable depending on the board design.  With the Hauppauge
          cards it works, so there is mono sound available as fallback.
@@ -65,5 +65,5 @@ Have fun,
 
   Gerd
 
--- 
+--
 Gerd Knorr <kraxel@bytesex.org> [SuSE Labs]
index 1f788e498effe392cd48d0a907a88a6601bdea72..b911f08718744a43a4f553886f03596a037718b1 100644 (file)
@@ -78,5 +78,5 @@ Have fun,
 
   Gerd
 
--- 
+--
 Gerd Knorr <kraxel@bytesex.org> [SuSE Labs]
index 8f1941ede4daa6018af217cef805d43179bfb4f7..d3389655ad96be9b9e5350bcd0a0c5d0ad4e70ee 100644 (file)
@@ -149,11 +149,11 @@ Lifeview Flyvideo Series:
   2) There is a print on the PCB:
       LR25       = Flyvideo (Zoran ZR36120, SAA7110A)
       LR26 Rev.N = Flyvideo II (Bt848)
-           Rev.O = Flyvideo II (Bt878)
+          Rev.O = Flyvideo II (Bt878)
       LR37 Rev.C = Flyvideo EZ (Capture only, ZR36120 + SAA7110)
       LR38 Rev.A1= Flyvideo II EZ (Bt848 capture only)
       LR50 Rev.Q = Flyvideo 98 (w/eeprom and PCI subsystem ID)
-           Rev.W = Flyvideo 98 (no eeprom)
+          Rev.W = Flyvideo 98 (no eeprom)
       LR51 Rev.E = Flyvideo 98 EZ (capture only)
       LR90       = Flyvideo 2000 (Bt878)
                   Flyvideo 2000S (Bt878) w/Stereo TV (Package incl. LR91 daughterboard)
@@ -163,7 +163,7 @@ Lifeview Flyvideo Series:
       LR136     = Flyvideo 2100/3100 (Low profile, SAA7130/SAA7134)
       LR137      = Flyvideo DV2000/DV3000 (SAA7130/SAA7134 + IEEE1394)
       LR138 Rev.C= Flyvideo 2000 (SAA7130)
-               or Flyvideo 3000 (SAA7134) w/Stereo TV
+               or Flyvideo 3000 (SAA7134) w/Stereo TV
                   These exist in variations w/FM and w/Remote sometimes denoted
                   by suffixes "FM" and "R".
   3) You have a laptop (miniPCI card):
@@ -197,7 +197,7 @@ Typhoon TV card series:
   50680 "TV Tuner Pal BG" (blue package)= Pixelview PV-BT878P+ (Rev 9B)
   50681 "TV Tuner PCI Pal I" (variant of 50680)
   50682 "TView TV/FM Tuner Pal BG"       = Flyvideo 98FM (LR50 Rev.Q)
-         Note: The package has a picture of CPH05x (which would be a real TView)
+        Note: The package has a picture of CPH05x (which would be a real TView)
   50683 "TV Tuner PCI SECAM" (variant of 50680)
   50684 "TV Tuner Pal BG"                = Pixelview 878TV(Rev.3D)
   50686 "TV Tuner"                       = KNC1 TV Station
@@ -418,9 +418,9 @@ Lifetec/Medion/Tevion/Aldi
 --------------------------
    LT9306/MD9306 = CPH061
    LT9415/MD9415 = LR90 Rev.F or Rev.G
-          MD9592 = Avermedia TVphone98 (PCI_ID=1461:0003), PCB-Rev=M168II-B (w/TDA9873H)
-          MD9717 = KNC One (Rev D4, saa7134, FM1216 MK2 tuner)
-          MD5044 = KNC One (Rev D4, saa7134, FM1216ME MK3 tuner)
+         MD9592 = Avermedia TVphone98 (PCI_ID=1461:0003), PCB-Rev=M168II-B (w/TDA9873H)
+         MD9717 = KNC One (Rev D4, saa7134, FM1216 MK2 tuner)
+         MD5044 = KNC One (Rev D4, saa7134, FM1216ME MK3 tuner)
 
 Modular Technologies (www.modulartech.com) UK
 ---------------------------------------------
@@ -453,10 +453,10 @@ Technisat
    Discos ADR PC-Karte ISA (no TV!)
    Discos ADR PC-Karte PCI (probably no TV?)
    Techni-PC-Sat (Sat. analog)
-         Rev 1.2 (zr36120, vpx3220, stv0030, saa5246, BSJE3-494A)
+        Rev 1.2 (zr36120, vpx3220, stv0030, saa5246, BSJE3-494A)
    Mediafocus I (zr36120/zr36125, drp3510, Sat. analog + ADR Radio)
    Mediafocus II (saa7146, Sat. analog)
-         SatADR Rev 2.1 (saa7146a, saa7113h, stv0056a, msp3400c, drp3510a, BSKE3-307A)
+        SatADR Rev 2.1 (saa7146a, saa7113h, stv0056a, msp3400c, drp3510a, BSKE3-307A)
    SkyStar 1 DVB  (AV7110) = Technotrend Premium
    SkyStar 2 DVB  (B2C2) (=Sky2PC)
 
index a72f4c94fb0b7be0a4b7c73e182382d9f2071cd1..7ca2154c2bf5eb75221c9186361333b3fe4bfdc6 100644 (file)
@@ -42,9 +42,9 @@ bttv uses the PCI Subsystem ID to autodetect the card type.  lspci lists
 the Subsystem ID in the second line, looks like this:
 
 00:0a.0 Multimedia video controller: Brooktree Corporation Bt878 (rev 02)
-        Subsystem: Hauppauge computer works Inc. WinTV/GO
-        Flags: bus master, medium devsel, latency 32, IRQ 5
-        Memory at e2000000 (32-bit, prefetchable) [size=4K]
+       Subsystem: Hauppauge computer works Inc. WinTV/GO
+       Flags: bus master, medium devsel, latency 32, IRQ 5
+       Memory at e2000000 (32-bit, prefetchable) [size=4K]
 
 only bt878-based cards can have a subsystem ID (which does not mean
 that every card really has one).  bt848 cards can't have a Subsystem
index b8c9c2605ce236e1e2454af74b1641abd0fb4c6f..1e6328f91083646a38e4dc46a384daee83b8abf2 100644 (file)
@@ -61,8 +61,8 @@ line for your board.  The important fields are these two:
 struct tvcard
 {
        [ ... ]
-        u32 gpiomask;
-        u32 audiomux[6]; /* Tuner, Radio, external, internal, mute, stereo */
+       u32 gpiomask;
+       u32 audiomux[6]; /* Tuner, Radio, external, internal, mute, stereo */
 };
 
 gpiomask specifies which pins are used to control the audio mux chip.
@@ -126,11 +126,11 @@ muxsel          - video mux, input->registervalue mapping
 pll             - same as pll= insmod option
 tuner_type      - same as tuner= insmod option
 *_modulename    - hint whenever some card needs this or that audio
-                  module loaded to work properly.
+                 module loaded to work properly.
 has_radio      - whenever this TV card has a radio tuner.
 no_msp34xx     - "1" disables loading of msp3400.o module
-no_tda9875     - "1" disables loading of tda9875.o module 
-needs_tvaudio  - set to "1" to load tvaudio.o module 
+no_tda9875     - "1" disables loading of tda9875.o module
+needs_tvaudio  - set to "1" to load tvaudio.o module
 
 If some config item is specified both from the tvcards array and as
 insmod option, the insmod option takes precedence.
@@ -144,5 +144,5 @@ Good luck,
 
 PS: If you have a new working entry, mail it to me.
 
--- 
+--
 Gerd Knorr <kraxel@bytesex.org>
index d18fbc70c0e0cdc220ef9635712ac326d50acb68..0a371d34954210e73dfadc811447f6d87845aafd 100644 (file)
@@ -21,7 +21,7 @@ SAMSUNG Tuner identification: (e.g. TCPM9091PD27)
    J= NTSC-Japan
    L= Secam LL
    M= BG+I+DK
-   N= NTSC 
+   N= NTSC
    Q= BG+I+DK+LL
  [89]: ?
  [125]:
@@ -96,7 +96,7 @@ LG Innotek Tuner:
   TADC-H002F: NTSC (L,175/410?; 2-B, C-W+11, W+12-69)
   TADC-M201D: PAL D/K+B/G+I (L,143/425)  (sound control at I2C address 0xc8)
   TADC-T003F: NTSC Taiwan  (L,175/410?; 2-B, C-W+11, W+12-69)
-  Suffix: 
+  Suffix:
     P= Standard phono female socket
     D= IEC female socket
     F= F-connector
index b07ea79c2b7ea21ad68db4b2b6f306399602ab67..05f9eb57aac95b843a969a50fb76b4faac57ac62 100644 (file)
@@ -10,33 +10,33 @@ bt878:
 ------------------------------------------------------------------------------
 
 saa7134:
-                /* LifeView FlyTV Platinum FM (LR214WF) */
-                /* "Peter Missel <peter.missel@onlinehome.de> */
-                .name           = "LifeView FlyTV Platinum FM",
-                /*      GP27    MDT2005 PB4 pin 10 */
-                /*      GP26    MDT2005 PB3 pin 9 */
-                /*      GP25    MDT2005 PB2 pin 8 */
-                /*      GP23    MDT2005 PB1 pin 7 */
-                /*      GP22    MDT2005 PB0 pin 6 */
-                /*      GP21    MDT2005 PB5 pin 11 */
-                /*      GP20    MDT2005 PB6 pin 12 */
-                /*      GP19    MDT2005 PB7 pin 13 */
-                /*      nc      MDT2005 PA3 pin 2 */
-                /*      Remote  MDT2005 PA2 pin 1 */
-                /*      GP18    MDT2005 PA1 pin 18 */
-                /*      nc      MDT2005 PA0 pin 17 strap low */
+               /* LifeView FlyTV Platinum FM (LR214WF) */
+               /* "Peter Missel <peter.missel@onlinehome.de> */
+               .name           = "LifeView FlyTV Platinum FM",
+               /*      GP27    MDT2005 PB4 pin 10 */
+               /*      GP26    MDT2005 PB3 pin 9 */
+               /*      GP25    MDT2005 PB2 pin 8 */
+               /*      GP23    MDT2005 PB1 pin 7 */
+               /*      GP22    MDT2005 PB0 pin 6 */
+               /*      GP21    MDT2005 PB5 pin 11 */
+               /*      GP20    MDT2005 PB6 pin 12 */
+               /*      GP19    MDT2005 PB7 pin 13 */
+               /*      nc      MDT2005 PA3 pin 2 */
+               /*      Remote  MDT2005 PA2 pin 1 */
+               /*      GP18    MDT2005 PA1 pin 18 */
+               /*      nc      MDT2005 PA0 pin 17 strap low */
 
-                /*      GP17    Strap "GP7"=High */
-                /*      GP16    Strap "GP6"=High
-                                0=Radio 1=TV
-                                Drives SA630D ENCH1 and HEF4052 A1 pins
-                                to do FM radio through SIF input */
-                /*      GP15    nc */
-                /*      GP14    nc */
-                /*      GP13    nc */
-                /*      GP12    Strap "GP5" = High */
-                /*      GP11    Strap "GP4" = High */
-                /*      GP10    Strap "GP3" = High */
-                /*      GP09    Strap "GP2" = Low */
-                /*      GP08    Strap "GP1" = Low */
-                /*      GP07.00 nc */
+               /*      GP17    Strap "GP7"=High */
+               /*      GP16    Strap "GP6"=High
+                               0=Radio 1=TV
+                               Drives SA630D ENCH1 and HEF4052 A1 pins
+                               to do FM radio through SIF input */
+               /*      GP15    nc */
+               /*      GP14    nc */
+               /*      GP13    nc */
+               /*      GP12    Strap "GP5" = High */
+               /*      GP11    Strap "GP4" = High */
+               /*      GP10    Strap "GP3" = High */
+               /*      GP09    Strap "GP2" = Low */
+               /*      GP08    Strap "GP1" = Low */
+               /*      GP07.00 nc */
index eb20c3afff585b965a0bf3c2f1eace56b909aacb..a8682612abc0d8ce46c1979a48b4b6d78f31b7b0 100644 (file)
 #include "proto.h"
 #include "pci_impl.h"
 
-void default_idle(void)
-{
-       barrier();
-}
-
 void
 cpu_idle(void)
 {
+       set_thread_flag(TIF_POLLING_NRFLAG);
+
        while (1) {
-               void (*idle)(void) = default_idle;
                /* FIXME -- EV6 and LCA45 know how to power down
                   the CPU.  */
 
                while (!need_resched())
-                       idle();
+                       cpu_relax();
                schedule();
        }
 }
index 91d5ef3397be3d56f643dc5fb21eaa4315303499..3bfef0934c9d39162e346e73764f379aad8946f4 100644 (file)
@@ -356,6 +356,16 @@ config HOTPLUG_CPU
          Say Y here to experiment with turning CPUs off and on.  CPUs
          can be controlled through /sys/devices/system/cpu.
 
+config LOCAL_TIMERS
+       bool "Use local timer interrupts"
+       depends on SMP && n
+       default y
+       help
+         Enable support for local timers on SMP platforms, rather then the
+         legacy IPI broadcast method.  Local timers allows the system
+         accounting to be spread across the timer interval, preventing a
+         "thundering herd" at every timer tick.
+
 config PREEMPT
        bool "Preemptible Kernel (EXPERIMENTAL)"
        depends on EXPERIMENTAL
index 50f13eec6cd70cd4c2e0a93233af141027211529..5ab94584baee6a46839e58819a9b443422c2a923 100644 (file)
@@ -283,8 +283,14 @@ void flush_window(void)
        putstr(".");
 }
 
+#ifndef arch_error
+#define arch_error(x)
+#endif
+
 static void error(char *x)
 {
+       arch_error(x);
+
        putstr("\n\n");
        putstr(x);
        putstr("\n\n -- System halted");
index bb4eff61441307458f92a104b0fa655542e118b7..c7fdf390cef9cbf20325431ea092d07c658f7f18 100644 (file)
 
 #define SCOOP_REG(d,adr) (*(volatile unsigned short*)(d +(adr)))
 
-/* PCMCIA to Scoop linkage structures for pxa2xx_sharpsl.c
-   There is no easy way to link multiple scoop devices into one
-   single entity for the pxa2xx_pcmcia device */
-int scoop_num;
-struct scoop_pcmcia_dev *scoop_devs;
-
 struct  scoop_dev {
        void  *base;
        spinlock_t scoop_lock;
index 7b17a87a3311af3ece561f3cbc19debf459e4a8c..7a3261f0bf79012e158e81eab69e7f633d56b4c6 100644 (file)
@@ -9,6 +9,7 @@
  */
 #include <linux/module.h>
 #include <linux/string.h>
+#include <linux/cryptohash.h>
 #include <linux/delay.h>
 #include <linux/in6.h>
 #include <linux/syscalls.h>
@@ -126,6 +127,9 @@ EXPORT_SYMBOL(__put_user_2);
 EXPORT_SYMBOL(__put_user_4);
 EXPORT_SYMBOL(__put_user_8);
 
+       /* crypto hash */
+EXPORT_SYMBOL(sha_transform);
+
        /* gcc lib functions */
 EXPORT_SYMBOL(__ashldi3);
 EXPORT_SYMBOL(__ashrdi3);
index a511ec5b11a33344c945b66811b889c0a91bf084..d9fb819bf7cc3960aedb4b9836451371458a4893 100644 (file)
        movne   r0, sp
        adrne   lr, 1b
        bne     do_IPI
+
+#ifdef CONFIG_LOCAL_TIMERS
+       test_for_ltirq r0, r6, r5, lr
+       movne   r0, sp
+       adrne   lr, 1b
+       bne     do_local_timer
+#endif
 #endif
 
        .endm
index 9def4404e1f27607e46931d4e093725d705d843a..d7099dbbb879ab8cd9ed6c417bdcc87d461dd747 100644 (file)
@@ -264,6 +264,7 @@ unlock:
 #endif
 #ifdef CONFIG_SMP
                show_ipi_list(p);
+               show_local_irqs(p);
 #endif
                seq_printf(p, "Err: %10lu\n", irq_err_count);
        }
@@ -995,7 +996,7 @@ void __init init_irq_proc(void)
        struct proc_dir_entry *dir;
        int irq;
 
-       dir = proc_mkdir("irq", 0);
+       dir = proc_mkdir("irq", NULL);
        if (!dir)
                return;
 
index ba298277becde78687365206e86cdfcbe4936545..c0f6a119de3b903c7bbe44d8d28699473205d3a6 100644 (file)
@@ -86,12 +86,16 @@ EXPORT_SYMBOL(pm_power_off);
  */
 void default_idle(void)
 {
-       local_irq_disable();
-       if (!need_resched() && !hlt_counter) {
-               timer_dyn_reprogram();
-               arch_idle();
+       if (hlt_counter)
+               cpu_relax();
+       else {
+               local_irq_disable();
+               if (!need_resched()) {
+                       timer_dyn_reprogram();
+                       arch_idle();
+               }
+               local_irq_enable();
        }
-       local_irq_enable();
 }
 
 /*
@@ -116,13 +120,13 @@ void cpu_idle(void)
 
                if (!idle)
                        idle = default_idle;
-               preempt_disable();
                leds_event(led_idle_start);
                while (!need_resched())
                        idle();
                leds_event(led_idle_end);
-               preempt_enable();
+               preempt_enable_no_resched();
                schedule();
+               preempt_disable();
        }
 }
 
index edb5a406922f3953b02f3f5ba148d3b438585588..e55ea952f7aa1d9f84ecce020d5caaa548f244fd 100644 (file)
@@ -142,7 +142,7 @@ int __cpuinit __cpu_up(unsigned int cpu)
                        ret = -EIO;
        }
 
-       secondary_data.stack = 0;
+       secondary_data.stack = NULL;
        secondary_data.pgdir = 0;
 
        *pmd_offset(pgd, PHYS_OFFSET) = __pmd(0);
@@ -184,6 +184,11 @@ int __cpuexit __cpu_disable(void)
         */
        migrate_irqs();
 
+       /*
+        * Stop the local timer for this CPU.
+        */
+       local_timer_stop(cpu);
+
        /*
         * Flush user cache and TLB mappings, and then remove this CPU
         * from the vm mask set of all processes.
@@ -251,7 +256,9 @@ void __cpuexit cpu_die(void)
 asmlinkage void __cpuinit secondary_start_kernel(void)
 {
        struct mm_struct *mm = &init_mm;
-       unsigned int cpu = smp_processor_id();
+       unsigned int cpu;
+
+       cpu = smp_processor_id();
 
        printk("CPU%u: Booted secondary processor\n", cpu);
 
@@ -268,6 +275,7 @@ asmlinkage void __cpuinit secondary_start_kernel(void)
        local_flush_tlb_all();
 
        cpu_init();
+       preempt_disable();
 
        /*
         * Give the platform a chance to do its own initialisation.
@@ -289,6 +297,11 @@ asmlinkage void __cpuinit secondary_start_kernel(void)
         */
        cpu_set(cpu, cpu_online_map);
 
+       /*
+        * Setup local timer for this CPU.
+        */
+       local_timer_setup(cpu);
+
        /*
         * OK, it's off to the idle thread for us
         */
@@ -359,8 +372,8 @@ static void send_ipi_message(cpumask_t callmap, enum ipi_msg_type msg)
  * You must not call this function with disabled interrupts, from a
  * hardware interrupt handler, nor from a bottom half handler.
  */
-int smp_call_function_on_cpu(void (*func)(void *info), void *info, int retry,
-                             int wait, cpumask_t callmap)
+static int smp_call_function_on_cpu(void (*func)(void *info), void *info,
+                                   int retry, int wait, cpumask_t callmap)
 {
        struct smp_call_struct data;
        unsigned long timeout;
@@ -454,6 +467,18 @@ void show_ipi_list(struct seq_file *p)
        seq_putc(p, '\n');
 }
 
+void show_local_irqs(struct seq_file *p)
+{
+       unsigned int cpu;
+
+       seq_printf(p, "LOC: ");
+
+       for_each_present_cpu(cpu)
+               seq_printf(p, "%10u ", irq_stat[cpu].local_timer_irqs);
+
+       seq_putc(p, '\n');
+}
+
 static void ipi_timer(struct pt_regs *regs)
 {
        int user = user_mode(regs);
@@ -464,6 +489,18 @@ static void ipi_timer(struct pt_regs *regs)
        irq_exit();
 }
 
+#ifdef CONFIG_LOCAL_TIMERS
+asmlinkage void do_local_timer(struct pt_regs *regs)
+{
+       int cpu = smp_processor_id();
+
+       if (local_timer_ack()) {
+               irq_stat[cpu].local_timer_irqs++;
+               ipi_timer(regs);
+       }
+}
+#endif
+
 /*
  * ipi_call_function - handle IPI from smp_call_function()
  *
@@ -515,7 +552,7 @@ static void ipi_cpu_stop(unsigned int cpu)
  *
  *  Bit 0 - Inter-processor function call
  */
-void do_IPI(struct pt_regs *regs)
+asmlinkage void do_IPI(struct pt_regs *regs)
 {
        unsigned int cpu = smp_processor_id();
        struct ipi_data *ipi = &per_cpu(ipi_data, cpu);
index be283cda63dda9f5817c0e9befce16d7e135974c..399010c140369e31d40c85cca9166d260de8dd76 100644 (file)
@@ -13,7 +13,6 @@
 #include <linux/init.h>
 #include <linux/kernel_stat.h>
 #include <linux/sched.h>
-#include <linux/version.h>
 
 #include <asm/io.h>
 #include <asm/hardware.h>
index eb5f6d744a4a77778d290ba063b18cccd01973d5..100fb31b5156df4a9cb3e6b0372ef2736d23d7e0 100644 (file)
@@ -62,6 +62,37 @@ static struct scoop_config corgi_scoop_setup = {
        .io_out         = CORGI_SCOOP_IO_OUT,
 };
 
+struct platform_device corgiscoop_device = {
+       .name           = "sharp-scoop",
+       .id             = -1,
+       .dev            = {
+               .platform_data  = &corgi_scoop_setup,
+       },
+       .num_resources  = ARRAY_SIZE(corgi_scoop_resources),
+       .resource       = corgi_scoop_resources,
+};
+
+static void corgi_pcmcia_init(void)
+{
+       /* Setup default state of GPIO outputs
+          before we enable them as outputs. */
+       GPSR(GPIO48_nPOE) = GPIO_bit(GPIO48_nPOE) |
+               GPIO_bit(GPIO49_nPWE) | GPIO_bit(GPIO50_nPIOR) |
+               GPIO_bit(GPIO51_nPIOW) | GPIO_bit(GPIO52_nPCE_1) |
+               GPIO_bit(GPIO53_nPCE_2);
+
+       pxa_gpio_mode(GPIO48_nPOE_MD);
+       pxa_gpio_mode(GPIO49_nPWE_MD);
+       pxa_gpio_mode(GPIO50_nPIOR_MD);
+       pxa_gpio_mode(GPIO51_nPIOW_MD);
+       pxa_gpio_mode(GPIO55_nPREG_MD);
+       pxa_gpio_mode(GPIO56_nPWAIT_MD);
+       pxa_gpio_mode(GPIO57_nIOIS16_MD);
+       pxa_gpio_mode(GPIO52_nPCE_1_MD);
+       pxa_gpio_mode(GPIO53_nPCE_2_MD);
+       pxa_gpio_mode(GPIO54_pSKTSEL_MD);
+}
+
 static struct scoop_pcmcia_dev corgi_pcmcia_scoop[] = {
 {
        .dev        = &corgiscoop_device.dev,
@@ -71,16 +102,14 @@ static struct scoop_pcmcia_dev corgi_pcmcia_scoop[] = {
 },
 };
 
-struct platform_device corgiscoop_device = {
-       .name           = "sharp-scoop",
-       .id             = -1,
-       .dev            = {
-               .platform_data  = &corgi_scoop_setup,
-       },
-       .num_resources  = ARRAY_SIZE(corgi_scoop_resources),
-       .resource       = corgi_scoop_resources,
+static struct scoop_pcmcia_config corgi_pcmcia_config = {
+       .devs         = &corgi_pcmcia_scoop[0],
+       .num_devs     = 1,
+       .pcmcia_init  = corgi_pcmcia_init,
 };
 
+EXPORT_SYMBOL(corgiscoop_device);
+
 
 /*
  * Corgi SSP Device
@@ -294,8 +323,7 @@ static void __init corgi_init(void)
        pxa_set_mci_info(&corgi_mci_platform_data);
        pxa_set_ficp_info(&corgi_ficp_platform_data);
 
-       scoop_num = 1;
-       scoop_devs = &corgi_pcmcia_scoop[0];
+       platform_scoop_config = &corgi_pcmcia_config;
 
        platform_add_devices(devices, ARRAY_SIZE(devices));
 }
index ad6a13f95a62cfcae51bc94ffc2fd1f243f17be7..eef3de26ad3704dba4604255abcf13bb3942b16a 100644 (file)
@@ -65,6 +65,27 @@ struct platform_device poodle_scoop_device = {
        .resource       = poodle_scoop_resources,
 };
 
+static void poodle_pcmcia_init(void)
+{
+       /* Setup default state of GPIO outputs
+          before we enable them as outputs. */
+       GPSR(GPIO48_nPOE) = GPIO_bit(GPIO48_nPOE) |
+               GPIO_bit(GPIO49_nPWE) | GPIO_bit(GPIO50_nPIOR) |
+               GPIO_bit(GPIO51_nPIOW) | GPIO_bit(GPIO52_nPCE_1) |
+               GPIO_bit(GPIO53_nPCE_2);
+
+       pxa_gpio_mode(GPIO48_nPOE_MD);
+       pxa_gpio_mode(GPIO49_nPWE_MD);
+       pxa_gpio_mode(GPIO50_nPIOR_MD);
+       pxa_gpio_mode(GPIO51_nPIOW_MD);
+       pxa_gpio_mode(GPIO55_nPREG_MD);
+       pxa_gpio_mode(GPIO56_nPWAIT_MD);
+       pxa_gpio_mode(GPIO57_nIOIS16_MD);
+       pxa_gpio_mode(GPIO52_nPCE_1_MD);
+       pxa_gpio_mode(GPIO53_nPCE_2_MD);
+       pxa_gpio_mode(GPIO54_pSKTSEL_MD);
+}
+
 static struct scoop_pcmcia_dev poodle_pcmcia_scoop[] = {
 {
        .dev        = &poodle_scoop_device.dev,
@@ -74,6 +95,14 @@ static struct scoop_pcmcia_dev poodle_pcmcia_scoop[] = {
 },
 };
 
+static struct scoop_pcmcia_config poodle_pcmcia_config = {
+       .devs         = &poodle_pcmcia_scoop[0],
+       .num_devs     = 1,
+       .pcmcia_init  = poodle_pcmcia_init,
+};
+
+EXPORT_SYMBOL(poodle_scoop_device);
+
 
 /* LoCoMo device */
 static struct resource locomo_resources[] = {
@@ -268,8 +297,7 @@ static void __init poodle_init(void)
        pxa_set_mci_info(&poodle_mci_platform_data);
        pxa_set_ficp_info(&poodle_ficp_platform_data);
 
-       scoop_num = 1;
-       scoop_devs = &poodle_pcmcia_scoop[0];
+       platform_scoop_config = &poodle_pcmcia_config;
 
        ret = platform_add_devices(devices, ARRAY_SIZE(devices));
        if (ret) {
index 6c6878cd2207db94f3b70343beef634fbb6491f2..4e9a699ee4280e61560a5672e9bd6c276c36a284 100644 (file)
@@ -104,6 +104,66 @@ struct platform_device spitzscoop2_device = {
        .resource       = spitz_scoop2_resources,
 };
 
+#define SPITZ_PWR_SD 0x01
+#define SPITZ_PWR_CF 0x02
+
+/* Power control is shared with between one of the CF slots and SD */
+static void spitz_card_pwr_ctrl(int device, unsigned short new_cpr)
+{
+       unsigned short cpr = read_scoop_reg(&spitzscoop_device.dev, SCOOP_CPR);
+
+       if (new_cpr & 0x0007) {
+               set_scoop_gpio(&spitzscoop_device.dev, SPITZ_SCP_CF_POWER);
+               if (!(cpr & 0x0002) && !(cpr & 0x0004))
+                       mdelay(5);
+               if (device == SPITZ_PWR_CF)
+                       cpr |= 0x0002;
+               if (device == SPITZ_PWR_SD)
+                       cpr |= 0x0004;
+               write_scoop_reg(&spitzscoop_device.dev, SCOOP_CPR, cpr | new_cpr);
+       } else {
+               if (device == SPITZ_PWR_CF)
+                       cpr &= ~0x0002;
+               if (device == SPITZ_PWR_SD)
+                       cpr &= ~0x0004;
+               write_scoop_reg(&spitzscoop_device.dev, SCOOP_CPR, cpr | new_cpr);
+               if (!(cpr & 0x0002) && !(cpr & 0x0004)) {
+                       mdelay(1);
+                       reset_scoop_gpio(&spitzscoop_device.dev, SPITZ_SCP_CF_POWER);
+               }
+       }
+}
+
+static void spitz_pcmcia_init(void)
+{
+       /* Setup default state of GPIO outputs
+          before we enable them as outputs. */
+       GPSR(GPIO48_nPOE) = GPIO_bit(GPIO48_nPOE) |
+               GPIO_bit(GPIO49_nPWE) | GPIO_bit(GPIO50_nPIOR) |
+               GPIO_bit(GPIO51_nPIOW) | GPIO_bit(GPIO54_nPCE_2);
+       GPSR(GPIO85_nPCE_1) = GPIO_bit(GPIO85_nPCE_1);
+
+       pxa_gpio_mode(GPIO48_nPOE_MD);
+       pxa_gpio_mode(GPIO49_nPWE_MD);
+       pxa_gpio_mode(GPIO50_nPIOR_MD);
+       pxa_gpio_mode(GPIO51_nPIOW_MD);
+       pxa_gpio_mode(GPIO55_nPREG_MD);
+       pxa_gpio_mode(GPIO56_nPWAIT_MD);
+       pxa_gpio_mode(GPIO57_nIOIS16_MD);
+       pxa_gpio_mode(GPIO85_nPCE_1_MD);
+       pxa_gpio_mode(GPIO54_nPCE_2_MD);
+       pxa_gpio_mode(GPIO104_pSKTSEL_MD);
+}
+
+static void spitz_pcmcia_pwr(struct device *scoop, unsigned short cpr, int nr)
+{
+       /* Only need to override behaviour for slot 0 */
+       if (nr == 0)
+               spitz_card_pwr_ctrl(SPITZ_PWR_CF, cpr);
+       else
+               write_scoop_reg(scoop, SCOOP_CPR, cpr);
+}
+
 static struct scoop_pcmcia_dev spitz_pcmcia_scoop[] = {
 {
        .dev        = &spitzscoop_device.dev,
@@ -117,6 +177,16 @@ static struct scoop_pcmcia_dev spitz_pcmcia_scoop[] = {
 },
 };
 
+static struct scoop_pcmcia_config spitz_pcmcia_config = {
+       .devs         = &spitz_pcmcia_scoop[0],
+       .num_devs     = 2,
+       .pcmcia_init  = spitz_pcmcia_init,
+       .power_ctrl   = spitz_pcmcia_pwr,
+};
+
+EXPORT_SYMBOL(spitzscoop_device);
+EXPORT_SYMBOL(spitzscoop2_device);
+
 
 /*
  * Spitz SSP Device
@@ -235,27 +305,14 @@ static int spitz_mci_init(struct device *dev, irqreturn_t (*spitz_detect_int)(in
        return 0;
 }
 
-/* Power control is shared with one of the CF slots so we have a mess */
 static void spitz_mci_setpower(struct device *dev, unsigned int vdd)
 {
        struct pxamci_platform_data* p_d = dev->platform_data;
 
-       unsigned short cpr = read_scoop_reg(&spitzscoop_device.dev, SCOOP_CPR);
-
-       if (( 1 << vdd) & p_d->ocr_mask) {
-               /* printk(KERN_DEBUG "%s: on\n", __FUNCTION__); */
-               set_scoop_gpio(&spitzscoop_device.dev, SPITZ_SCP_CF_POWER);
-               mdelay(2);
-               write_scoop_reg(&spitzscoop_device.dev, SCOOP_CPR, cpr | 0x04);
-       } else {
-               /* printk(KERN_DEBUG "%s: off\n", __FUNCTION__); */
-               write_scoop_reg(&spitzscoop_device.dev, SCOOP_CPR, cpr & ~0x04);
-
-               if (!(cpr | 0x02)) {
-                       mdelay(1);
-                       reset_scoop_gpio(&spitzscoop_device.dev, SPITZ_SCP_CF_POWER);
-               }
-       }
+       if (( 1 << vdd) & p_d->ocr_mask)
+               spitz_card_pwr_ctrl(SPITZ_PWR_SD, 0x0004);
+       else
+               spitz_card_pwr_ctrl(SPITZ_PWR_SD, 0x0000);
 }
 
 static int spitz_mci_get_ro(struct device *dev)
@@ -351,8 +408,8 @@ static void __init common_init(void)
 
 static void __init spitz_init(void)
 {
-       scoop_num = 2;
-       scoop_devs = &spitz_pcmcia_scoop[0];
+       platform_scoop_config = &spitz_pcmcia_config;
+
        spitz_bl_machinfo.set_bl_intensity = spitz_bl_set_intensity;
 
        common_init();
index 7dad3f1465e076028954b1f18169ed8b82b2502e..b9b2057349ebe9a1738fd327ab668bd11decb4e7 100644 (file)
@@ -132,11 +132,13 @@ static void __init pxa_timer_init(void)
        tv.tv_sec = pxa_get_rtc_time();
        do_settimeofday(&tv);
 
-       OSMR0 = 0;              /* set initial match at 0 */
+       OIER = 0;               /* disable any timer interrupts */
+       OSCR = LATCH*2;         /* push OSCR out of the way */
+       OSMR0 = LATCH;          /* set initial match */
        OSSR = 0xf;             /* clear status on all timers */
        setup_irq(IRQ_OST0, &pxa_timer_irq);
-       OIER |= OIER_E0;        /* enable match on timer 0 to cause interrupts */
-       OSCR = 0;               /* initialize free-running timer, force first match */
+       OIER = OIER_E0;         /* enable match on timer 0 to cause interrupts */
+       OSCR = 0;               /* initialize free-running timer */
 }
 
 #ifdef CONFIG_NO_IDLE_HZ
index 400609f8b6a85e3703e5b64933bbfd0373d47a00..c312054dfb8872b3e2af9a1065fdd227488af969 100644 (file)
@@ -98,6 +98,9 @@ struct platform_device tosascoop_jc_device = {
        .resource       = tosa_scoop_jc_resources,
 };
 
+/*
+ * PCMCIA
+ */
 static struct scoop_pcmcia_dev tosa_pcmcia_scoop[] = {
 {
        .dev        = &tosascoop_device.dev,
@@ -111,16 +114,155 @@ static struct scoop_pcmcia_dev tosa_pcmcia_scoop[] = {
 },
 };
 
+static void tosa_pcmcia_init(void)
+{
+       /* Setup default state of GPIO outputs
+          before we enable them as outputs. */
+       GPSR(GPIO48_nPOE) = GPIO_bit(GPIO48_nPOE) |
+               GPIO_bit(GPIO49_nPWE) | GPIO_bit(GPIO50_nPIOR) |
+               GPIO_bit(GPIO51_nPIOW) | GPIO_bit(GPIO52_nPCE_1) |
+               GPIO_bit(GPIO53_nPCE_2);
+
+       pxa_gpio_mode(GPIO48_nPOE_MD);
+       pxa_gpio_mode(GPIO49_nPWE_MD);
+       pxa_gpio_mode(GPIO50_nPIOR_MD);
+       pxa_gpio_mode(GPIO51_nPIOW_MD);
+       pxa_gpio_mode(GPIO55_nPREG_MD);
+       pxa_gpio_mode(GPIO56_nPWAIT_MD);
+       pxa_gpio_mode(GPIO57_nIOIS16_MD);
+       pxa_gpio_mode(GPIO52_nPCE_1_MD);
+       pxa_gpio_mode(GPIO53_nPCE_2_MD);
+       pxa_gpio_mode(GPIO54_pSKTSEL_MD);
+}
+
+static struct scoop_pcmcia_config tosa_pcmcia_config = {
+       .devs         = &tosa_pcmcia_scoop[0],
+       .num_devs     = 2,
+       .pcmcia_init  = tosa_pcmcia_init,
+};
+
+/*
+ * USB Device Controller
+ */
+static void tosa_udc_command(int cmd)
+{
+       switch(cmd)     {
+               case PXA2XX_UDC_CMD_CONNECT:
+                       set_scoop_gpio(&tosascoop_jc_device.dev,TOSA_SCOOP_JC_USB_PULLUP);
+                       break;
+               case PXA2XX_UDC_CMD_DISCONNECT:
+                       reset_scoop_gpio(&tosascoop_jc_device.dev,TOSA_SCOOP_JC_USB_PULLUP);
+                       break;
+       }
+}
+
+static int tosa_udc_is_connected(void)
+{
+       return ((GPLR(TOSA_GPIO_USB_IN) & GPIO_bit(TOSA_GPIO_USB_IN)) == 0);
+}
+
+
+static struct pxa2xx_udc_mach_info udc_info __initdata = {
+       .udc_command            = tosa_udc_command,
+       .udc_is_connected       = tosa_udc_is_connected,
+};
+
+/*
+ * MMC/SD Device
+ */
+static struct pxamci_platform_data tosa_mci_platform_data;
+
+static int tosa_mci_init(struct device *dev, irqreturn_t (*tosa_detect_int)(int, void *, struct pt_regs *), void *data)
+{
+       int err;
+
+       /* setup GPIO for PXA25x MMC controller */
+       pxa_gpio_mode(GPIO6_MMCCLK_MD);
+       pxa_gpio_mode(GPIO8_MMCCS0_MD);
+       pxa_gpio_mode(TOSA_GPIO_nSD_DETECT | GPIO_IN);
+
+       tosa_mci_platform_data.detect_delay = msecs_to_jiffies(250);
+
+       err = request_irq(TOSA_IRQ_GPIO_nSD_DETECT, tosa_detect_int, SA_INTERRUPT,
+                               "MMC/SD card detect", data);
+       if (err) {
+               printk(KERN_ERR "tosa_mci_init: MMC/SD: can't request MMC card detect IRQ\n");
+               return -1;
+       }
+
+       set_irq_type(TOSA_IRQ_GPIO_nSD_DETECT, IRQT_BOTHEDGE);
+
+       return 0;
+}
+
+static void tosa_mci_setpower(struct device *dev, unsigned int vdd)
+{
+       struct pxamci_platform_data* p_d = dev->platform_data;
+
+       if (( 1 << vdd) & p_d->ocr_mask) {
+               set_scoop_gpio(&tosascoop_device.dev,TOSA_SCOOP_PWR_ON);
+       } else {
+               reset_scoop_gpio(&tosascoop_device.dev,TOSA_SCOOP_PWR_ON);
+       }
+}
+
+static int tosa_mci_get_ro(struct device *dev)
+{
+       return (read_scoop_reg(&tosascoop_device.dev, SCOOP_GPWR)&TOSA_SCOOP_SD_WP);
+}
+
+static void tosa_mci_exit(struct device *dev, void *data)
+{
+       free_irq(TOSA_IRQ_GPIO_nSD_DETECT, data);
+}
+
+static struct pxamci_platform_data tosa_mci_platform_data = {
+       .ocr_mask       = MMC_VDD_32_33|MMC_VDD_33_34,
+       .init           = tosa_mci_init,
+       .get_ro         = tosa_mci_get_ro,
+       .setpower       = tosa_mci_setpower,
+       .exit           = tosa_mci_exit,
+};
+
+/*
+ * Irda
+ */
+static void tosa_irda_transceiver_mode(struct device *dev, int mode)
+{
+       if (mode & IR_OFF) {
+               reset_scoop_gpio(&tosascoop_device.dev,TOSA_SCOOP_IR_POWERDWN);
+               pxa_gpio_mode(GPIO47_STTXD|GPIO_DFLT_LOW);
+               pxa_gpio_mode(GPIO47_STTXD|GPIO_OUT);
+       } else {
+               pxa_gpio_mode(GPIO47_STTXD_MD);
+               set_scoop_gpio(&tosascoop_device.dev,TOSA_SCOOP_IR_POWERDWN);
+       }
+}
+
+static struct pxaficp_platform_data tosa_ficp_platform_data = {
+       .transceiver_cap  = IR_SIRMODE | IR_OFF,
+       .transceiver_mode = tosa_irda_transceiver_mode,
+};
+
+/*
+ * Tosa Keyboard
+ */
+static struct platform_device tosakbd_device = {
+       .name           = "tosa-keyboard",
+       .id             = -1,
+};
 
 static struct platform_device *devices[] __initdata = {
        &tosascoop_device,
        &tosascoop_jc_device,
+       &tosakbd_device,
 };
 
 static void __init tosa_init(void)
 {
        pxa_gpio_mode(TOSA_GPIO_ON_RESET | GPIO_IN);
        pxa_gpio_mode(TOSA_GPIO_TC6393_INT | GPIO_IN);
+       pxa_gpio_mode(TOSA_GPIO_USB_IN | GPIO_IN);
 
        /* setup sleep mode values */
        PWER  = 0x00000002;
@@ -131,13 +273,15 @@ static void __init tosa_init(void)
        PGSR2 = 0x00014000;
        PCFR |= PCFR_OPDE;
 
-       // enable batt_fault
+       /* enable batt_fault */
        PMCR = 0x01;
 
-       platform_add_devices(devices, ARRAY_SIZE(devices));
+       pxa_set_mci_info(&tosa_mci_platform_data);
+       pxa_set_udc_info(&udc_info);
+       pxa_set_ficp_info(&tosa_ficp_platform_data);
+       platform_scoop_config = &tosa_pcmcia_config;
 
-       scoop_num = 2;
-       scoop_devs = &tosa_pcmcia_scoop[0];
+       platform_add_devices(devices, ARRAY_SIZE(devices));
 }
 
 static void __init fixup_tosa(struct machine_desc *desc,
index 482eb512ebe8a79d0b38d1989b39e68d77ac4add..4ea60d8b6e36838bdd5deb72955732297edf6cf9 100644 (file)
@@ -550,6 +550,11 @@ static irqreturn_t realview_timer_interrupt(int irq, void *dev_id, struct pt_reg
 
        timer_tick(regs);
 
+#ifdef CONFIG_SMP
+       smp_send_timer();
+       update_process_times(user_mode(regs));
+#endif
+
        write_sequnlock(&xtime_lock);
 
        return IRQ_HANDLED;
index 9844644d0fb5c69400c76588ca4d24ed19d550f8..09b35f62247a8863c268ec0ae4c1b3d3259c1d1d 100644 (file)
@@ -32,7 +32,7 @@ static unsigned int __init get_core_count(void)
 {
        unsigned int ncores;
 
-       ncores = __raw_readl(IO_ADDRESS(REALVIEW_MPCORE_SCU_BASE) + SCU_CONFIG);
+       ncores = __raw_readl(__io_address(REALVIEW_MPCORE_SCU_BASE) + SCU_CONFIG);
 
        return (ncores & 0x03) + 1;
 }
@@ -133,12 +133,12 @@ static void __init poke_milo(void)
 #if 1
 #define REALVIEW_SYS_FLAGSS_OFFSET 0x30
        __raw_writel(virt_to_phys(realview_secondary_startup),
-                    (IO_ADDRESS(REALVIEW_SYS_BASE) +
-                     REALVIEW_SYS_FLAGSS_OFFSET));
+                    __io_address(REALVIEW_SYS_BASE) +
+                    REALVIEW_SYS_FLAGSS_OFFSET);
 #define REALVIEW_SYS_FLAGSC_OFFSET 0x34
        __raw_writel(3,
-                    (IO_ADDRESS(REALVIEW_SYS_BASE) +
-                     REALVIEW_SYS_FLAGSC_OFFSET));
+                    __io_address(REALVIEW_SYS_BASE) +
+                    REALVIEW_SYS_FLAGSC_OFFSET);
 #endif
 
        mb();
index c796bcdd6158208c77cc1f97b7bfbb8a12ca6573..0b9d7ca49ec1ff9f9520cc02c845c0c8990c30b1 100644 (file)
@@ -121,6 +121,14 @@ config S3C2410_BOOT_WATCHDOG
          system resets depends on the value of PCLK. The timeout on an
          200MHz s3c2410 should be about 30 seconds.
 
+config S3C2410_BOOT_ERROR_RESET
+       bool "S3C2410 Reboot on decompression error"
+       depends on ARCH_S3C2410
+       help
+         Say y here to use the watchdog to reset the system if the
+         kernel decompressor detects an error during decompression.
+
+
 comment "S3C2410 Setup"
 
 config S3C2410_DMA
index 0b71c896bbd1ac5fe5ebb9ae55487cf01992e9d4..1be2567a7486606039f1f36902d97fad891b0aaf 100644 (file)
 
 /* macros to modify the physical addresses for io space */
 
-#define PA_CS2(item) ((item) + S3C2410_CS2)
-#define PA_CS3(item) ((item) + S3C2410_CS3)
-#define PA_CS4(item) ((item) + S3C2410_CS4)
-#define PA_CS5(item) ((item) + S3C2410_CS5)
+#define PA_CS2(item) (__phys_to_pfn((item) + S3C2410_CS2))
+#define PA_CS3(item) (__phys_to_pfn((item) + S3C2410_CS3))
+#define PA_CS4(item) (__phys_to_pfn((item) + S3C2410_CS4))
+#define PA_CS5(item) (__phys_to_pfn((item) + S3C2410_CS5))
 
 static struct map_desc bast_iodesc[] __initdata = {
   /* ISA IO areas */
-
-  { (u32)S3C24XX_VA_ISA_BYTE, PA_CS2(BAST_PA_ISAIO),   SZ_16M, MT_DEVICE },
-  { (u32)S3C24XX_VA_ISA_WORD, PA_CS3(BAST_PA_ISAIO),   SZ_16M, MT_DEVICE },
-
-  /* we could possibly compress the next set down into a set of smaller tables
-   * pagetables, but that would mean using an L2 section, and it still means
-   * we cannot actually feed the same register to an LDR due to 16K spacing
-   */
-
+  {
+         .virtual      = (u32)S3C24XX_VA_ISA_BYTE,
+         .pfn          = PA_CS2(BAST_PA_ISAIO),
+         .length       = SZ_16M,
+         .type         = MT_DEVICE,
+  }, {
+         .virtual      = (u32)S3C24XX_VA_ISA_WORD,
+         .pfn          = PA_CS3(BAST_PA_ISAIO),
+         .length       = SZ_16M,
+         .type         = MT_DEVICE,
+  },
   /* bast CPLD control registers, and external interrupt controls */
-  { (u32)BAST_VA_CTRL1, BAST_PA_CTRL1,            SZ_1M, MT_DEVICE },
-  { (u32)BAST_VA_CTRL2, BAST_PA_CTRL2,            SZ_1M, MT_DEVICE },
-  { (u32)BAST_VA_CTRL3, BAST_PA_CTRL3,            SZ_1M, MT_DEVICE },
-  { (u32)BAST_VA_CTRL4, BAST_PA_CTRL4,            SZ_1M, MT_DEVICE },
-
+  {
+         .virtual      = (u32)BAST_VA_CTRL1,
+         .pfn          = __phys_to_pfn(BAST_PA_CTRL1),
+         .length       = SZ_1M,
+         .type         = MT_DEVICE,
+  }, {
+         .virtual      = (u32)BAST_VA_CTRL2,
+         .pfn          = __phys_to_pfn(BAST_PA_CTRL2),
+         .length       = SZ_1M,
+         .type         = MT_DEVICE,
+  }, {
+         .virtual      = (u32)BAST_VA_CTRL3,
+         .pfn          = __phys_to_pfn(BAST_PA_CTRL3),
+         .length       = SZ_1M,
+         .type         = MT_DEVICE,
+  }, {
+         .virtual      = (u32)BAST_VA_CTRL4,
+         .pfn          = __phys_to_pfn(BAST_PA_CTRL4),
+         .length       = SZ_1M,
+         .type         = MT_DEVICE,
+  },
   /* PC104 IRQ mux */
-  { (u32)BAST_VA_PC104_IRQREQ,  BAST_PA_PC104_IRQREQ,   SZ_1M, MT_DEVICE },
-  { (u32)BAST_VA_PC104_IRQRAW,  BAST_PA_PC104_IRQRAW,   SZ_1M, MT_DEVICE },
-  { (u32)BAST_VA_PC104_IRQMASK, BAST_PA_PC104_IRQMASK,  SZ_1M, MT_DEVICE },
+  {
+         .virtual      = (u32)BAST_VA_PC104_IRQREQ,
+         .pfn          = __phys_to_pfn(BAST_PA_PC104_IRQREQ),
+         .length       = SZ_1M,
+         .type         = MT_DEVICE,
+  }, {
+         .virtual      = (u32)BAST_VA_PC104_IRQRAW,
+         .pfn          = __phys_to_pfn(BAST_PA_PC104_IRQRAW),
+         .length       = SZ_1M,
+         .type         = MT_DEVICE,
+  }, {
+         .virtual      = (u32)BAST_VA_PC104_IRQMASK,
+         .pfn          = __phys_to_pfn(BAST_PA_PC104_IRQMASK),
+         .length       = SZ_1M,
+         .type         = MT_DEVICE,
+  },
 
   /* peripheral space... one for each of fast/slow/byte/16bit */
   /* note, ide is only decoded in word space, even though some registers
index 46b259673c18156606f6ffb190ce69790d4b5274..ae7e099bf6c80521eaf32cd9279881642dbea94d 100644 (file)
 
 /* macros to modify the physical addresses for io space */
 
-#define PA_CS2(item) ((item) + S3C2410_CS2)
-#define PA_CS3(item) ((item) + S3C2410_CS3)
-#define PA_CS4(item) ((item) + S3C2410_CS4)
-#define PA_CS5(item) ((item) + S3C2410_CS5)
+#define PA_CS2(item) (__phys_to_pfn((item) + S3C2410_CS2))
+#define PA_CS3(item) (__phys_to_pfn((item) + S3C2410_CS3))
+#define PA_CS4(item) (__phys_to_pfn((item) + S3C2410_CS4))
+#define PA_CS5(item) (__phys_to_pfn((item) + S3C2410_CS5))
 
 static struct map_desc vr1000_iodesc[] __initdata = {
   /* ISA IO areas */
-
-  { (u32)S3C24XX_VA_ISA_BYTE, PA_CS2(BAST_PA_ISAIO),      SZ_16M, MT_DEVICE },
-  { (u32)S3C24XX_VA_ISA_WORD, PA_CS3(BAST_PA_ISAIO),      SZ_16M, MT_DEVICE },
-
-  /* we could possibly compress the next set down into a set of smaller tables
-   * pagetables, but that would mean using an L2 section, and it still means
-   * we cannot actually feed the same register to an LDR due to 16K spacing
-   */
-
-  /* bast CPLD control registers, and external interrupt controls */
-  { (u32)VR1000_VA_CTRL1, VR1000_PA_CTRL1,            SZ_1M, MT_DEVICE },
-  { (u32)VR1000_VA_CTRL2, VR1000_PA_CTRL2,            SZ_1M, MT_DEVICE },
-  { (u32)VR1000_VA_CTRL3, VR1000_PA_CTRL3,            SZ_1M, MT_DEVICE },
-  { (u32)VR1000_VA_CTRL4, VR1000_PA_CTRL4,            SZ_1M, MT_DEVICE },
+  {
+         .virtual      = (u32)S3C24XX_VA_ISA_BYTE,
+         .pfn          = PA_CS2(BAST_PA_ISAIO),
+         .length       = SZ_16M,
+         .type         = MT_DEVICE,
+  }, {
+         .virtual      = (u32)S3C24XX_VA_ISA_WORD,
+         .pfn          = PA_CS3(BAST_PA_ISAIO),
+         .length       = SZ_16M,
+         .type         = MT_DEVICE,
+  },
+
+  /*  CPLD control registers, and external interrupt controls */
+  {
+         .virtual      = (u32)VR1000_VA_CTRL1,
+         .pfn          = __phys_to_pfn(VR1000_PA_CTRL1),
+         .length       = SZ_1M,
+         .type         = MT_DEVICE,
+  }, {
+         .virtual      = (u32)VR1000_VA_CTRL2,
+         .pfn          = __phys_to_pfn(VR1000_PA_CTRL2),
+         .length       = SZ_1M,
+         .type         = MT_DEVICE,
+  }, {
+         .virtual      = (u32)VR1000_VA_CTRL3,
+         .pfn          = __phys_to_pfn(VR1000_PA_CTRL3),
+         .length       = SZ_1M,
+         .type         = MT_DEVICE,
+  }, {
+         .virtual      = (u32)VR1000_VA_CTRL4,
+         .pfn          = __phys_to_pfn(VR1000_PA_CTRL4),
+         .length       = SZ_1M,
+         .type         = MT_DEVICE,
+  },
 
   /* peripheral space... one for each of fast/slow/byte/16bit */
   /* note, ide is only decoded in word space, even though some registers
index 47e0420623fc25083a486f74887bff522260108b..e4b435e634e41a657321360a5c6d22173ad98fc6 100644 (file)
@@ -124,11 +124,13 @@ static void __init sa1100_timer_init(void)
        tv.tv_sec = sa1100_get_rtc_time();
        do_settimeofday(&tv);
 
-       OSMR0 = 0;              /* set initial match at 0 */
+       OIER = 0;               /* disable any timer interrupts */
+       OSCR = LATCH*2;         /* push OSCR out of the way */
+       OSMR0 = LATCH;          /* set initial match */
        OSSR = 0xf;             /* clear status on all timers */
        setup_irq(IRQ_OST0, &sa1100_timer_irq);
-       OIER |= OIER_E0;        /* enable match on timer 0 to cause interrupts */
-       OSCR = 0;               /* initialize free-running timer, force first match */
+       OIER = OIER_E0;         /* enable match on timer 0 to cause interrupts */
+       OSCR = 0;               /* initialize free-running timer */
 }
 
 #ifdef CONFIG_NO_IDLE_HZ
index 1fb16f9edfd58ba552ddb0bee7f6487e0fb6d5fd..2ede2ee8cae420ecf4b5a24593e572058c942929 100644 (file)
@@ -25,7 +25,6 @@
 
 #include <linux/config.h>
 #include <linux/module.h>
-#include <linux/version.h>
 #include <linux/types.h>
 #include <linux/errno.h>
 #include <linux/kernel.h>
index 9eb9964d32a7368c0b71c53015c75a7e58626f48..15833a0057dd1c9ad7360275cd81b4e1716d053b 100644 (file)
@@ -74,15 +74,13 @@ __setup("hlt", hlt_setup);
 void cpu_idle(void)
 {
        /* endless idle loop with no priority at all */
-       preempt_disable();
        while (1) {
-               while (!need_resched()) {
-                       local_irq_disable();
-                       if (!need_resched() && !hlt_counter)
-                               local_irq_enable();
-               }
+               while (!need_resched())
+                       cpu_relax();
+               preempt_enable_no_resched();
+               schedule();
+               preempt_disable();
        }
-       schedule();
 }
 
 static char reboot_mode = 'h';
index 201f4c90d96153fe1720a06114da50c8d7d46a85..f2c55742e90c2ce1c8ccadd9f22b14e57b365d3c 100644 (file)
@@ -19,7 +19,6 @@
  */
 
 #include <linux/config.h>
-#include <linux/version.h>
 #include <linux/module.h>
 #include <linux/kernel.h>
 #include <linux/types.h>
index 094ff45ae85b58552ea1747f3828c0357df6268f..cac05a5e514cf19817d3a28b49b6ca3d0c92c07d 100644 (file)
 #include <asm/rtc.h>
 
 #include <linux/config.h>
-#include <linux/version.h>
 
 #include <asm/arch/svinto.h>
 #include <asm/fasttimer.h>
index fc2a619b035d1802eb265ee71f4e76c67d3a0e83..93ddea4d956490640a95da0ca2676ac1e2678958 100644 (file)
@@ -14,7 +14,6 @@
  *
  */
 
-#include <linux/version.h>
 #include <linux/slab.h>
 #include <linux/init.h>
 #include <linux/module.h>
index f894580b648bbc79165d42e1aa0370d43db885ab..d788bda3578cd609e8325d9cb5dd035fcf9c5f2e 100644 (file)
@@ -18,7 +18,6 @@
  */
 
 #include <linux/config.h>
-#include <linux/version.h>
 #include <linux/module.h>
 #include <linux/kernel.h>
 #include <linux/types.h>
index 957f551ba5ce21602467506a4c7f6f5276a1523e..13867f4fad16a858a13d4305a3869998ef516b78 100644 (file)
@@ -161,6 +161,7 @@ void __init smp_callin(void)
        REG_WR(intr_vect, irq_regs[cpu], rw_mask, vect_mask);
        unmask_irq(IPI_INTR_VECT);
        unmask_irq(TIMER_INTR_VECT);
+       preempt_disable();
        local_irq_enable();
 
        cpu_set(cpu, cpu_online_map);
index 949a0e40e03cc63f6304c90e9909a254bbe909ce..7c80afb1046077d2fb219d2542c3b815c7d3916d 100644 (file)
@@ -218,7 +218,9 @@ void cpu_idle (void)
                                idle = default_idle;
                        idle();
                }
+               preempt_enable_no_resched();
                schedule();
+               preempt_disable();
        }
 }
 
index 3001b82b1514856efed7204f6b09e0345a8cb974..54a452136f00e8f93cabd0bcdf8e5a450d662b26 100644 (file)
@@ -77,16 +77,20 @@ void (*idle)(void) = core_sleep_idle;
  */
 void cpu_idle(void)
 {
+       int cpu = smp_processor_id();
+
        /* endless idle loop with no priority at all */
        while (1) {
                while (!need_resched()) {
-                       irq_stat[smp_processor_id()].idle_timestamp = jiffies;
+                       irq_stat[cpu].idle_timestamp = jiffies;
 
                        if (!frv_dma_inprogress && idle)
                                idle();
                }
 
+               preempt_enable_no_resched();
                schedule();
+               preempt_disable();
        }
 }
 
index 27f1fce64ce465026ee90c0cffd2e25717843075..fe21adf3e75e8c26e2619e71bbc5167edabc84a7 100644 (file)
@@ -53,22 +53,18 @@ asmlinkage void ret_from_fork(void);
 #if !defined(CONFIG_H8300H_SIM) && !defined(CONFIG_H8S_SIM)
 void default_idle(void)
 {
-       while(1) {
-               if (!need_resched()) {
-                       local_irq_enable();
-                       __asm__("sleep");
-                       local_irq_disable();
-               }
-               schedule();
-       }
+       local_irq_disable();
+       if (!need_resched()) {
+               local_irq_enable();
+               /* XXX: race here! What if need_resched() gets set now? */
+               __asm__("sleep");
+       } else
+               local_irq_enable();
 }
 #else
 void default_idle(void)
 {
-       while(1) {
-               if (need_resched())
-                       schedule();
-       }
+       cpu_relax();
 }
 #endif
 void (*idle)(void) = default_idle;
@@ -81,7 +77,13 @@ void (*idle)(void) = default_idle;
  */
 void cpu_idle(void)
 {
-       idle();
+       while (1) {
+               while (!need_resched())
+                       idle();
+               preempt_enable_no_resched();
+               schedule();
+               preempt_disable();
+       }
 }
 
 void machine_restart(char * __unused)
index 86e80c551478894c468b4225f72d00a4c772bcfc..003548b8735f961b24794da2306bff45944ee63e 100644 (file)
@@ -769,8 +769,26 @@ static int set_system_power_state(u_short state)
 static int apm_do_idle(void)
 {
        u32     eax;
+       u8      ret = 0;
+       int     idled = 0;
+       int     polling;
+
+       polling = test_thread_flag(TIF_POLLING_NRFLAG);
+       if (polling) {
+               clear_thread_flag(TIF_POLLING_NRFLAG);
+               smp_mb__after_clear_bit();
+       }
+       if (!need_resched()) {
+               idled = 1;
+               ret = apm_bios_call_simple(APM_FUNC_IDLE, 0, 0, &eax);
+       }
+       if (polling)
+               set_thread_flag(TIF_POLLING_NRFLAG);
+
+       if (!idled)
+               return 0;
 
-       if (apm_bios_call_simple(APM_FUNC_IDLE, 0, 0, &eax)) {
+       if (ret) {
                static unsigned long t;
 
                /* This always fails on some SMP boards running UP kernels.
index 7a14fdfd3af95423275cab21ea56624bd4e1f4e7..1cb261f225d580939785c0b9fc94859dcf92a8a0 100644 (file)
@@ -99,14 +99,22 @@ EXPORT_SYMBOL(enable_hlt);
  */
 void default_idle(void)
 {
+       local_irq_enable();
+
        if (!hlt_counter && boot_cpu_data.hlt_works_ok) {
-               local_irq_disable();
-               if (!need_resched())
-                       safe_halt();
-               else
-                       local_irq_enable();
+               clear_thread_flag(TIF_POLLING_NRFLAG);
+               smp_mb__after_clear_bit();
+               while (!need_resched()) {
+                       local_irq_disable();
+                       if (!need_resched())
+                               safe_halt();
+                       else
+                               local_irq_enable();
+               }
+               set_thread_flag(TIF_POLLING_NRFLAG);
        } else {
-               cpu_relax();
+               while (!need_resched())
+                       cpu_relax();
        }
 }
 #ifdef CONFIG_APM_MODULE
@@ -120,29 +128,14 @@ EXPORT_SYMBOL(default_idle);
  */
 static void poll_idle (void)
 {
-       int oldval;
-
        local_irq_enable();
 
-       /*
-        * Deal with another CPU just having chosen a thread to
-        * run here:
-        */
-       oldval = test_and_clear_thread_flag(TIF_NEED_RESCHED);
-
-       if (!oldval) {
-               set_thread_flag(TIF_POLLING_NRFLAG);
-               asm volatile(
-                       "2:"
-                       "testl %0, %1;"
-                       "rep; nop;"
-                       "je 2b;"
-                       : : "i"(_TIF_NEED_RESCHED), "m" (current_thread_info()->flags));
-
-               clear_thread_flag(TIF_POLLING_NRFLAG);
-       } else {
-               set_need_resched();
-       }
+       asm volatile(
+               "2:"
+               "testl %0, %1;"
+               "rep; nop;"
+               "je 2b;"
+               : : "i"(_TIF_NEED_RESCHED), "m" (current_thread_info()->flags));
 }
 
 #ifdef CONFIG_HOTPLUG_CPU
@@ -179,7 +172,9 @@ static inline void play_dead(void)
  */
 void cpu_idle(void)
 {
-       int cpu = raw_smp_processor_id();
+       int cpu = smp_processor_id();
+
+       set_thread_flag(TIF_POLLING_NRFLAG);
 
        /* endless idle loop with no priority at all */
        while (1) {
@@ -201,7 +196,9 @@ void cpu_idle(void)
                        __get_cpu_var(irq_stat).idle_timestamp = jiffies;
                        idle();
                }
+               preempt_enable_no_resched();
                schedule();
+               preempt_disable();
        }
 }
 
@@ -244,15 +241,12 @@ static void mwait_idle(void)
 {
        local_irq_enable();
 
-       if (!need_resched()) {
-               set_thread_flag(TIF_POLLING_NRFLAG);
-               do {
-                       __monitor((void *)&current_thread_info()->flags, 0, 0);
-                       if (need_resched())
-                               break;
-                       __mwait(0, 0);
-               } while (!need_resched());
-               clear_thread_flag(TIF_POLLING_NRFLAG);
+       while (!need_resched()) {
+               __monitor((void *)&current_thread_info()->flags, 0, 0);
+               smp_mb();
+               if (need_resched())
+                       break;
+               __mwait(0, 0);
        }
 }
 
index b48ac635f3c19cb79d11086835b538cc0b1dcf00..fdfcb0cba9b40183f9287fd08e13c22ae5a6419a 100644 (file)
@@ -129,9 +129,7 @@ struct drive_info_struct { char dummy[32]; } drive_info;
 EXPORT_SYMBOL(drive_info);
 #endif
 struct screen_info screen_info;
-#ifdef CONFIG_VT
 EXPORT_SYMBOL(screen_info);
-#endif
 struct apm_info apm_info;
 EXPORT_SYMBOL(apm_info);
 struct sys_desc_table_struct {
index 47ec76794d02ac11bdcef2416bff7796a9099572..bc5a9d97466b572cf5e6755fc5e5de0eb828b11f 100644 (file)
@@ -485,6 +485,7 @@ static void __devinit start_secondary(void *unused)
         * things done here to the most necessary things.
         */
        cpu_init();
+       preempt_disable();
        smp_callin();
        while (!cpu_isset(smp_processor_id(), smp_commenced_mask))
                rep_nop();
index 164b211f417474db5e566c4bab14024b10a3077c..88739394f6df5b1471e9c75b5aa6dd91b9ccf6d3 100644 (file)
 #define CODE
 #include "compat_ioctl.c"
 
-typedef int (* ioctl32_handler_t)(unsigned int, unsigned int, unsigned long, struct file *);
-
 #define COMPATIBLE_IOCTL(cmd)          HANDLE_IOCTL((cmd),sys_ioctl)
-#define HANDLE_IOCTL(cmd,handler)      { (cmd), (ioctl32_handler_t)(handler), NULL },
+#define HANDLE_IOCTL(cmd,handler)      { (cmd), (ioctl_trans_handler_t)(handler), NULL },
 #define IOCTL_TABLE_START \
        struct ioctl_trans ioctl_start[] = {
 #define IOCTL_TABLE_END \
index f081c60ab20684234f3e815ef4e520cdd8d75de8..eb39bc9c133bd05dbf5adba4017dc286d56e473a 100644 (file)
@@ -88,7 +88,7 @@ mca_page_isolate(unsigned long paddr)
        if (!ia64_phys_addr_valid(paddr))
                return ISOLATE_NONE;
 
-       if (!pfn_valid(paddr))
+       if (!pfn_valid(paddr >> PAGE_SHIFT))
                return ISOLATE_NONE;
 
        /* convert physical address to physical page number */
@@ -108,6 +108,7 @@ mca_page_isolate(unsigned long paddr)
                return ISOLATE_NG;
 
        /* add attribute 'Reserved' and register the page */
+       get_page(p);
        SetPageReserved(p);
        page_isolate[num_page_isolate++] = p;
 
index 051e050359e490ac4a5e44a90cb6c46849ea77f9..640d6908f8ec9727525f798fd306af5f981617eb 100644 (file)
@@ -197,11 +197,15 @@ void
 default_idle (void)
 {
        local_irq_enable();
-       while (!need_resched())
-               if (can_do_pal_halt)
-                       safe_halt();
-               else
+       while (!need_resched()) {
+               if (can_do_pal_halt) {
+                       local_irq_disable();
+                       if (!need_resched())
+                               safe_halt();
+                       local_irq_enable();
+               } else
                        cpu_relax();
+       }
 }
 
 #ifdef CONFIG_HOTPLUG_CPU
@@ -263,16 +267,16 @@ void __attribute__((noreturn))
 cpu_idle (void)
 {
        void (*mark_idle)(int) = ia64_mark_idle;
+       int cpu = smp_processor_id();
+       set_thread_flag(TIF_POLLING_NRFLAG);
 
        /* endless idle loop with no priority at all */
        while (1) {
+               if (!need_resched()) {
+                       void (*idle)(void);
 #ifdef CONFIG_SMP
-               if (!need_resched())
                        min_xtp();
 #endif
-               while (!need_resched()) {
-                       void (*idle)(void);
-
                        if (__get_cpu_var(cpu_idle_state))
                                __get_cpu_var(cpu_idle_state) = 0;
 
@@ -284,17 +288,17 @@ cpu_idle (void)
                        if (!idle)
                                idle = default_idle;
                        (*idle)();
-               }
-
-               if (mark_idle)
-                       (*mark_idle)(0);
-
+                       if (mark_idle)
+                               (*mark_idle)(0);
 #ifdef CONFIG_SMP
-               normal_xtp();
+                       normal_xtp();
 #endif
+               }
+               preempt_enable_no_resched();
                schedule();
+               preempt_disable();
                check_pgt_cache();
-               if (cpu_is_offline(smp_processor_id()))
+               if (cpu_is_offline(cpu))
                        play_dead();
        }
 }
index 400a4898712492da0bdbe28ea27aa525f7a842ef..8f44e7d2df66eb8e0d052132ab8fe7a390587212 100644 (file)
@@ -399,6 +399,7 @@ start_secondary (void *unused)
        Dprintk("start_secondary: starting CPU 0x%x\n", hard_smp_processor_id());
        efi_map_pal_code();
        cpu_init();
+       preempt_disable();
        smp_callin();
 
        cpu_idle();
index 7b03b8084ffc441d90d3725e601816f6b856d741..1f500c81002c88869a47935cad3237eaad10bca3 100644 (file)
@@ -212,13 +212,13 @@ void pcibr_target_interrupt(struct sn_irq_info *sn_irq_info)
                    pdi_pcibus_info;
 
                /* Disable the device's IRQ   */
-               pcireg_intr_enable_bit_clr(pcibus_info, bit);
+               pcireg_intr_enable_bit_clr(pcibus_info, (1 << bit));
 
                /* Change the device's IRQ    */
                pcireg_intr_addr_addr_set(pcibus_info, bit, xtalk_addr);
 
                /* Re-enable the device's IRQ */
-               pcireg_intr_enable_bit_set(pcibus_info, bit);
+               pcireg_intr_enable_bit_set(pcibus_info, (1 << bit));
 
                pcibr_force_interrupt(sn_irq_info);
        }
index 4f718c3e93d3b47b07c4f3bc130ec88b02cb4198..5d534091262c9f8a4a545a8e748e8defa38ab488 100644 (file)
@@ -131,7 +131,7 @@ void pcireg_intr_enable_bit_clr(struct pcibus_info *pcibus_info, uint64_t bits)
                        __sn_clrq_relaxed(&ptr->tio.cp_int_enable, bits);
                        break;
                case PCIBR_BRIDGETYPE_PIC:
-                       __sn_clrq_relaxed(&ptr->pic.p_int_enable, ~bits);
+                       __sn_clrq_relaxed(&ptr->pic.p_int_enable, bits);
                        break;
                default:
                        panic
index ea13a8f4d8b05aadc691f010435b6fa6ef751a91..cc4b571e5db715c1fba35eab7ce3ee0d1e6784ef 100644 (file)
@@ -104,7 +104,9 @@ void cpu_idle (void)
 
                        idle();
                }
+               preempt_enable_no_resched();
                schedule();
+               preempt_disable();
        }
 }
 
index 640d592ea07251207f59f4864cfd0ce9e1ad580d..b90c54169fa5ae22bd82f68988d44c2a14705873 100644 (file)
@@ -426,6 +426,7 @@ void __init smp_cpus_done(unsigned int max_cpus)
 int __init start_secondary(void *unused)
 {
        cpu_init();
+       preempt_disable();
        smp_callin();
        while (!cpu_isset(smp_processor_id(), smp_commenced_mask))
                cpu_relax();
index 11b1b90ba6ba49d4dc193517921fd88a5fe84a9f..13d109328a428166d4a11ba456595ff2d0170a91 100644 (file)
@@ -102,7 +102,9 @@ void cpu_idle(void)
        while (1) {
                while (!need_resched())
                        idle();
+               preempt_enable_no_resched();
                schedule();
+               preempt_disable();
        }
 }
 
index 1ef15d5ef943937c47f61903872e29ebd02a2b6a..4f21f42d096bad6737343318c64d45a802cffa77 100644 (file)
@@ -111,17 +111,6 @@ void __init plat_setup(void)
     }
 #endif
 
-#ifdef CONFIG_FB_E1356
-       if ((argptr = strstr(argptr, "video=")) == NULL) {
-               argptr = prom_getcmdline();
-#ifdef CONFIG_MIPS_PB1000
-               strcat(argptr, " video=e1356fb:system:pb1000,mmunalign:1");
-#else
-               strcat(argptr, " video=e1356fb:system:pb1500");
-#endif
-       }
-#endif
-
 #ifdef CONFIG_FB_XPERT98
        if ((argptr = strstr(argptr, "video=")) == NULL) {
                argptr = prom_getcmdline();
index b260e51eb51730bfc3e0c12dc06ee527831cc25a..326f3aa637419a4583edb299e3a715f60b9571fe 100644 (file)
@@ -658,7 +658,6 @@ CONFIG_FB=y
 # CONFIG_FB_SMIVGX is not set
 # CONFIG_FB_CYBLA is not set
 # CONFIG_FB_TRIDENT is not set
-# CONFIG_FB_E1356 is not set
 # CONFIG_FB_S1D13XXX is not set
 # CONFIG_FB_VIRTUAL is not set
 
index 9a728c2d8fd570d02c1b71db15b629ae9a220188..6390a753e80bc49edc3f07c2f4f36ee0127947d7 100644 (file)
@@ -628,7 +628,6 @@ CONFIG_FB=y
 # CONFIG_FB_SMIVGX is not set
 # CONFIG_FB_CYBLA is not set
 # CONFIG_FB_TRIDENT is not set
-# CONFIG_FB_E1356 is not set
 # CONFIG_FB_S1D13XXX is not set
 # CONFIG_FB_VIRTUAL is not set
 
index ffb23fcab862138ec53a87ffa6abc1d3711b505c..f18d05c2ca775abc6ccedc22ec7845e355e52512 100644 (file)
@@ -758,7 +758,6 @@ CONFIG_FB_MODE_HELPERS=y
 # CONFIG_FB_SMIVGX is not set
 # CONFIG_FB_CYBLA is not set
 # CONFIG_FB_TRIDENT is not set
-# CONFIG_FB_E1356 is not set
 # CONFIG_FB_S1D13XXX is not set
 # CONFIG_FB_VIRTUAL is not set
 
index 05e65206a7b459625f0fc2f73e8ee55f0af621e7..37bd8d5c865d7e88aeecc9f33a7100ab54dc8acb 100644 (file)
@@ -897,7 +897,6 @@ CONFIG_FB=y
 # CONFIG_FB_SMIVGX is not set
 # CONFIG_FB_CYBLA is not set
 # CONFIG_FB_TRIDENT is not set
-# CONFIG_FB_E1356 is not set
 # CONFIG_FB_S1D13XXX is not set
 # CONFIG_FB_VIRTUAL is not set
 
index 2bc61ca4ba0809da5ad99c7243115d7411e93f44..897420d39053fc9899a1a49e3488744164a707de 100644 (file)
@@ -876,7 +876,6 @@ CONFIG_FB_ATY_CT=y
 # CONFIG_FB_SMIVGX is not set
 # CONFIG_FB_CYBLA is not set
 # CONFIG_FB_TRIDENT is not set
-# CONFIG_FB_E1356 is not set
 # CONFIG_FB_S1D13XXX is not set
 # CONFIG_FB_VIRTUAL is not set
 
index ed9b2da510beb626ea443b5bc01d56c180cd0a1f..9ea1fc74886468cde3691cd2ef1cea7f68fe7bc1 100644 (file)
@@ -26,10 +26,8 @@ long sys_ioctl(unsigned int fd, unsigned int cmd, unsigned long arg);
 #define CODE
 #include "compat_ioctl.c"
 
-typedef int (* ioctl32_handler_t)(unsigned int, unsigned int, unsigned long, struct file *);
-
 #define COMPATIBLE_IOCTL(cmd)          HANDLE_IOCTL((cmd),sys_ioctl)
-#define HANDLE_IOCTL(cmd,handler)      { (cmd), (ioctl32_handler_t)(handler), NULL },
+#define HANDLE_IOCTL(cmd,handler)      { (cmd), (ioctl_trans_handler_t)(handler), NULL },
 #define IOCTL_TABLE_START \
        struct ioctl_trans ioctl_start[] = {
 #define IOCTL_TABLE_END \
index 4fe3d5715c416c6b2aa74152f974348f757b2c41..dd725779d91fa19857e667a9c4131d381a16f410 100644 (file)
@@ -52,7 +52,9 @@ ATTRIB_NORET void cpu_idle(void)
                while (!need_resched())
                        if (cpu_wait)
                                (*cpu_wait)();
+               preempt_enable_no_resched();
                schedule();
+               preempt_disable();
        }
 }
 
index fcacf1aae98aebd04e509107e56aeaf4d0c49f0f..25472fcaf7157c1cc7c888f5f759ec0404870c06 100644 (file)
@@ -82,7 +82,7 @@ extern ATTRIB_NORET void cpu_idle(void);
  */
 asmlinkage void start_secondary(void)
 {
-       unsigned int cpu = smp_processor_id();
+       unsigned int cpu;
 
        cpu_probe();
        cpu_report();
@@ -95,6 +95,8 @@ asmlinkage void start_secondary(void)
         */
 
        calibrate_delay();
+       preempt_disable();
+       cpu = smp_processor_id();
        cpu_data[cpu].udelay_val = loops_per_jiffy;
 
        prom_smp_finish();
index 230f5a93c2e6d0a2c839a87999af39cf7864ff80..9cd9c0fe22658c9bcbcd6fbdb6e62a73f3ca609b 100644 (file)
@@ -84,7 +84,6 @@ IRQ  Device
 #include <asm/ptrace.h>
 #include <asm/reboot.h>
 #include <asm/time.h>
-#include <linux/version.h>
 #include <linux/bootmem.h>
 #include <asm/tx4938/rbtx4938.h>
 
index 1ad44f92d6e469a58fa4a7b5e6e42a1096a82efa..e23c4e1e3a25c5dd8d2e73dbfe8e47bf49ade25c 100644 (file)
@@ -30,7 +30,6 @@
 #include <linux/types.h>
 #include <linux/sched.h>
 #include <linux/thread_info.h>
-#include <linux/version.h>
 #include <linux/ptrace.h>
 #include <linux/hardirq.h>
 
index 7fdca87ef647369bc12a5c77330f35f15c7f7f53..fee4f1f09adc687b84bcfdd5355a6f1fa3c8a1f4 100644 (file)
@@ -88,11 +88,15 @@ void default_idle(void)
  */
 void cpu_idle(void)
 {
+       set_thread_flag(TIF_POLLING_NRFLAG);
+
        /* endless idle loop with no priority at all */
        while (1) {
                while (!need_resched())
                        barrier();
+               preempt_enable_no_resched();
                schedule();
+               preempt_disable();
                check_pgt_cache();
        }
 }
index 5db3be4e2704ba8ed5e982b0e22ab841dff23c6c..a9ecf6465784eb0272518d648e39c2814d31dc02 100644 (file)
@@ -463,6 +463,7 @@ void __init smp_callin(void)
 #endif
 
        smp_cpu_init(slave_id);
+       preempt_disable();
 
 #if 0  /* NOT WORKING YET - see entry.S */
        istack = (void *)__get_free_pages(GFP_KERNEL,ISTACK_ORDER);
index 6ffae2d2b3fa655ad46dcde5cfac90996cde7bc0..1493c7896fe35f3af26a866e56f4c1b5aed5a2b5 100644 (file)
@@ -404,6 +404,14 @@ config CPU_FREQ_PMAC
          this currently includes some models of iBook & Titanium
          PowerBook.
 
+config CPU_FREQ_PMAC64
+       bool "Support for some Apple G5s"
+       depends on CPU_FREQ && PMAC_SMU && PPC64
+       select CPU_FREQ_TABLE
+       help
+         This adds support for frequency switching on Apple iMac G5,
+         and some of the more recent desktop G5 machines as well.
+
 config PPC601_SYNC_FIX
        bool "Workarounds for PPC601 bugs"
        depends on 6xx && (PPC_PREP || PPC_PMAC)
@@ -484,6 +492,7 @@ source "fs/Kconfig.binfmt"
 config FORCE_MAX_ZONEORDER
        int
        depends on PPC64
+       default "9" if PPC_64K_PAGES
        default "13"
 
 config MATH_EMULATION
index 6323065fbf2ce0d71692bb24ba117923fb1a3ede..e76854f8c121c0ae49acbdea06a1d11284271643 100644 (file)
@@ -1,18 +1,32 @@
 #
 # Automatically generated make config: don't edit
-# Linux kernel version: 2.6.14-rc4
-# Thu Oct 20 08:30:23 2005
+# Linux kernel version: 2.6.14
+# Mon Nov  7 13:37:59 2005
 #
+CONFIG_PPC64=y
 CONFIG_64BIT=y
+CONFIG_PPC_MERGE=y
 CONFIG_MMU=y
+CONFIG_GENERIC_HARDIRQS=y
 CONFIG_RWSEM_XCHGADD_ALGORITHM=y
 CONFIG_GENERIC_CALIBRATE_DELAY=y
-CONFIG_GENERIC_ISA_DMA=y
+CONFIG_PPC=y
 CONFIG_EARLY_PRINTK=y
 CONFIG_COMPAT=y
+CONFIG_SYSVIPC_COMPAT=y
 CONFIG_SCHED_NO_NO_OMIT_FRAME_POINTER=y
 CONFIG_ARCH_MAY_HAVE_PC_FDC=y
-CONFIG_FORCE_MAX_ZONEORDER=13
+
+#
+# Processor support
+#
+CONFIG_POWER4_ONLY=y
+CONFIG_POWER4=y
+CONFIG_PPC_FPU=y
+CONFIG_ALTIVEC=y
+CONFIG_PPC_STD_MMU=y
+CONFIG_SMP=y
+CONFIG_NR_CPUS=2
 
 #
 # Code maturity level options
@@ -67,30 +81,60 @@ CONFIG_MODVERSIONS=y
 CONFIG_MODULE_SRCVERSION_ALL=y
 CONFIG_KMOD=y
 CONFIG_STOP_MACHINE=y
-CONFIG_SYSVIPC_COMPAT=y
 
 #
 # Platform support
 #
-# CONFIG_PPC_ISERIES is not set
 CONFIG_PPC_MULTIPLATFORM=y
+# CONFIG_PPC_ISERIES is not set
+# CONFIG_EMBEDDED6xx is not set
+# CONFIG_APUS is not set
 # CONFIG_PPC_PSERIES is not set
-# CONFIG_PPC_BPA is not set
 CONFIG_PPC_PMAC=y
+CONFIG_PPC_PMAC64=y
 # CONFIG_PPC_MAPLE is not set
-CONFIG_PPC=y
-CONFIG_PPC64=y
+# CONFIG_PPC_CELL is not set
 CONFIG_PPC_OF=y
-CONFIG_MPIC=y
-CONFIG_ALTIVEC=y
-CONFIG_KEXEC=y
 CONFIG_U3_DART=y
-CONFIG_PPC_PMAC64=y
-CONFIG_BOOTX_TEXT=y
-CONFIG_POWER4_ONLY=y
+CONFIG_MPIC=y
+# CONFIG_PPC_RTAS is not set
+# CONFIG_MMIO_NVRAM is not set
+# CONFIG_PPC_MPC106 is not set
+CONFIG_GENERIC_TBSYNC=y
+CONFIG_CPU_FREQ=y
+CONFIG_CPU_FREQ_TABLE=y
+# CONFIG_CPU_FREQ_DEBUG is not set
+CONFIG_CPU_FREQ_STAT=y
+# CONFIG_CPU_FREQ_STAT_DETAILS is not set
+CONFIG_CPU_FREQ_DEFAULT_GOV_PERFORMANCE=y
+# CONFIG_CPU_FREQ_DEFAULT_GOV_USERSPACE is not set
+CONFIG_CPU_FREQ_GOV_PERFORMANCE=y
+CONFIG_CPU_FREQ_GOV_POWERSAVE=y
+CONFIG_CPU_FREQ_GOV_USERSPACE=y
+# CONFIG_CPU_FREQ_GOV_ONDEMAND is not set
+# CONFIG_CPU_FREQ_GOV_CONSERVATIVE is not set
+CONFIG_CPU_FREQ_PMAC64=y
+# CONFIG_WANT_EARLY_SERIAL is not set
+
+#
+# Kernel options
+#
+# CONFIG_HZ_100 is not set
+CONFIG_HZ_250=y
+# CONFIG_HZ_1000 is not set
+CONFIG_HZ=250
+CONFIG_PREEMPT_NONE=y
+# CONFIG_PREEMPT_VOLUNTARY is not set
+# CONFIG_PREEMPT is not set
+# CONFIG_PREEMPT_BKL is not set
+CONFIG_BINFMT_ELF=y
+# CONFIG_BINFMT_MISC is not set
+CONFIG_FORCE_MAX_ZONEORDER=13
 CONFIG_IOMMU_VMERGE=y
-CONFIG_SMP=y
-CONFIG_NR_CPUS=2
+# CONFIG_HOTPLUG_CPU is not set
+CONFIG_KEXEC=y
+CONFIG_IRQ_ALL_CPUS=y
+# CONFIG_NUMA is not set
 CONFIG_ARCH_SELECT_MEMORY_MODEL=y
 CONFIG_ARCH_FLATMEM_ENABLE=y
 CONFIG_SELECT_MEMORY_MODEL=y
@@ -100,28 +144,21 @@ CONFIG_FLATMEM_MANUAL=y
 CONFIG_FLATMEM=y
 CONFIG_FLAT_NODE_MEM_MAP=y
 # CONFIG_SPARSEMEM_STATIC is not set
-# CONFIG_NUMA is not set
+CONFIG_SPLIT_PTLOCK_CPUS=4
+# CONFIG_PPC_64K_PAGES is not set
 # CONFIG_SCHED_SMT is not set
-CONFIG_PREEMPT_NONE=y
-# CONFIG_PREEMPT_VOLUNTARY is not set
-# CONFIG_PREEMPT is not set
-# CONFIG_PREEMPT_BKL is not set
-# CONFIG_HZ_100 is not set
-CONFIG_HZ_250=y
-# CONFIG_HZ_1000 is not set
-CONFIG_HZ=250
-CONFIG_GENERIC_HARDIRQS=y
-CONFIG_SECCOMP=y
-CONFIG_BINFMT_ELF=y
-# CONFIG_BINFMT_MISC is not set
-# CONFIG_HOTPLUG_CPU is not set
 CONFIG_PROC_DEVICETREE=y
 # CONFIG_CMDLINE_BOOL is not set
+# CONFIG_PM is not set
+CONFIG_SECCOMP=y
 CONFIG_ISA_DMA_API=y
 
 #
-# Bus Options
+# Bus options
 #
+CONFIG_GENERIC_ISA_DMA=y
+# CONFIG_PPC_I8259 is not set
+# CONFIG_PPC_INDIRECT_PCI is not set
 CONFIG_PCI=y
 CONFIG_PCI_DOMAINS=y
 CONFIG_PCI_LEGACY_PROC=y
@@ -136,6 +173,7 @@ CONFIG_PCI_LEGACY_PROC=y
 # PCI Hotplug Support
 #
 # CONFIG_HOTPLUG_PCI is not set
+CONFIG_KERNEL_START=0xc000000000000000
 
 #
 # Networking
@@ -276,6 +314,10 @@ CONFIG_LLC=y
 # CONFIG_NET_DIVERT is not set
 # CONFIG_ECONET is not set
 # CONFIG_WAN_ROUTER is not set
+
+#
+# QoS and/or fair queueing
+#
 # CONFIG_NET_SCHED is not set
 CONFIG_NET_CLS_ROUTE=y
 
@@ -348,6 +390,11 @@ CONFIG_IOSCHED_NOOP=y
 CONFIG_IOSCHED_AS=y
 CONFIG_IOSCHED_DEADLINE=y
 CONFIG_IOSCHED_CFQ=y
+CONFIG_DEFAULT_AS=y
+# CONFIG_DEFAULT_DEADLINE is not set
+# CONFIG_DEFAULT_CFQ is not set
+# CONFIG_DEFAULT_NOOP is not set
+CONFIG_DEFAULT_IOSCHED="anticipatory"
 # CONFIG_ATA_OVER_ETH is not set
 
 #
@@ -449,6 +496,7 @@ CONFIG_SCSI_SPI_ATTRS=y
 #
 # SCSI low-level drivers
 #
+# CONFIG_ISCSI_TCP is not set
 # CONFIG_BLK_DEV_3W_XXXX_RAID is not set
 # CONFIG_SCSI_3W_9XXX is not set
 # CONFIG_SCSI_ACARD is not set
@@ -465,10 +513,12 @@ CONFIG_SCSI_SATA_SVW=y
 # CONFIG_SCSI_ATA_PIIX is not set
 # CONFIG_SCSI_SATA_MV is not set
 # CONFIG_SCSI_SATA_NV is not set
-# CONFIG_SCSI_SATA_PROMISE is not set
+# CONFIG_SCSI_PDC_ADMA is not set
 # CONFIG_SCSI_SATA_QSTOR is not set
+# CONFIG_SCSI_SATA_PROMISE is not set
 # CONFIG_SCSI_SATA_SX4 is not set
 # CONFIG_SCSI_SATA_SIL is not set
+# CONFIG_SCSI_SATA_SIL24 is not set
 # CONFIG_SCSI_SATA_SIS is not set
 # CONFIG_SCSI_SATA_ULI is not set
 # CONFIG_SCSI_SATA_VIA is not set
@@ -567,6 +617,9 @@ CONFIG_IEEE1394_RAWIO=y
 CONFIG_ADB_PMU=y
 CONFIG_PMAC_SMU=y
 CONFIG_THERM_PM72=y
+CONFIG_WINDFARM=y
+CONFIG_WINDFARM_PM81=y
+CONFIG_WINDFARM_PM91=y
 
 #
 # Network device support
@@ -603,6 +656,7 @@ CONFIG_SUNGEM=y
 # CONFIG_NET_TULIP is not set
 # CONFIG_HP100 is not set
 # CONFIG_NET_PCI is not set
+# CONFIG_FEC_8XX is not set
 
 #
 # Ethernet (1000 Mbit)
@@ -768,6 +822,7 @@ CONFIG_MAX_RAW_DEVS=256
 # TPM devices
 #
 # CONFIG_TCG_TPM is not set
+# CONFIG_TELCLOCK is not set
 
 #
 # I2C support
@@ -820,6 +875,7 @@ CONFIG_I2C_PMAC_SMU=y
 # CONFIG_SENSORS_PCF8591 is not set
 # CONFIG_SENSORS_RTC8564 is not set
 # CONFIG_SENSORS_MAX6875 is not set
+# CONFIG_RTC_X1205_I2C is not set
 # CONFIG_I2C_DEBUG_CORE is not set
 # CONFIG_I2C_DEBUG_ALGO is not set
 # CONFIG_I2C_DEBUG_BUS is not set
@@ -876,10 +932,9 @@ CONFIG_FB_OF=y
 # CONFIG_FB_ASILIANT is not set
 # CONFIG_FB_IMSTT is not set
 # CONFIG_FB_VGA16 is not set
-# CONFIG_FB_NVIDIA is not set
-CONFIG_FB_RIVA=y
-# CONFIG_FB_RIVA_I2C is not set
-# CONFIG_FB_RIVA_DEBUG is not set
+CONFIG_FB_NVIDIA=y
+CONFIG_FB_NVIDIA_I2C=y
+# CONFIG_FB_RIVA is not set
 # CONFIG_FB_MATROX is not set
 # CONFIG_FB_RADEON_OLD is not set
 CONFIG_FB_RADEON=y
@@ -924,7 +979,96 @@ CONFIG_LCD_DEVICE=y
 #
 # Sound
 #
-# CONFIG_SOUND is not set
+CONFIG_SOUND=m
+
+#
+# Advanced Linux Sound Architecture
+#
+CONFIG_SND=m
+CONFIG_SND_TIMER=m
+CONFIG_SND_PCM=m
+CONFIG_SND_HWDEP=m
+CONFIG_SND_RAWMIDI=m
+CONFIG_SND_SEQUENCER=m
+# CONFIG_SND_SEQ_DUMMY is not set
+CONFIG_SND_OSSEMUL=y
+CONFIG_SND_MIXER_OSS=m
+CONFIG_SND_PCM_OSS=m
+CONFIG_SND_SEQUENCER_OSS=y
+# CONFIG_SND_VERBOSE_PRINTK is not set
+# CONFIG_SND_DEBUG is not set
+CONFIG_SND_GENERIC_DRIVER=y
+
+#
+# Generic devices
+#
+# CONFIG_SND_DUMMY is not set
+# CONFIG_SND_VIRMIDI is not set
+# CONFIG_SND_MTPAV is not set
+# CONFIG_SND_SERIAL_U16550 is not set
+# CONFIG_SND_MPU401 is not set
+
+#
+# PCI devices
+#
+# CONFIG_SND_ALI5451 is not set
+# CONFIG_SND_ATIIXP is not set
+# CONFIG_SND_ATIIXP_MODEM is not set
+# CONFIG_SND_AU8810 is not set
+# CONFIG_SND_AU8820 is not set
+# CONFIG_SND_AU8830 is not set
+# CONFIG_SND_AZT3328 is not set
+# CONFIG_SND_BT87X is not set
+# CONFIG_SND_CS46XX is not set
+# CONFIG_SND_CS4281 is not set
+# CONFIG_SND_EMU10K1 is not set
+# CONFIG_SND_EMU10K1X is not set
+# CONFIG_SND_CA0106 is not set
+# CONFIG_SND_KORG1212 is not set
+# CONFIG_SND_MIXART is not set
+# CONFIG_SND_NM256 is not set
+# CONFIG_SND_RME32 is not set
+# CONFIG_SND_RME96 is not set
+# CONFIG_SND_RME9652 is not set
+# CONFIG_SND_HDSP is not set
+# CONFIG_SND_HDSPM is not set
+# CONFIG_SND_TRIDENT is not set
+# CONFIG_SND_YMFPCI is not set
+# CONFIG_SND_AD1889 is not set
+# CONFIG_SND_ALS4000 is not set
+# CONFIG_SND_CMIPCI is not set
+# CONFIG_SND_ENS1370 is not set
+# CONFIG_SND_ENS1371 is not set
+# CONFIG_SND_ES1938 is not set
+# CONFIG_SND_ES1968 is not set
+# CONFIG_SND_MAESTRO3 is not set
+# CONFIG_SND_FM801 is not set
+# CONFIG_SND_ICE1712 is not set
+# CONFIG_SND_ICE1724 is not set
+# CONFIG_SND_INTEL8X0 is not set
+# CONFIG_SND_INTEL8X0M is not set
+# CONFIG_SND_SONICVIBES is not set
+# CONFIG_SND_VIA82XX is not set
+# CONFIG_SND_VIA82XX_MODEM is not set
+# CONFIG_SND_VX222 is not set
+# CONFIG_SND_HDA_INTEL is not set
+
+#
+# ALSA PowerMac devices
+#
+CONFIG_SND_POWERMAC=m
+CONFIG_SND_POWERMAC_AUTO_DRC=y
+
+#
+# USB devices
+#
+CONFIG_SND_USB_AUDIO=m
+# CONFIG_SND_USB_USX2Y is not set
+
+#
+# Open Sound System
+#
+# CONFIG_SOUND_PRIME is not set
 
 #
 # USB support
@@ -958,12 +1102,16 @@ CONFIG_USB_OHCI_LITTLE_ENDIAN=y
 #
 # USB Device Class drivers
 #
-# CONFIG_USB_BLUETOOTH_TTY is not set
+# CONFIG_OBSOLETE_OSS_USB_DRIVER is not set
 CONFIG_USB_ACM=m
 CONFIG_USB_PRINTER=y
 
 #
-# NOTE: USB_STORAGE enables SCSI, and 'SCSI disk support' may also be needed; see USB_STORAGE Help for more information
+# NOTE: USB_STORAGE enables SCSI, and 'SCSI disk support'
+#
+
+#
+# may also be needed; see USB_STORAGE Help for more information
 #
 CONFIG_USB_STORAGE=y
 # CONFIG_USB_STORAGE_DEBUG is not set
@@ -1074,6 +1222,7 @@ CONFIG_USB_SERIAL_KEYSPAN_USA49WLC=y
 CONFIG_USB_SERIAL_KLSI=m
 CONFIG_USB_SERIAL_KOBIL_SCT=m
 CONFIG_USB_SERIAL_MCT_U232=m
+# CONFIG_USB_SERIAL_NOKIA_DKU2 is not set
 CONFIG_USB_SERIAL_PL2303=m
 # CONFIG_USB_SERIAL_HP4X is not set
 CONFIG_USB_SERIAL_SAFE=m
@@ -1310,6 +1459,20 @@ CONFIG_NLS_ISO8859_15=y
 # CONFIG_NLS_KOI8_U is not set
 CONFIG_NLS_UTF8=y
 
+#
+# Library routines
+#
+CONFIG_CRC_CCITT=m
+# CONFIG_CRC16 is not set
+CONFIG_CRC32=y
+CONFIG_LIBCRC32C=m
+CONFIG_ZLIB_INFLATE=y
+CONFIG_ZLIB_DEFLATE=m
+CONFIG_TEXTSEARCH=y
+CONFIG_TEXTSEARCH_KMP=m
+CONFIG_TEXTSEARCH_BM=m
+CONFIG_TEXTSEARCH_FSM=m
+
 #
 # Profiling support
 #
@@ -1331,12 +1494,14 @@ CONFIG_DETECT_SOFTLOCKUP=y
 # CONFIG_DEBUG_KOBJECT is not set
 # CONFIG_DEBUG_INFO is not set
 CONFIG_DEBUG_FS=y
+# CONFIG_DEBUG_VM is not set
+# CONFIG_RCU_TORTURE_TEST is not set
 # CONFIG_DEBUG_STACKOVERFLOW is not set
 # CONFIG_KPROBES is not set
 # CONFIG_DEBUG_STACK_USAGE is not set
 # CONFIG_DEBUGGER is not set
-# CONFIG_PPCDBG is not set
 CONFIG_IRQSTACKS=y
+CONFIG_BOOTX_TEXT=y
 
 #
 # Security options
@@ -1376,17 +1541,3 @@ CONFIG_CRYPTO_TEST=m
 #
 # Hardware crypto devices
 #
-
-#
-# Library routines
-#
-CONFIG_CRC_CCITT=m
-# CONFIG_CRC16 is not set
-CONFIG_CRC32=y
-CONFIG_LIBCRC32C=m
-CONFIG_ZLIB_INFLATE=y
-CONFIG_ZLIB_DEFLATE=m
-CONFIG_TEXTSEARCH=y
-CONFIG_TEXTSEARCH_KMP=m
-CONFIG_TEXTSEARCH_BM=m
-CONFIG_TEXTSEARCH_FSM=m
index b3e95ff0dba0a63116d6e06f375d56c138dec85b..ae1433da09b27ea4cd76f0013616a35d38560855 100644 (file)
@@ -603,6 +603,76 @@ _GLOBAL(real_writeb)
        blr
 #endif /* defined(CONFIG_PPC_PMAC) || defined(CONFIG_PPC_MAPLE) */
 
+/*
+ * SCOM access functions for 970 (FX only for now)
+ *
+ * unsigned long scom970_read(unsigned int address);
+ * void scom970_write(unsigned int address, unsigned long value);
+ *
+ * The address passed in is the 24 bits register address. This code
+ * is 970 specific and will not check the status bits, so you should
+ * know what you are doing.
+ */
+_GLOBAL(scom970_read)
+       /* interrupts off */
+       mfmsr   r4
+       ori     r0,r4,MSR_EE
+       xori    r0,r0,MSR_EE
+       mtmsrd  r0,1
+
+       /* rotate 24 bits SCOM address 8 bits left and mask out it's low 8 bits
+        * (including parity). On current CPUs they must be 0'd,
+        * and finally or in RW bit
+        */
+       rlwinm  r3,r3,8,0,15
+       ori     r3,r3,0x8000
+
+       /* do the actual scom read */
+       sync
+       mtspr   SPRN_SCOMC,r3
+       isync
+       mfspr   r3,SPRN_SCOMD
+       isync
+       mfspr   r0,SPRN_SCOMC
+       isync
+
+       /* XXX: fixup result on some buggy 970's (ouch ! we lost a bit, bah
+        * that's the best we can do). Not implemented yet as we don't use
+        * the scom on any of the bogus CPUs yet, but may have to be done
+        * ultimately
+        */
+
+       /* restore interrupts */
+       mtmsrd  r4,1
+       blr
+
+
+_GLOBAL(scom970_write)
+       /* interrupts off */
+       mfmsr   r5
+       ori     r0,r5,MSR_EE
+       xori    r0,r0,MSR_EE
+       mtmsrd  r0,1
+
+       /* rotate 24 bits SCOM address 8 bits left and mask out it's low 8 bits
+        * (including parity). On current CPUs they must be 0'd.
+        */
+
+       rlwinm  r3,r3,8,0,15
+
+       sync
+       mtspr   SPRN_SCOMD,r4      /* write data */
+       isync
+       mtspr   SPRN_SCOMC,r3      /* write command */
+       isync
+       mfspr   3,SPRN_SCOMC
+       isync
+
+       /* restore interrupts */
+       mtmsrd  r5,1
+       blr
+
+
 /*
  * Create a kernel thread
  *   kernel_thread(fn, arg, flags)
index 7f64f0464d446997756c4fae4c903665d717ea19..de69fb37c7313ce83d450bdbd6f5a15eb621bdd0 100644 (file)
 #include <asm/processor.h>
 #include <asm/mmu.h>
 #include <asm/prom.h>
+#include <asm/machdep.h>
 #ifdef CONFIG_PPC64
 #include <asm/firmware.h>
 #include <asm/time.h>
-#include <asm/machdep.h>
 #endif
 
 extern unsigned long _get_SP(void);
@@ -203,10 +203,8 @@ int dump_spe(struct pt_regs *regs, elf_vrregset_t *evrregs)
 
 int set_dabr(unsigned long dabr)
 {
-#ifdef CONFIG_PPC64
        if (ppc_md.set_dabr)
                return ppc_md.set_dabr(dabr);
-#endif
 
        mtspr(SPRN_DABR, dabr);
        return 0;
index 3675ef4bac90f09c4e12b5d02580beecafa6ea40..f645adb57534be04a39a2ed7718362b06359e812 100644 (file)
@@ -1974,14 +1974,29 @@ EXPORT_SYMBOL(get_property);
 /*
  * Add a property to a node
  */
-void prom_add_property(struct device_node* np, struct property* prop)
+int prom_add_property(struct device_node* np, struct property* prop)
 {
-       struct property **next = &np->properties;
+       struct property **next;
 
        prop->next = NULL;      
-       while (*next)
+       write_lock(&devtree_lock);
+       next = &np->properties;
+       while (*next) {
+               if (strcmp(prop->name, (*next)->name) == 0) {
+                       /* duplicate ! don't insert it */
+                       write_unlock(&devtree_lock);
+                       return -1;
+               }
                next = &(*next)->next;
+       }
        *next = prop;
+       write_unlock(&devtree_lock);
+
+       /* try to add to proc as well if it was initialized */
+       if (np->pde)
+               proc_device_tree_add_prop(np->pde, prop);
+
+       return 0;
 }
 
 /* I quickly hacked that one, check against spec ! */
index c758b6624d7bee6c777c5e0532c8b16553b7f52b..6dc33d19fc2abcfcf1c6ce3726c5cbf4adcf49a6 100644 (file)
@@ -403,19 +403,19 @@ static int __init prom_next_node(phandle *nodep)
        }
 }
 
-static int __init prom_getprop(phandle node, const char *pname,
+static int inline prom_getprop(phandle node, const char *pname,
                               void *value, size_t valuelen)
 {
        return call_prom("getprop", 4, 1, node, ADDR(pname),
                         (u32)(unsigned long) value, (u32) valuelen);
 }
 
-static int __init prom_getproplen(phandle node, const char *pname)
+static int inline prom_getproplen(phandle node, const char *pname)
 {
        return call_prom("getproplen", 2, 1, node, ADDR(pname));
 }
 
-static int __init prom_setprop(phandle node, const char *pname,
+static int inline prom_setprop(phandle node, const char *pname,
                               void *value, size_t valuelen)
 {
        return call_prom("setprop", 4, 1, node, ADDR(pname),
@@ -1408,8 +1408,9 @@ static int __init prom_find_machine_type(void)
        struct prom_t *_prom = &RELOC(prom);
        char compat[256];
        int len, i = 0;
+#ifdef CONFIG_PPC64
        phandle rtas;
-
+#endif
        len = prom_getprop(_prom->root, "compatible",
                           compat, sizeof(compat)-1);
        if (len > 0) {
@@ -1872,7 +1873,7 @@ static void __init fixup_device_tree(void)
        if (prom_getprop(u3, "device-rev", &u3_rev, sizeof(u3_rev))
            == PROM_ERROR)
                return;
-       if (u3_rev != 0x35 && u3_rev != 0x37)
+       if (u3_rev < 0x35 || u3_rev > 0x39)
                return;
        /* does it need fixup ? */
        if (prom_getproplen(i2c, "interrupts") > 0)
index b7fc2d884950c2fa31e935ca7628ace355167610..9d4e07f6f1ecb5e061fa6619df534fde1491cef3 100644 (file)
@@ -17,6 +17,7 @@
 #include <linux/spinlock.h>
 #include <linux/module.h>
 #include <linux/init.h>
+#include <linux/delay.h>
 
 #include <asm/prom.h>
 #include <asm/rtas.h>
@@ -83,7 +84,7 @@ void call_rtas_display_status_delay(unsigned char c)
                while (width-- > 0)
                        call_rtas_display_status(' ');
                width = 16;
-               udelay(500000);
+               mdelay(500);
                pending_newline = 1;
        } else {
                if (pending_newline) {
@@ -608,7 +609,6 @@ asmlinkage int ppc_rtas(struct rtas_args __user *uargs)
        return 0;
 }
 
-#ifdef CONFIG_SMP
 /* This version can't take the spinlock, because it never returns */
 
 struct rtas_args rtas_stop_self_args = {
@@ -633,7 +633,6 @@ void rtas_stop_self(void)
 
        panic("Alas, I survived.\n");
 }
-#endif
 
 /*
  * Call early during boot, before mem init or bootmem, to retreive the RTAS
index d43fa8c0e5ac0861058b8800dafffb7fc63a8a5a..e22856ecb5a0396f1000cae57289a24107a168dd 100644 (file)
@@ -405,6 +405,46 @@ static int __init set_preferred_console(void)
 console_initcall(set_preferred_console);
 #endif /* CONFIG_PPC_MULTIPLATFORM */
 
+void __init check_for_initrd(void)
+{
+#ifdef CONFIG_BLK_DEV_INITRD
+       unsigned long *prop;
+
+       DBG(" -> check_for_initrd()\n");
+
+       if (of_chosen) {
+               prop = (unsigned long *)get_property(of_chosen,
+                               "linux,initrd-start", NULL);
+               if (prop != NULL) {
+                       initrd_start = (unsigned long)__va(*prop);
+                       prop = (unsigned long *)get_property(of_chosen,
+                                       "linux,initrd-end", NULL);
+                       if (prop != NULL) {
+                               initrd_end = (unsigned long)__va(*prop);
+                               initrd_below_start_ok = 1;
+                       } else
+                               initrd_start = 0;
+               }
+       }
+
+       /* If we were passed an initrd, set the ROOT_DEV properly if the values
+        * look sensible. If not, clear initrd reference.
+        */
+       if (initrd_start >= KERNELBASE && initrd_end >= KERNELBASE &&
+           initrd_end > initrd_start)
+               ROOT_DEV = Root_RAM0;
+       else {
+               printk("Bogus initrd %08lx %08lx\n", initrd_start, initrd_end);
+               initrd_start = initrd_end = 0;
+       }
+
+       if (initrd_start)
+               printk("Found initrd at 0x%lx:0x%lx\n", initrd_start, initrd_end);
+
+       DBG(" <- check_for_initrd()\n");
+#endif /* CONFIG_BLK_DEV_INITRD */
+}
+
 #ifdef CONFIG_SMP
 
 /**
index b45eedbb4b3a53ec439698ca3f7b115ad2ae87be..3af2631e3fab07f0ce0a4406bd897319a783d6a5 100644 (file)
@@ -286,6 +286,7 @@ void __init setup_arch(char **cmdline_p)
        loops_per_jiffy = 500000000 / HZ;
 
        unflatten_device_tree();
+       check_for_initrd();
        finish_device_tree();
 
        smp_setup_cpu_maps();
index b0994050024ff0c127dfece85a4e42ade8255387..0471e843b6c53961f515a6e46a8e594cbc26a946 100644 (file)
@@ -41,7 +41,6 @@
 #include <asm/elf.h>
 #include <asm/machdep.h>
 #include <asm/paca.h>
-#include <asm/ppcdebug.h>
 #include <asm/time.h>
 #include <asm/cputable.h>
 #include <asm/sections.h>
@@ -60,6 +59,7 @@
 #include <asm/firmware.h>
 #include <asm/systemcfg.h>
 #include <asm/xmon.h>
+#include <asm/udbg.h>
 
 #ifdef DEBUG
 #define DBG(fmt...) udbg_printf(fmt)
@@ -243,12 +243,6 @@ void __init early_setup(unsigned long dt_ptr)
 
        DBG(" -> early_setup()\n");
 
-       /*
-        * Fill the default DBG level (do we want to keep
-        * that old mecanism around forever ?)
-        */
-       ppcdbg_initialize();
-
        /*
         * Do early initializations using the flattened device
         * tree, like retreiving the physical memory map or
@@ -401,43 +395,6 @@ static void __init initialize_cache_info(void)
        DBG(" <- initialize_cache_info()\n");
 }
 
-static void __init check_for_initrd(void)
-{
-#ifdef CONFIG_BLK_DEV_INITRD
-       u64 *prop;
-
-       DBG(" -> check_for_initrd()\n");
-
-       if (of_chosen) {
-               prop = (u64 *)get_property(of_chosen,
-                               "linux,initrd-start", NULL);
-               if (prop != NULL) {
-                       initrd_start = (unsigned long)__va(*prop);
-                       prop = (u64 *)get_property(of_chosen,
-                                       "linux,initrd-end", NULL);
-                       if (prop != NULL) {
-                               initrd_end = (unsigned long)__va(*prop);
-                               initrd_below_start_ok = 1;
-                       } else
-                               initrd_start = 0;
-               }
-       }
-
-       /* If we were passed an initrd, set the ROOT_DEV properly if the values
-        * look sensible. If not, clear initrd reference.
-        */
-       if (initrd_start >= KERNELBASE && initrd_end >= KERNELBASE &&
-           initrd_end > initrd_start)
-               ROOT_DEV = Root_RAM0;
-       else
-               initrd_start = initrd_end = 0;
-
-       if (initrd_start)
-               printk("Found initrd at 0x%lx:0x%lx\n", initrd_start, initrd_end);
-
-       DBG(" <- check_for_initrd()\n");
-#endif /* CONFIG_BLK_DEV_INITRD */
-}
 
 /*
  * Do some initial setup of the system.  The parameters are those which 
@@ -521,7 +478,6 @@ void __init setup_system(void)
 
        printk("-----------------------------------------------------\n");
        printk("ppc64_pft_size                = 0x%lx\n", ppc64_pft_size);
-       printk("ppc64_debug_switch            = 0x%lx\n", ppc64_debug_switch);
        printk("ppc64_interrupt_controller    = 0x%ld\n", ppc64_interrupt_controller);
        printk("systemcfg                     = 0x%p\n", systemcfg);
        printk("systemcfg->platform           = 0x%x\n", systemcfg->platform);
index 876c57c11365a57ff36e75f5171c865fb5c35e70..081d931eae481e34671818eab5b21a208cb18012 100644 (file)
@@ -44,7 +44,6 @@
 #include <asm/cacheflush.h>
 #ifdef CONFIG_PPC64
 #include "ppc32.h"
-#include <asm/ppcdebug.h>
 #include <asm/unistd.h>
 #include <asm/vdso.h>
 #else
index ec9d0984b6a09118f89abeb7f95675247c293f9f..58194e150711992afe9315d12afcf990964e933f 100644 (file)
@@ -33,7 +33,6 @@
 #include <asm/ucontext.h>
 #include <asm/uaccess.h>
 #include <asm/pgtable.h>
-#include <asm/ppcdebug.h>
 #include <asm/unistd.h>
 #include <asm/cacheflush.h>
 #include <asm/vdso.h>
index 1794a694a92868d75adbd5584b6b6ac4fa72f9a7..5c330c3366e42e2ec500cd8fe98fbdd7c94c3bc8 100644 (file)
@@ -40,7 +40,6 @@
 #include <asm/prom.h>
 #include <asm/smp.h>
 #include <asm/time.h>
-#include <asm/xmon.h>
 #include <asm/machdep.h>
 #include <asm/cputable.h>
 #include <asm/system.h>
index b1c89bc4bf90bc5c32dca68dc52b0c1d08399b08..a6282b625b440203aebb48f58e59c10fb4fa1ed5 100644 (file)
@@ -61,6 +61,7 @@
 #include <asm/prom.h>
 #include <asm/irq.h>
 #include <asm/div64.h>
+#include <asm/smp.h>
 #ifdef CONFIG_PPC64
 #include <asm/systemcfg.h>
 #include <asm/firmware.h>
@@ -119,10 +120,6 @@ static unsigned adjusting_time = 0;
 unsigned long ppc_proc_freq;
 unsigned long ppc_tb_freq;
 
-#ifdef CONFIG_PPC32    /* XXX for now */
-#define boot_cpuid     0
-#endif
-
 u64 tb_last_jiffy __cacheline_aligned_in_smp;
 unsigned long tb_last_stamp;
 
index 07e5ee40b8700aadc5cc82a395c7c20e088a402a..0578f838760301d2dd7c20c1294ba5459c07e4cd 100644 (file)
@@ -39,7 +39,6 @@
 #include <asm/io.h>
 #include <asm/machdep.h>
 #include <asm/rtas.h>
-#include <asm/xmon.h>
 #include <asm/pmc.h>
 #ifdef CONFIG_PPC32
 #include <asm/reg.h>
@@ -748,22 +747,12 @@ static int check_bug_trap(struct pt_regs *regs)
                return 0;
        if (bug->line & BUG_WARNING_TRAP) {
                /* this is a WARN_ON rather than BUG/BUG_ON */
-#ifdef CONFIG_XMON
-               xmon_printf(KERN_ERR "Badness in %s at %s:%ld\n",
-                      bug->function, bug->file,
-                      bug->line & ~BUG_WARNING_TRAP);
-#endif /* CONFIG_XMON */               
                printk(KERN_ERR "Badness in %s at %s:%ld\n",
                       bug->function, bug->file,
                       bug->line & ~BUG_WARNING_TRAP);
                dump_stack();
                return 1;
        }
-#ifdef CONFIG_XMON
-       xmon_printf(KERN_CRIT "kernel BUG in %s at %s:%ld!\n",
-              bug->function, bug->file, bug->line);
-       xmon(regs);
-#endif /* CONFIG_XMON */
        printk(KERN_CRIT "kernel BUG in %s at %s:%ld!\n",
               bug->function, bug->file, bug->line);
 
@@ -898,10 +887,6 @@ void altivec_unavailable_exception(struct pt_regs *regs)
        die("Unrecoverable VMX/Altivec Unavailable Exception", regs, SIGABRT);
 }
 
-#ifdef CONFIG_PPC64
-extern perf_irq_t perf_irq;
-#endif
-
 #if defined(CONFIG_PPC64) || defined(CONFIG_E500)
 void performance_monitor_exception(struct pt_regs *regs)
 {
index 97082a4203ada988fbbf9b8735ce8f25dbafbd05..71a6addf9f7fba85e81d614235cfc72670b569d0 100644 (file)
@@ -21,6 +21,7 @@
 #include <asm/iommu.h>
 #include <asm/dma.h>
 #include <asm/vio.h>
+#include <asm/prom.h>
 
 static const struct vio_device_id *vio_match_device(
                const struct vio_device_id *, const struct vio_dev *);
@@ -265,7 +266,33 @@ static int vio_bus_match(struct device *dev, struct device_driver *drv)
        return (ids != NULL) && (vio_match_device(ids, vio_dev) != NULL);
 }
 
+static int vio_hotplug(struct device *dev, char **envp, int num_envp,
+                       char *buffer, int buffer_size)
+{
+       const struct vio_dev *vio_dev = to_vio_dev(dev);
+       char *cp;
+       int length;
+
+       if (!num_envp)
+               return -ENOMEM;
+
+       if (!vio_dev->dev.platform_data)
+               return -ENODEV;
+       cp = (char *)get_property(vio_dev->dev.platform_data, "compatible", &length);
+       if (!cp)
+               return -ENODEV;
+
+       envp[0] = buffer;
+       length = scnprintf(buffer, buffer_size, "MODALIAS=vio:T%sS%s",
+                               vio_dev->type, cp);
+       if (buffer_size - length <= 0)
+               return -ENOMEM;
+       envp[1] = NULL;
+       return 0;
+}
+
 struct bus_type vio_bus_type = {
        .name = "vio",
+       .hotplug = vio_hotplug,
        .match = vio_bus_match,
 };
index 2a912f411eb4af13500c97271e71e2b32d650daf..35bd03c41dd19727601e15f9169bc8807f50fb75 100644 (file)
@@ -23,6 +23,7 @@
 #if defined(CONFIG_PPC_SPLPAR) || defined(CONFIG_PPC_ISERIES)
 #include <asm/hvcall.h>
 #include <asm/iseries/hv_call.h>
+#include <asm/smp.h>
 
 void __spin_yield(raw_spinlock_t *lock)
 {
index 841d8b6323a8da26699086273bb4560514bc85f8..93d4fbfdb724a137ee6ab385d880e79e80795f75 100644 (file)
@@ -389,5 +389,22 @@ void bad_page_fault(struct pt_regs *regs, unsigned long address, int sig)
        }
 
        /* kernel has accessed a bad area */
+
+       printk(KERN_ALERT "Unable to handle kernel paging request for ");
+       switch (regs->trap) {
+               case 0x300:
+               case 0x380:
+                       printk("data at address 0x%08lx\n", regs->dar);
+                       break;
+               case 0x400:
+               case 0x480:
+                       printk("instruction fetch\n");
+                       break;
+               default:
+                       printk("unknown fault\n");
+       }
+       printk(KERN_ALERT "Faulting instruction address: 0x%08lx\n",
+               regs->nip);
+
        die("Kernel access of bad area", regs, sig);
 }
index f15dfb92dec052d51f6c9212a8323ea2cf517945..22e474876133b334724d053a3e2434c06481acca 100644 (file)
@@ -33,7 +33,6 @@
 #include <linux/init.h>
 #include <linux/signal.h>
 
-#include <asm/ppcdebug.h>
 #include <asm/processor.h>
 #include <asm/pgtable.h>
 #include <asm/mmu.h>
@@ -409,12 +408,6 @@ void __init htab_initialize(void)
        htab_size_bytes = htab_get_table_size();
        pteg_count = htab_size_bytes >> 7;
 
-       /* For debug, make the HTAB 1/8 as big as it normally would be. */
-       ifppcdebug(PPCDBG_HTABSIZE) {
-               pteg_count >>= 3;
-               htab_size_bytes = pteg_count << 7;
-       }
-
        htab_hash_mask = pteg_count - 1;
 
        if (systemcfg->platform & PLATFORM_LPAR) {
@@ -514,6 +507,9 @@ unsigned int hash_page_do_lazy_icache(unsigned int pp, pte_t pte, int trap)
 {
        struct page *page;
 
+       if (!pfn_valid(pte_pfn(pte)))
+               return pp;
+
        page = pte_page(pte);
 
        /* page is dirty */
index dfe7fa37b41a16835b629964d2b21faefe2d97b9..ce974c83d88a6f1decd8341ccf92fbf253133c37 100644 (file)
@@ -57,7 +57,6 @@
 #include <asm/processor.h>
 #include <asm/mmzone.h>
 #include <asm/cputable.h>
-#include <asm/ppcdebug.h>
 #include <asm/sections.h>
 #include <asm/system.h>
 #include <asm/iommu.h>
index 7faa46b71f21ee2db7a6c4d783206c747cdaad8d..6f55efd9be957debe2c1522bda11ca50cb174a17 100644 (file)
@@ -358,7 +358,7 @@ void __init mem_init(void)
        }
 
        codesize = (unsigned long)&_sdata - (unsigned long)&_stext;
-       datasize = (unsigned long)&__init_begin - (unsigned long)&_sdata;
+       datasize = (unsigned long)&_edata - (unsigned long)&_sdata;
        initsize = (unsigned long)&__init_end - (unsigned long)&__init_begin;
        bsssize = (unsigned long)&__bss_stop - (unsigned long)&__bss_start;
 
index 4035cad8d7f19b84482d11f48ce067bb23e53133..da09ba03c424fb6b89ca06c795bbf2c646d5f734 100644 (file)
@@ -21,6 +21,7 @@
 #include <asm/machdep.h>
 #include <asm/abs_addr.h>
 #include <asm/system.h>
+#include <asm/smp.h>
 
 static int numa_enabled = 1;
 
index 51b7869409715d8ce9ebf51d31a89b4258460c55..900842451bd33a339676ffddfc540cc8e7f82646 100644 (file)
@@ -59,7 +59,6 @@
 #include <asm/processor.h>
 #include <asm/mmzone.h>
 #include <asm/cputable.h>
-#include <asm/ppcdebug.h>
 #include <asm/sections.h>
 #include <asm/system.h>
 #include <asm/iommu.h>
index 88644931584707ad11fde6282465221350e253d9..c4ee5478427b4ae322a8e1b4dd18f3600a23ce9a 100644 (file)
@@ -17,6 +17,7 @@
 #include <asm/systemcfg.h>
 #include <asm/rtas.h>
 #include <asm/oprofile_impl.h>
+#include <asm/reg.h>
 
 #define dbg(args...)
 
@@ -81,6 +82,26 @@ static void power4_reg_setup(struct op_counter_config *ctr,
 
 extern void ppc64_enable_pmcs(void);
 
+/*
+ * Older CPUs require the MMCRA sample bit to be always set, but newer 
+ * CPUs only want it set for some groups. Eventually we will remove all
+ * knowledge of this bit in the kernel, oprofile userspace should be
+ * setting it when required.
+ *
+ * In order to keep current installations working we force the bit for
+ * those older CPUs. Once everyone has updated their oprofile userspace we
+ * can remove this hack.
+ */
+static inline int mmcra_must_set_sample(void)
+{
+       if (__is_processor(PV_POWER4) || __is_processor(PV_POWER4p) ||
+           __is_processor(PV_970) || __is_processor(PV_970FX) ||
+           __is_processor(PV_970MP))
+               return 1;
+
+       return 0;
+}
+
 static void power4_cpu_setup(void *unused)
 {
        unsigned int mmcr0 = mmcr0_val;
@@ -98,7 +119,8 @@ static void power4_cpu_setup(void *unused)
 
        mtspr(SPRN_MMCR1, mmcr1_val);
 
-       mmcra |= MMCRA_SAMPLE_ENABLE;
+       if (mmcra_must_set_sample())
+               mmcra |= MMCRA_SAMPLE_ENABLE;
        mtspr(SPRN_MMCRA, mmcra);
 
        dbg("setup on cpu %d, mmcr0 %lx\n", smp_processor_id(),
index c1135912cc055c2df6139a64ebe346a67349c94b..a06603d84a451147d0cd646c40d18d9ef172bc94 100644 (file)
@@ -35,7 +35,6 @@
 #include <linux/irq.h>
 #include <linux/spinlock.h>
 
-#include <asm/ppcdebug.h>
 #include <asm/iseries/hv_types.h>
 #include <asm/iseries/hv_lp_event.h>
 #include <asm/iseries/hv_call_xm.h>
@@ -227,8 +226,6 @@ static void iSeries_enable_IRQ(unsigned int irq)
        /* Unmask secondary INTA */
        mask = 0x80000000;
        HvCallPci_unmaskInterrupts(bus, subBus, deviceId, mask);
-       PPCDBG(PPCDBG_BUSWALK, "iSeries_enable_IRQ 0x%02X.%02X.%02X 0x%04X\n",
-                       bus, subBus, deviceId, irq);
 }
 
 /* This is called by iSeries_activate_IRQs */
@@ -310,8 +307,6 @@ static void iSeries_disable_IRQ(unsigned int irq)
        /* Mask secondary INTA   */
        mask = 0x80000000;
        HvCallPci_maskInterrupts(bus, subBus, deviceId, mask);
-       PPCDBG(PPCDBG_BUSWALK, "iSeries_disable_IRQ 0x%02X.%02X.%02X 0x%04X\n",
-                       bus, subBus, deviceId, irq);
 }
 
 /*
index 7d7d5884343fa4a77a355601420a4cd681cf7aa2..4b75131773a698eef0ec7ff1ab38e5b3b9331b97 100644 (file)
@@ -32,7 +32,6 @@
 #include <asm/prom.h>
 #include <asm/machdep.h>
 #include <asm/pci-bridge.h>
-#include <asm/ppcdebug.h>
 #include <asm/iommu.h>
 #include <asm/abs_addr.h>
 
@@ -207,10 +206,6 @@ static struct device_node *build_device_node(HvBusNumber Bus,
        struct device_node *node;
        struct pci_dn *pdn;
 
-       PPCDBG(PPCDBG_BUSWALK,
-                       "-build_device_node 0x%02X.%02X.%02X Function: %02X\n",
-                       Bus, SubBus, AgentId, Function);
-
        node = kmalloc(sizeof(struct device_node), GFP_KERNEL);
        if (node == NULL)
                return NULL;
@@ -243,8 +238,6 @@ unsigned long __init find_and_init_phbs(void)
        struct pci_controller *phb;
        HvBusNumber bus;
 
-       PPCDBG(PPCDBG_BUSWALK, "find_and_init_phbs Entry\n");
-
        /* Check all possible buses. */
        for (bus = 0; bus < 256; bus++) {
                int ret = HvCallXm_testBus(bus);
@@ -261,9 +254,6 @@ unsigned long __init find_and_init_phbs(void)
                        phb->last_busno = bus;
                        phb->ops = &iSeries_pci_ops;
 
-                       PPCDBG(PPCDBG_BUSWALK, "PCI:Create iSeries pci_controller(%p), Bus: %04X\n",
-                                       phb, bus);
-
                        /* Find and connect the devices. */
                        scan_PHB_slots(phb);
                }
@@ -285,11 +275,9 @@ unsigned long __init find_and_init_phbs(void)
  */
 void iSeries_pcibios_init(void)
 {
-       PPCDBG(PPCDBG_BUSWALK, "iSeries_pcibios_init Entry.\n");
        iomm_table_initialize();
        find_and_init_phbs();
        io_page_mask = -1;
-       PPCDBG(PPCDBG_BUSWALK, "iSeries_pcibios_init Exit.\n");
 }
 
 /*
@@ -301,8 +289,6 @@ void __init iSeries_pci_final_fixup(void)
        struct device_node *node;
        int DeviceCount = 0;
 
-       PPCDBG(PPCDBG_BUSWALK, "iSeries_pcibios_fixup Entry.\n");
-
        /* Fix up at the device node and pci_dev relationship */
        mf_display_src(0xC9000100);
 
@@ -316,9 +302,6 @@ void __init iSeries_pci_final_fixup(void)
                        ++DeviceCount;
                        pdev->sysdata = (void *)node;
                        PCI_DN(node)->pcidev = pdev;
-                       PPCDBG(PPCDBG_BUSWALK,
-                                       "pdev 0x%p <==> DevNode 0x%p\n",
-                                       pdev, node);
                        allocate_device_bars(pdev);
                        iSeries_Device_Information(pdev, DeviceCount);
                        iommu_devnode_init_iSeries(node);
@@ -333,13 +316,10 @@ void __init iSeries_pci_final_fixup(void)
 
 void pcibios_fixup_bus(struct pci_bus *PciBus)
 {
-       PPCDBG(PPCDBG_BUSWALK, "iSeries_pcibios_fixup_bus(0x%04X) Entry.\n",
-                       PciBus->number);
 }
 
 void pcibios_fixup_resources(struct pci_dev *pdev)
 {
-       PPCDBG(PPCDBG_BUSWALK, "fixup_resources pdev %p\n", pdev);
 }
 
 /*
@@ -401,9 +381,6 @@ static void scan_EADS_bridge(HvBusNumber bus, HvSubBusNumber SubBus,
                        printk("found device at bus %d idsel %d func %d (AgentId %x)\n",
                               bus, IdSel, Function, AgentId);
                        /*  Connect EADs: 0x18.00.12 = 0x00 */
-                       PPCDBG(PPCDBG_BUSWALK,
-                                       "PCI:Connect EADs: 0x%02X.%02X.%02X\n",
-                                       bus, SubBus, AgentId);
                        HvRc = HvCallPci_getBusUnitInfo(bus, SubBus, AgentId,
                                        iseries_hv_addr(BridgeInfo),
                                        sizeof(struct HvCallPci_BridgeInfo));
@@ -414,14 +391,6 @@ static void scan_EADS_bridge(HvBusNumber bus, HvSubBusNumber SubBus,
                                        BridgeInfo->maxAgents,
                                        BridgeInfo->maxSubBusNumber,
                                        BridgeInfo->logicalSlotNumber);
-                               PPCDBG(PPCDBG_BUSWALK,
-                                       "PCI: BridgeInfo, Type:0x%02X, SubBus:0x%02X, MaxAgents:0x%02X, MaxSubBus: 0x%02X, LSlot: 0x%02X\n",
-                                       BridgeInfo->busUnitInfo.deviceType,
-                                       BridgeInfo->subBusNumber,
-                                       BridgeInfo->maxAgents,
-                                       BridgeInfo->maxSubBusNumber,
-                                       BridgeInfo->logicalSlotNumber);
-
                                if (BridgeInfo->busUnitInfo.deviceType ==
                                                HvCallPci_BridgeDevice)  {
                                        /* Scan_Bridge_Slot...: 0x18.00.12 */
@@ -454,9 +423,6 @@ static int scan_bridge_slot(HvBusNumber Bus,
 
        /* iSeries_allocate_IRQ.: 0x18.00.12(0xA3) */
        Irq = iSeries_allocate_IRQ(Bus, 0, EADsIdSel);
-       PPCDBG(PPCDBG_BUSWALK,
-               "PCI:- allocate and assign IRQ 0x%02X.%02X.%02X = 0x%02X\n",
-               Bus, 0, EADsIdSel, Irq);
 
        /*
         * Connect all functions of any device found.
@@ -482,9 +448,6 @@ static int scan_bridge_slot(HvBusNumber Bus,
                        printk("read vendor ID: %x\n", VendorId);
 
                        /* FoundDevice: 0x18.28.10 = 0x12AE */
-                       PPCDBG(PPCDBG_BUSWALK,
-                              "PCI:- FoundDevice: 0x%02X.%02X.%02X = 0x%04X, irq %d\n",
-                              Bus, SubBus, AgentId, VendorId, Irq);
                        HvRc = HvCallPci_configStore8(Bus, SubBus, AgentId,
                                                      PCI_INTERRUPT_LINE, Irq);
                        if (HvRc != 0)
index c5207064977db1ac3ae901b6f86762e1a1393fc6..7f8f0cda6a742ca7844c79259c6f5601c8d04b30 100644 (file)
@@ -71,8 +71,6 @@ extern void hvlog(char *fmt, ...);
 #endif
 
 /* Function Prototypes */
-extern void ppcdbg_initialize(void);
-
 static void build_iSeries_Memory_Map(void);
 static void iseries_shared_idle(void);
 static void iseries_dedicated_idle(void);
@@ -309,8 +307,6 @@ static void __init iSeries_init_early(void)
 
        ppc64_firmware_features = FW_FEATURE_ISERIES;
 
-       ppcdbg_initialize();
-
        ppc64_interrupt_controller = IC_ISERIES;
 
 #if defined(CONFIG_BLK_DEV_INITRD)
@@ -698,20 +694,19 @@ static void iseries_shared_idle(void)
                if (hvlpevent_is_pending())
                        process_iSeries_events();
 
+               preempt_enable_no_resched();
                schedule();
+               preempt_disable();
        }
 }
 
 static void iseries_dedicated_idle(void)
 {
        long oldval;
+       set_thread_flag(TIF_POLLING_NRFLAG);
 
        while (1) {
-               oldval = test_and_clear_thread_flag(TIF_NEED_RESCHED);
-
-               if (!oldval) {
-                       set_thread_flag(TIF_POLLING_NRFLAG);
-
+               if (!need_resched()) {
                        while (!need_resched()) {
                                ppc64_runlatch_off();
                                HMT_low();
@@ -724,13 +719,12 @@ static void iseries_dedicated_idle(void)
                        }
 
                        HMT_medium();
-                       clear_thread_flag(TIF_POLLING_NRFLAG);
-               } else {
-                       set_need_resched();
                }
 
                ppc64_runlatch_on();
+               preempt_enable_no_resched();
                schedule();
+               preempt_disable();
        }
 }
 
index 3336bad67724e0f6cb30ea775d9e3a6c00e1903b..fcb094ec6aec6efa082879088bf542399c43b23e 100644 (file)
@@ -40,7 +40,6 @@
 #include <asm/paca.h>
 #include <asm/iseries/hv_call.h>
 #include <asm/time.h>
-#include <asm/ppcdebug.h>
 #include <asm/machdep.h>
 #include <asm/cputable.h>
 #include <asm/system.h>
index 4369676f1d541d416665a4e1d165150ed7566f78..c9df44fcf5710f0ea558b39df6cb945efd090011 100644 (file)
@@ -1,7 +1,8 @@
 obj-y                          += pic.o setup.o time.o feature.o pci.o \
                                   sleep.o low_i2c.o cache.o
 obj-$(CONFIG_PMAC_BACKLIGHT)   += backlight.o
-obj-$(CONFIG_CPU_FREQ_PMAC)    += cpufreq.o
+obj-$(CONFIG_CPU_FREQ_PMAC)    += cpufreq_32.o
+obj-$(CONFIG_CPU_FREQ_PMAC64)  += cpufreq_64.o
 obj-$(CONFIG_NVRAM)            += nvram.o
 # ppc64 pmac doesn't define CONFIG_NVRAM but needs nvram stuff
 obj-$(CONFIG_PPC64)            += nvram.o
similarity index 99%
rename from arch/powerpc/platforms/powermac/cpufreq.c
rename to arch/powerpc/platforms/powermac/cpufreq_32.c
index c47f8b69725c63144935336b52eacda34d9531b9..56fd4e05fede95b68d05e91b075e91f2c2ab535b 100644 (file)
@@ -397,18 +397,16 @@ static int pmac_cpufreq_target(   struct cpufreq_policy *policy,
                                        unsigned int relation)
 {
        unsigned int    newstate = 0;
+       int             rc;
 
        if (cpufreq_frequency_table_target(policy, pmac_cpu_freqs,
                        target_freq, relation, &newstate))
                return -EINVAL;
 
-       return do_set_cpu_speed(newstate, 1);
-}
+       rc = do_set_cpu_speed(newstate, 1);
 
-unsigned int pmac_get_one_cpufreq(int i)
-{
-       /* Supports only one CPU for now */
-       return (i == 0) ? cur_freq : 0;
+       ppc_proc_freq = cur_freq * 1000ul;
+       return rc;
 }
 
 static int pmac_cpufreq_cpu_init(struct cpufreq_policy *policy)
@@ -474,6 +472,8 @@ static int pmac_cpufreq_resume(struct cpufreq_policy *policy)
        do_set_cpu_speed(sleep_freq == low_freq ?
                         CPUFREQ_LOW : CPUFREQ_HIGH, 0);
 
+       ppc_proc_freq = cur_freq * 1000ul;
+
        no_schedule = 0;
        return 0;
 }
@@ -547,7 +547,7 @@ static int pmac_cpufreq_init_MacRISC3(struct device_node *cpunode)
                 */
                if (low_freq < 98000000)
                        low_freq = 101000000;
-                       
+
                /* Convert those to CPU core clocks */
                low_freq = (low_freq * (*ratio)) / 2000;
                hi_freq = (hi_freq * (*ratio)) / 2000;
@@ -714,6 +714,7 @@ out:
 
        pmac_cpu_freqs[CPUFREQ_LOW].frequency = low_freq;
        pmac_cpu_freqs[CPUFREQ_HIGH].frequency = hi_freq;
+       ppc_proc_freq = cur_freq * 1000ul;
 
        printk(KERN_INFO "Registering PowerMac CPU frequency driver\n");
        printk(KERN_INFO "Low: %d Mhz, High: %d Mhz, Boot: %d Mhz\n",
diff --git a/arch/powerpc/platforms/powermac/cpufreq_64.c b/arch/powerpc/platforms/powermac/cpufreq_64.c
new file mode 100644 (file)
index 0000000..3915034
--- /dev/null
@@ -0,0 +1,323 @@
+/*
+ *  Copyright (C) 2002 - 2005 Benjamin Herrenschmidt <benh@kernel.crashing.org>
+ *  and                       Markus Demleitner <msdemlei@cl.uni-heidelberg.de>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This driver adds basic cpufreq support for SMU & 970FX based G5 Macs,
+ * that is iMac G5 and latest single CPU desktop.
+ */
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/errno.h>
+#include <linux/kernel.h>
+#include <linux/delay.h>
+#include <linux/sched.h>
+#include <linux/slab.h>
+#include <linux/cpufreq.h>
+#include <linux/init.h>
+#include <linux/completion.h>
+#include <asm/prom.h>
+#include <asm/machdep.h>
+#include <asm/irq.h>
+#include <asm/sections.h>
+#include <asm/cputable.h>
+#include <asm/time.h>
+#include <asm/smu.h>
+
+#undef DEBUG
+
+#ifdef DEBUG
+#define DBG(fmt...) printk(fmt)
+#else
+#define DBG(fmt...)
+#endif
+
+/* see 970FX user manual */
+
+#define SCOM_PCR 0x0aa001                      /* PCR scom addr */
+
+#define PCR_HILO_SELECT                0x80000000U     /* 1 = PCR, 0 = PCRH */
+#define PCR_SPEED_FULL         0x00000000U     /* 1:1 speed value */
+#define PCR_SPEED_HALF         0x00020000U     /* 1:2 speed value */
+#define PCR_SPEED_QUARTER      0x00040000U     /* 1:4 speed value */
+#define PCR_SPEED_MASK         0x000e0000U     /* speed mask */
+#define PCR_SPEED_SHIFT                17
+#define PCR_FREQ_REQ_VALID     0x00010000U     /* freq request valid */
+#define PCR_VOLT_REQ_VALID     0x00008000U     /* volt request valid */
+#define PCR_TARGET_TIME_MASK   0x00006000U     /* target time */
+#define PCR_STATLAT_MASK       0x00001f00U     /* STATLAT value */
+#define PCR_SNOOPLAT_MASK      0x000000f0U     /* SNOOPLAT value */
+#define PCR_SNOOPACC_MASK      0x0000000fU     /* SNOOPACC value */
+
+#define SCOM_PSR 0x408001                      /* PSR scom addr */
+/* warning: PSR is a 64 bits register */
+#define PSR_CMD_RECEIVED       0x2000000000000000U   /* command received */
+#define PSR_CMD_COMPLETED      0x1000000000000000U   /* command completed */
+#define PSR_CUR_SPEED_MASK     0x0300000000000000U   /* current speed */
+#define PSR_CUR_SPEED_SHIFT    (56)
+
+/*
+ * The G5 only supports two frequencies (Quarter speed is not supported)
+ */
+#define CPUFREQ_HIGH                  0
+#define CPUFREQ_LOW                   1
+
+static struct cpufreq_frequency_table g5_cpu_freqs[] = {
+       {CPUFREQ_HIGH,          0},
+       {CPUFREQ_LOW,           0},
+       {0,                     CPUFREQ_TABLE_END},
+};
+
+static struct freq_attr* g5_cpu_freqs_attr[] = {
+       &cpufreq_freq_attr_scaling_available_freqs,
+       NULL,
+};
+
+/* Power mode data is an array of the 32 bits PCR values to use for
+ * the various frequencies, retreived from the device-tree
+ */
+static u32 *g5_pmode_data;
+static int g5_pmode_max;
+static int g5_pmode_cur;
+
+static DECLARE_MUTEX(g5_switch_mutex);
+
+
+static struct smu_sdbp_fvt *g5_fvt_table;      /* table of op. points */
+static int g5_fvt_count;                       /* number of op. points */
+static int g5_fvt_cur;                         /* current op. point */
+
+/* ----------------- real hardware interface */
+
+static void g5_switch_volt(int speed_mode)
+{
+       struct smu_simple_cmd   cmd;
+
+       DECLARE_COMPLETION(comp);
+       smu_queue_simple(&cmd, SMU_CMD_POWER_COMMAND, 8, smu_done_complete,
+                        &comp, 'V', 'S', 'L', 'E', 'W',
+                        0xff, g5_fvt_cur+1, speed_mode);
+       wait_for_completion(&comp);
+}
+
+static int g5_switch_freq(int speed_mode)
+{
+       struct cpufreq_freqs freqs;
+       int to;
+
+       if (g5_pmode_cur == speed_mode)
+               return 0;
+
+       down(&g5_switch_mutex);
+
+       freqs.old = g5_cpu_freqs[g5_pmode_cur].frequency;
+       freqs.new = g5_cpu_freqs[speed_mode].frequency;
+       freqs.cpu = 0;
+
+       cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE);
+
+       /* If frequency is going up, first ramp up the voltage */
+       if (speed_mode < g5_pmode_cur)
+               g5_switch_volt(speed_mode);
+
+       /* Clear PCR high */
+       scom970_write(SCOM_PCR, 0);
+       /* Clear PCR low */
+               scom970_write(SCOM_PCR, PCR_HILO_SELECT | 0);
+       /* Set PCR low */
+       scom970_write(SCOM_PCR, PCR_HILO_SELECT |
+                     g5_pmode_data[speed_mode]);
+
+       /* Wait for completion */
+       for (to = 0; to < 10; to++) {
+               unsigned long psr = scom970_read(SCOM_PSR);
+
+               if ((psr & PSR_CMD_RECEIVED) == 0 &&
+                   (((psr >> PSR_CUR_SPEED_SHIFT) ^
+                     (g5_pmode_data[speed_mode] >> PCR_SPEED_SHIFT)) & 0x3)
+                   == 0)
+                       break;
+               if (psr & PSR_CMD_COMPLETED)
+                       break;
+               udelay(100);
+       }
+
+       /* If frequency is going down, last ramp the voltage */
+       if (speed_mode > g5_pmode_cur)
+               g5_switch_volt(speed_mode);
+
+       g5_pmode_cur = speed_mode;
+       ppc_proc_freq = g5_cpu_freqs[speed_mode].frequency * 1000ul;
+
+       cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE);
+
+       up(&g5_switch_mutex);
+
+       return 0;
+}
+
+static int g5_query_freq(void)
+{
+       unsigned long psr = scom970_read(SCOM_PSR);
+       int i;
+
+       for (i = 0; i <= g5_pmode_max; i++)
+               if ((((psr >> PSR_CUR_SPEED_SHIFT) ^
+                     (g5_pmode_data[i] >> PCR_SPEED_SHIFT)) & 0x3) == 0)
+                       break;
+       return i;
+}
+
+/* ----------------- cpufreq bookkeeping */
+
+static int g5_cpufreq_verify(struct cpufreq_policy *policy)
+{
+       return cpufreq_frequency_table_verify(policy, g5_cpu_freqs);
+}
+
+static int g5_cpufreq_target(struct cpufreq_policy *policy,
+       unsigned int target_freq, unsigned int relation)
+{
+       unsigned int    newstate = 0;
+
+       if (cpufreq_frequency_table_target(policy, g5_cpu_freqs,
+                       target_freq, relation, &newstate))
+               return -EINVAL;
+
+       return g5_switch_freq(newstate);
+}
+
+static unsigned int g5_cpufreq_get_speed(unsigned int cpu)
+{
+       return g5_cpu_freqs[g5_pmode_cur].frequency;
+}
+
+static int g5_cpufreq_cpu_init(struct cpufreq_policy *policy)
+{
+       if (policy->cpu != 0)
+               return -ENODEV;
+
+       policy->governor = CPUFREQ_DEFAULT_GOVERNOR;
+       policy->cpuinfo.transition_latency = CPUFREQ_ETERNAL;
+       policy->cur = g5_cpu_freqs[g5_query_freq()].frequency;
+       cpufreq_frequency_table_get_attr(g5_cpu_freqs, policy->cpu);
+
+       return cpufreq_frequency_table_cpuinfo(policy,
+               g5_cpu_freqs);
+}
+
+
+static struct cpufreq_driver g5_cpufreq_driver = {
+       .name           = "powermac",
+       .owner          = THIS_MODULE,
+       .flags          = CPUFREQ_CONST_LOOPS,
+       .init           = g5_cpufreq_cpu_init,
+       .verify         = g5_cpufreq_verify,
+       .target         = g5_cpufreq_target,
+       .get            = g5_cpufreq_get_speed,
+       .attr           = g5_cpu_freqs_attr,
+};
+
+
+static int __init g5_cpufreq_init(void)
+{
+       struct device_node *cpunode;
+       unsigned int psize, ssize;
+       struct smu_sdbp_header *shdr;
+       unsigned long max_freq;
+       u32 *valp;
+       int rc = -ENODEV;
+
+       /* Look for CPU and SMU nodes */
+       cpunode = of_find_node_by_type(NULL, "cpu");
+       if (!cpunode) {
+               DBG("No CPU node !\n");
+               return -ENODEV;
+       }
+
+       /* Check 970FX for now */
+       valp = (u32 *)get_property(cpunode, "cpu-version", NULL);
+       if (!valp) {
+               DBG("No cpu-version property !\n");
+               goto bail_noprops;
+       }
+       if (((*valp) >> 16) != 0x3c) {
+               DBG("Wrong CPU version: %08x\n", *valp);
+               goto bail_noprops;
+       }
+
+       /* Look for the powertune data in the device-tree */
+       g5_pmode_data = (u32 *)get_property(cpunode, "power-mode-data",&psize);
+       if (!g5_pmode_data) {
+               DBG("No power-mode-data !\n");
+               goto bail_noprops;
+       }
+       g5_pmode_max = psize / sizeof(u32) - 1;
+
+       /* Look for the FVT table */
+       shdr = smu_get_sdb_partition(SMU_SDB_FVT_ID, NULL);
+       if (!shdr)
+               goto bail_noprops;
+       g5_fvt_table = (struct smu_sdbp_fvt *)&shdr[1];
+       ssize = (shdr->len * sizeof(u32)) - sizeof(struct smu_sdbp_header);
+       g5_fvt_count = ssize / sizeof(struct smu_sdbp_fvt);
+       g5_fvt_cur = 0;
+
+       /* Sanity checking */
+       if (g5_fvt_count < 1 || g5_pmode_max < 1)
+               goto bail_noprops;
+
+       /*
+        * From what I see, clock-frequency is always the maximal frequency.
+        * The current driver can not slew sysclk yet, so we really only deal
+        * with powertune steps for now. We also only implement full freq and
+        * half freq in this version. So far, I haven't yet seen a machine
+        * supporting anything else.
+        */
+       valp = (u32 *)get_property(cpunode, "clock-frequency", NULL);
+       if (!valp)
+               return -ENODEV;
+       max_freq = (*valp)/1000;
+       g5_cpu_freqs[0].frequency = max_freq;
+       g5_cpu_freqs[1].frequency = max_freq/2;
+
+       /* Check current frequency */
+       g5_pmode_cur = g5_query_freq();
+       if (g5_pmode_cur > 1)
+               /* We don't support anything but 1:1 and 1:2, fixup ... */
+               g5_pmode_cur = 1;
+
+       /* Force apply current frequency to make sure everything is in
+        * sync (voltage is right for example). Firmware may leave us with
+        * a strange setting ...
+        */
+       g5_switch_freq(g5_pmode_cur);
+
+       printk(KERN_INFO "Registering G5 CPU frequency driver\n");
+       printk(KERN_INFO "Low: %d Mhz, High: %d Mhz, Cur: %d MHz\n",
+               g5_cpu_freqs[1].frequency/1000,
+               g5_cpu_freqs[0].frequency/1000,
+               g5_cpu_freqs[g5_pmode_cur].frequency/1000);
+
+       rc = cpufreq_register_driver(&g5_cpufreq_driver);
+
+       /* We keep the CPU node on hold... hopefully, Apple G5 don't have
+        * hotplug CPU with a dynamic device-tree ...
+        */
+       return rc;
+
+ bail_noprops:
+       of_node_put(cpunode);
+
+       return rc;
+}
+
+module_init(g5_cpufreq_init);
+
+
+MODULE_LICENSE("GPL");
index 80b58c1ec4120d8b43de70f081d77c2955d56a11..7acb0546671fe2ea341c604573e541bd8d06cad9 100644 (file)
@@ -193,18 +193,6 @@ static void pmac_show_cpuinfo(struct seq_file *m)
                   pmac_newworld ? "NewWorld" : "OldWorld");
 }
 
-static void pmac_show_percpuinfo(struct seq_file *m, int i)
-{
-#ifdef CONFIG_CPU_FREQ_PMAC
-       extern unsigned int pmac_get_one_cpufreq(int i);
-       unsigned int freq = pmac_get_one_cpufreq(i);
-       if (freq != 0) {
-               seq_printf(m, "clock\t\t: %dMHz\n", freq/1000);
-               return;
-       }
-#endif /* CONFIG_CPU_FREQ_PMAC */
-}
-
 #ifndef CONFIG_ADB_CUDA
 int find_via_cuda(void)
 {
@@ -767,7 +755,6 @@ struct machdep_calls __initdata pmac_md = {
        .setup_arch             = pmac_setup_arch,
        .init_early             = pmac_init_early,
        .show_cpuinfo           = pmac_show_cpuinfo,
-       .show_percpuinfo        = pmac_show_percpuinfo,
        .init_IRQ               = pmac_pic_init,
        .get_irq                = mpic_get_irq, /* changed later */
        .pcibios_fixup          = pmac_pcibios_fixup,
index 513e2723149358c4ff06ed556c449ecc6248be2e..fcc50bfd43fd35d560175b89917bbc51d4c56cfb 100644 (file)
@@ -37,7 +37,6 @@
 #include <asm/io.h>
 #include <asm/prom.h>
 #include <asm/rtas.h>
-#include <asm/ppcdebug.h>
 #include <asm/iommu.h>
 #include <asm/pci-bridge.h>
 #include <asm/machdep.h>
@@ -47,6 +46,7 @@
 #include <asm/firmware.h>
 #include <asm/tce.h>
 #include <asm/ppc-pci.h>
+#include <asm/udbg.h>
 
 #include "plpar_wrappers.h"
 
index ab0c6dd6ec94538beaab0c12e3b9254d224222fe..a50e5f3f396dc177da02deea3cbad714d01be4ce 100644 (file)
 #include <asm/machdep.h>
 #include <asm/abs_addr.h>
 #include <asm/mmu_context.h>
-#include <asm/ppcdebug.h>
 #include <asm/iommu.h>
 #include <asm/tlbflush.h>
 #include <asm/tlb.h>
 #include <asm/prom.h>
 #include <asm/abs_addr.h>
 #include <asm/cputable.h>
+#include <asm/udbg.h>
+#include <asm/smp.h>
 
 #include "plpar_wrappers.h"
 
index 382f8c5b0e7c0978892cf5f9a873ab9754477a25..3bd1b3e0600362237c410bbb7f008a67ddd68862 100644 (file)
@@ -107,14 +107,4 @@ static inline long plpar_put_term_char(unsigned long termno, unsigned long len,
                        lbuf[1]);
 }
 
-static inline long plpar_set_xdabr(unsigned long address, unsigned long flags)
-{
-       return plpar_hcall_norets(H_SET_XDABR, address, flags);
-}
-
-static inline long plpar_set_dabr(unsigned long val)
-{
-       return plpar_hcall_norets(H_SET_DABR, val);
-}
-
 #endif /* _PSERIES_PLPAR_WRAPPERS_H */
index 6562ff4b0a8210375270b37b70307ae1a94068a1..fbd214d68b0717573ed443632bde26d055038345 100644 (file)
@@ -48,7 +48,7 @@
 #include <asm/ptrace.h>
 #include <asm/machdep.h>
 #include <asm/rtas.h>
-#include <asm/ppcdebug.h>
+#include <asm/udbg.h>
 
 static unsigned char ras_log_buf[RTAS_ERROR_LOG_MAX];
 static DEFINE_SPINLOCK(ras_log_buf_lock);
index 65bee939eeccce1d5e626f985eee080af08c9c63..a093a0d4dd69d15c03f7379521e7e54dae6b1f94 100644 (file)
@@ -65,6 +65,7 @@
 #include <asm/ppc-pci.h>
 #include <asm/i8259.h>
 #include <asm/udbg.h>
+#include <asm/smp.h>
 
 #include "plpar_wrappers.h"
 
@@ -353,14 +354,15 @@ static void pSeries_mach_cpu_die(void)
 
 static int pseries_set_dabr(unsigned long dabr)
 {
-       if (firmware_has_feature(FW_FEATURE_XDABR)) {
-               /* We want to catch accesses from kernel and userspace */
-               return plpar_set_xdabr(dabr, H_DABRX_KERNEL | H_DABRX_USER);
-       }
-
-       return plpar_set_dabr(dabr);
+       return plpar_hcall_norets(H_SET_DABR, dabr);
 }
 
+static int pseries_set_xdabr(unsigned long dabr)
+{
+       /* We want to catch accesses from kernel and userspace */
+       return plpar_hcall_norets(H_SET_XDABR, dabr,
+                       H_DABRX_KERNEL | H_DABRX_USER);
+}
 
 /*
  * Early initialization.  Relocation is on but do not reference unbolted pages
@@ -396,8 +398,10 @@ static void __init pSeries_init_early(void)
                DBG("Hello World !\n");
        }
 
-       if (firmware_has_feature(FW_FEATURE_XDABR | FW_FEATURE_DABR))
+       if (firmware_has_feature(FW_FEATURE_DABR))
                ppc_md.set_dabr = pseries_set_dabr;
+       else if (firmware_has_feature(FW_FEATURE_XDABR))
+               ppc_md.set_dabr = pseries_set_xdabr;
 
        iommu_init_early_pSeries();
 
@@ -465,6 +469,7 @@ static inline void dedicated_idle_sleep(unsigned int cpu)
                 * more.
                 */
                clear_thread_flag(TIF_POLLING_NRFLAG);
+               smp_mb__after_clear_bit();
 
                /*
                 * SMT dynamic mode. Cede will result in this thread going
@@ -477,6 +482,7 @@ static inline void dedicated_idle_sleep(unsigned int cpu)
                        cede_processor();
                else
                        local_irq_enable();
+               set_thread_flag(TIF_POLLING_NRFLAG);
        } else {
                /*
                 * Give the HV an opportunity at the processor, since we are
@@ -488,11 +494,11 @@ static inline void dedicated_idle_sleep(unsigned int cpu)
 
 static void pseries_dedicated_idle(void)
 { 
-       long oldval;
        struct paca_struct *lpaca = get_paca();
        unsigned int cpu = smp_processor_id();
        unsigned long start_snooze;
        unsigned long *smt_snooze_delay = &__get_cpu_var(smt_snooze_delay);
+       set_thread_flag(TIF_POLLING_NRFLAG);
 
        while (1) {
                /*
@@ -501,10 +507,7 @@ static void pseries_dedicated_idle(void)
                 */
                lpaca->lppaca.idle = 1;
 
-               oldval = test_and_clear_thread_flag(TIF_NEED_RESCHED);
-               if (!oldval) {
-                       set_thread_flag(TIF_POLLING_NRFLAG);
-
+               if (!need_resched()) {
                        start_snooze = __get_tb() +
                                *smt_snooze_delay * tb_ticks_per_usec;
 
@@ -527,15 +530,14 @@ static void pseries_dedicated_idle(void)
                        }
 
                        HMT_medium();
-                       clear_thread_flag(TIF_POLLING_NRFLAG);
-               } else {
-                       set_need_resched();
                }
 
                lpaca->lppaca.idle = 0;
                ppc64_runlatch_on();
 
+               preempt_enable_no_resched();
                schedule();
+               preempt_disable();
 
                if (cpu_is_offline(cpu) && system_state == SYSTEM_RUNNING)
                        cpu_die();
@@ -579,7 +581,9 @@ static void pseries_shared_idle(void)
                lpaca->lppaca.idle = 0;
                ppc64_runlatch_on();
 
+               preempt_enable_no_resched();
                schedule();
+               preempt_disable();
 
                if (cpu_is_offline(cpu) && system_state == SYSTEM_RUNNING)
                        cpu_die();
index 90bce6e0c191827e6a91a6ae91d762eee4094633..b7ac32fdd7766f74ceff0d2098df4614eae83701 100644 (file)
@@ -207,6 +207,9 @@ void __init i8259_init(unsigned long intack_addr, int offset)
 
        spin_unlock_irqrestore(&i8259_lock, flags);
 
+       for (i = 0; i < NUM_ISA_INTERRUPTS; ++i)
+               irq_desc[offset + i].handler = &i8259_pic;
+
        /* reserve our resources */
        setup_irq(offset + 2, &i8259_irqaction);
        request_resource(&ioport_resource, &pic1_iores);
@@ -216,6 +219,4 @@ void __init i8259_init(unsigned long intack_addr, int offset)
        if (intack_addr != 0)
                pci_intack = ioremap(intack_addr, 1);
 
-       for (i = 0; i < NUM_ISA_INTERRUPTS; ++i)
-               irq_desc[offset + i].handler = &i8259_pic;
 }
index 607722178c1a6695616c528c0511e8f22e23d41f..543d6590981248ff1ebdff05822c36aaeefe9ca0 100644 (file)
@@ -37,7 +37,6 @@
 #include <linux/vmalloc.h>
 #include <asm/io.h>
 #include <asm/prom.h>
-#include <asm/ppcdebug.h>
 #include <asm/iommu.h>
 #include <asm/pci-bridge.h>
 #include <asm/machdep.h>
index 4a5522ca8207e439f6e1adfc06ccba4b522a1f72..673dc64ebcb1df1804480245db281c7215a836c0 100644 (file)
@@ -1,16 +1,17 @@
 #
 # Automatically generated make config: don't edit
-# Linux kernel version: 2.6.11-rc4
-# Thu Feb 17 16:12:23 2005
+# Linux kernel version: 2.6.14
+# Mon Nov  7 15:38:29 2005
 #
 CONFIG_MMU=y
 CONFIG_GENERIC_HARDIRQS=y
 CONFIG_RWSEM_XCHGADD_ALGORITHM=y
 CONFIG_GENERIC_CALIBRATE_DELAY=y
-CONFIG_HAVE_DEC_LOCK=y
 CONFIG_PPC=y
 CONFIG_PPC32=y
 CONFIG_GENERIC_NVRAM=y
+CONFIG_SCHED_NO_NO_OMIT_FRAME_POINTER=y
+CONFIG_ARCH_MAY_HAVE_PC_FDC=y
 
 #
 # Code maturity level options
@@ -18,23 +19,28 @@ CONFIG_GENERIC_NVRAM=y
 CONFIG_EXPERIMENTAL=y
 CONFIG_CLEAN_COMPILE=y
 CONFIG_BROKEN_ON_SMP=y
+CONFIG_INIT_ENV_ARG_LIMIT=32
 
 #
 # General setup
 #
 CONFIG_LOCALVERSION=""
+CONFIG_LOCALVERSION_AUTO=y
 CONFIG_SWAP=y
 CONFIG_SYSVIPC=y
 # CONFIG_POSIX_MQUEUE is not set
 # CONFIG_BSD_PROCESS_ACCT is not set
 CONFIG_SYSCTL=y
 # CONFIG_AUDIT is not set
-CONFIG_LOG_BUF_SHIFT=14
 # CONFIG_HOTPLUG is not set
 CONFIG_KOBJECT_UEVENT=y
 # CONFIG_IKCONFIG is not set
+CONFIG_INITRAMFS_SOURCE=""
 CONFIG_EMBEDDED=y
 # CONFIG_KALLSYMS is not set
+CONFIG_PRINTK=y
+CONFIG_BUG=y
+CONFIG_BASE_FULL=y
 CONFIG_FUTEX=y
 # CONFIG_EPOLL is not set
 # CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
@@ -44,6 +50,7 @@ CONFIG_CC_ALIGN_LABELS=0
 CONFIG_CC_ALIGN_LOOPS=0
 CONFIG_CC_ALIGN_JUMPS=0
 # CONFIG_TINY_SHMEM is not set
+CONFIG_BASE_SMALL=0
 
 #
 # Loadable module support
@@ -59,44 +66,90 @@ CONFIG_6xx=y
 # CONFIG_POWER3 is not set
 # CONFIG_POWER4 is not set
 # CONFIG_8xx is not set
+# CONFIG_E200 is not set
 # CONFIG_E500 is not set
+CONFIG_PPC_FPU=y
+# CONFIG_KEXEC is not set
 # CONFIG_CPU_FREQ is not set
+# CONFIG_WANT_EARLY_SERIAL is not set
 CONFIG_PPC_GEN550=y
-CONFIG_83xx=y
-
-#
-# Freescale 83xx options
-#
-CONFIG_MPC834x_SYS=y
-CONFIG_MPC834x=y
 CONFIG_PPC_STD_MMU=y
 
 #
 # Platform options
 #
+# CONFIG_PPC_MULTIPLATFORM is not set
+# CONFIG_APUS is not set
+# CONFIG_KATANA is not set
+# CONFIG_WILLOW is not set
+# CONFIG_CPCI690 is not set
+# CONFIG_POWERPMC250 is not set
+# CONFIG_CHESTNUT is not set
+# CONFIG_SPRUCE is not set
+# CONFIG_HDPU is not set
+# CONFIG_EV64260 is not set
+# CONFIG_LOPEC is not set
+# CONFIG_MVME5100 is not set
+# CONFIG_PPLUS is not set
+# CONFIG_PRPMC750 is not set
+# CONFIG_PRPMC800 is not set
+# CONFIG_SANDPOINT is not set
+# CONFIG_RADSTONE_PPC7D is not set
+# CONFIG_PAL4 is not set
+# CONFIG_GEMINI is not set
+# CONFIG_EST8260 is not set
+# CONFIG_SBC82xx is not set
+# CONFIG_SBS8260 is not set
+# CONFIG_RPX8260 is not set
+# CONFIG_TQM8260 is not set
+# CONFIG_ADS8272 is not set
+# CONFIG_PQ2FADS is not set
+# CONFIG_LITE5200 is not set
+CONFIG_MPC834x_SYS=y
+# CONFIG_EV64360 is not set
+CONFIG_83xx=y
+CONFIG_MPC834x=y
 # CONFIG_SMP is not set
-# CONFIG_PREEMPT is not set
 # CONFIG_HIGHMEM is not set
+# CONFIG_HZ_100 is not set
+CONFIG_HZ_250=y
+# CONFIG_HZ_1000 is not set
+CONFIG_HZ=250
+CONFIG_PREEMPT_NONE=y
+# CONFIG_PREEMPT_VOLUNTARY is not set
+# CONFIG_PREEMPT is not set
+CONFIG_SELECT_MEMORY_MODEL=y
+CONFIG_FLATMEM_MANUAL=y
+# CONFIG_DISCONTIGMEM_MANUAL is not set
+# CONFIG_SPARSEMEM_MANUAL is not set
+CONFIG_FLATMEM=y
+CONFIG_FLAT_NODE_MEM_MAP=y
+# CONFIG_SPARSEMEM_STATIC is not set
+CONFIG_SPLIT_PTLOCK_CPUS=4
 CONFIG_BINFMT_ELF=y
 # CONFIG_BINFMT_MISC is not set
 # CONFIG_CMDLINE_BOOL is not set
+# CONFIG_PM is not set
+# CONFIG_SOFTWARE_SUSPEND is not set
+CONFIG_SECCOMP=y
+CONFIG_ISA_DMA_API=y
 
 #
 # Bus options
 #
 CONFIG_GENERIC_ISA_DMA=y
-# CONFIG_PCI is not set
-# CONFIG_PCI_DOMAINS is not set
+# CONFIG_PPC_I8259 is not set
+CONFIG_PPC_INDIRECT_PCI=y
+CONFIG_PCI=y
+CONFIG_PCI_DOMAINS=y
+# CONFIG_MPC83xx_PCI2 is not set
+CONFIG_PCI_LEGACY_PROC=y
 
 #
 # PCCARD (PCMCIA/CardBus) support
 #
 # CONFIG_PCCARD is not set
 
-#
-# PC-card bridges
-#
-
 #
 # Advanced setup
 #
@@ -111,6 +164,75 @@ CONFIG_KERNEL_START=0xc0000000
 CONFIG_TASK_SIZE=0x80000000
 CONFIG_BOOT_LOAD=0x00800000
 
+#
+# Networking
+#
+CONFIG_NET=y
+
+#
+# Networking options
+#
+CONFIG_PACKET=y
+# CONFIG_PACKET_MMAP is not set
+CONFIG_UNIX=y
+# CONFIG_NET_KEY is not set
+CONFIG_INET=y
+CONFIG_IP_MULTICAST=y
+# CONFIG_IP_ADVANCED_ROUTER is not set
+CONFIG_IP_FIB_HASH=y
+CONFIG_IP_PNP=y
+CONFIG_IP_PNP_DHCP=y
+CONFIG_IP_PNP_BOOTP=y
+# CONFIG_IP_PNP_RARP is not set
+# CONFIG_NET_IPIP is not set
+# CONFIG_NET_IPGRE is not set
+# CONFIG_IP_MROUTE is not set
+# CONFIG_ARPD is not set
+CONFIG_SYN_COOKIES=y
+# CONFIG_INET_AH is not set
+# CONFIG_INET_ESP is not set
+# CONFIG_INET_IPCOMP is not set
+# CONFIG_INET_TUNNEL is not set
+CONFIG_INET_DIAG=y
+CONFIG_INET_TCP_DIAG=y
+# CONFIG_TCP_CONG_ADVANCED is not set
+CONFIG_TCP_CONG_BIC=y
+# CONFIG_IPV6 is not set
+# CONFIG_NETFILTER is not set
+
+#
+# DCCP Configuration (EXPERIMENTAL)
+#
+# CONFIG_IP_DCCP is not set
+
+#
+# SCTP Configuration (EXPERIMENTAL)
+#
+# CONFIG_IP_SCTP is not set
+# CONFIG_ATM is not set
+# CONFIG_BRIDGE is not set
+# CONFIG_VLAN_8021Q is not set
+# CONFIG_DECNET is not set
+# CONFIG_LLC2 is not set
+# CONFIG_IPX is not set
+# CONFIG_ATALK is not set
+# CONFIG_X25 is not set
+# CONFIG_LAPB is not set
+# CONFIG_NET_DIVERT is not set
+# CONFIG_ECONET is not set
+# CONFIG_WAN_ROUTER is not set
+# CONFIG_NET_SCHED is not set
+# CONFIG_NET_CLS_ROUTE is not set
+
+#
+# Network testing
+#
+# CONFIG_NET_PKTGEN is not set
+# CONFIG_HAMRADIO is not set
+# CONFIG_IRDA is not set
+# CONFIG_BT is not set
+# CONFIG_IEEE80211 is not set
+
 #
 # Device Drivers
 #
@@ -122,6 +244,11 @@ CONFIG_STANDALONE=y
 CONFIG_PREVENT_FIRMWARE_BUILD=y
 # CONFIG_FW_LOADER is not set
 
+#
+# Connector - unified userspace <-> kernelspace linker
+#
+# CONFIG_CONNECTOR is not set
+
 #
 # Memory Technology Devices (MTD)
 #
@@ -140,15 +267,19 @@ CONFIG_PREVENT_FIRMWARE_BUILD=y
 # Block devices
 #
 # CONFIG_BLK_DEV_FD is not set
+# CONFIG_BLK_CPQ_DA is not set
+# CONFIG_BLK_CPQ_CISS_DA is not set
+# CONFIG_BLK_DEV_DAC960 is not set
+# CONFIG_BLK_DEV_UMEM is not set
 # CONFIG_BLK_DEV_COW_COMMON is not set
 CONFIG_BLK_DEV_LOOP=y
 # CONFIG_BLK_DEV_CRYPTOLOOP is not set
 # CONFIG_BLK_DEV_NBD is not set
+# CONFIG_BLK_DEV_SX8 is not set
 CONFIG_BLK_DEV_RAM=y
 CONFIG_BLK_DEV_RAM_COUNT=16
 CONFIG_BLK_DEV_RAM_SIZE=32768
 CONFIG_BLK_DEV_INITRD=y
-CONFIG_INITRAMFS_SOURCE=""
 # CONFIG_LBD is not set
 # CONFIG_CDROM_PKTCDVD is not set
 
@@ -159,6 +290,11 @@ CONFIG_IOSCHED_NOOP=y
 CONFIG_IOSCHED_AS=y
 CONFIG_IOSCHED_DEADLINE=y
 CONFIG_IOSCHED_CFQ=y
+CONFIG_DEFAULT_AS=y
+# CONFIG_DEFAULT_DEADLINE is not set
+# CONFIG_DEFAULT_CFQ is not set
+# CONFIG_DEFAULT_NOOP is not set
+CONFIG_DEFAULT_IOSCHED="anticipatory"
 # CONFIG_ATA_OVER_ETH is not set
 
 #
@@ -169,6 +305,7 @@ CONFIG_IOSCHED_CFQ=y
 #
 # SCSI device support
 #
+# CONFIG_RAID_ATTRS is not set
 # CONFIG_SCSI is not set
 
 #
@@ -179,110 +316,116 @@ CONFIG_IOSCHED_CFQ=y
 #
 # Fusion MPT device support
 #
+# CONFIG_FUSION is not set
 
 #
 # IEEE 1394 (FireWire) support
 #
+# CONFIG_IEEE1394 is not set
 
 #
 # I2O device support
 #
+# CONFIG_I2O is not set
 
 #
 # Macintosh device drivers
 #
 
 #
-# Networking support
+# Network device support
 #
-CONFIG_NET=y
-
-#
-# Networking options
-#
-CONFIG_PACKET=y
-# CONFIG_PACKET_MMAP is not set
-# CONFIG_NETLINK_DEV is not set
-CONFIG_UNIX=y
-# CONFIG_NET_KEY is not set
-CONFIG_INET=y
-CONFIG_IP_MULTICAST=y
-# CONFIG_IP_ADVANCED_ROUTER is not set
-CONFIG_IP_PNP=y
-CONFIG_IP_PNP_DHCP=y
-CONFIG_IP_PNP_BOOTP=y
-# CONFIG_IP_PNP_RARP is not set
-# CONFIG_NET_IPIP is not set
-# CONFIG_NET_IPGRE is not set
-# CONFIG_IP_MROUTE is not set
-# CONFIG_ARPD is not set
-CONFIG_SYN_COOKIES=y
-# CONFIG_INET_AH is not set
-# CONFIG_INET_ESP is not set
-# CONFIG_INET_IPCOMP is not set
-# CONFIG_INET_TUNNEL is not set
-CONFIG_IP_TCPDIAG=y
-# CONFIG_IP_TCPDIAG_IPV6 is not set
-# CONFIG_IPV6 is not set
-# CONFIG_NETFILTER is not set
+CONFIG_NETDEVICES=y
+# CONFIG_DUMMY is not set
+# CONFIG_BONDING is not set
+# CONFIG_EQUALIZER is not set
+# CONFIG_TUN is not set
 
 #
-# SCTP Configuration (EXPERIMENTAL)
+# ARCnet devices
 #
-# CONFIG_IP_SCTP is not set
-# CONFIG_ATM is not set
-# CONFIG_BRIDGE is not set
-# CONFIG_VLAN_8021Q is not set
-# CONFIG_DECNET is not set
-# CONFIG_LLC2 is not set
-# CONFIG_IPX is not set
-# CONFIG_ATALK is not set
-# CONFIG_X25 is not set
-# CONFIG_LAPB is not set
-# CONFIG_NET_DIVERT is not set
-# CONFIG_ECONET is not set
-# CONFIG_WAN_ROUTER is not set
+# CONFIG_ARCNET is not set
 
 #
-# QoS and/or fair queueing
+# PHY device support
 #
-# CONFIG_NET_SCHED is not set
-# CONFIG_NET_CLS_ROUTE is not set
+CONFIG_PHYLIB=y
 
 #
-# Network testing
+# MII PHY device drivers
 #
-# CONFIG_NET_PKTGEN is not set
-# CONFIG_NETPOLL is not set
-# CONFIG_NET_POLL_CONTROLLER is not set
-# CONFIG_HAMRADIO is not set
-# CONFIG_IRDA is not set
-# CONFIG_BT is not set
-CONFIG_NETDEVICES=y
-# CONFIG_DUMMY is not set
-# CONFIG_BONDING is not set
-# CONFIG_EQUALIZER is not set
-# CONFIG_TUN is not set
+CONFIG_MARVELL_PHY=y
+# CONFIG_DAVICOM_PHY is not set
+# CONFIG_QSEMI_PHY is not set
+# CONFIG_LXT_PHY is not set
+# CONFIG_CICADA_PHY is not set
 
 #
 # Ethernet (10 or 100Mbit)
 #
 CONFIG_NET_ETHERNET=y
 CONFIG_MII=y
+# CONFIG_HAPPYMEAL is not set
+# CONFIG_SUNGEM is not set
+# CONFIG_CASSINI is not set
+# CONFIG_NET_VENDOR_3COM is not set
+
+#
+# Tulip family network device support
+#
+# CONFIG_NET_TULIP is not set
+# CONFIG_HP100 is not set
+CONFIG_NET_PCI=y
+# CONFIG_PCNET32 is not set
+# CONFIG_AMD8111_ETH is not set
+# CONFIG_ADAPTEC_STARFIRE is not set
+# CONFIG_B44 is not set
+# CONFIG_FORCEDETH is not set
+# CONFIG_DGRS is not set
+# CONFIG_EEPRO100 is not set
+CONFIG_E100=y
+# CONFIG_FEALNX is not set
+# CONFIG_NATSEMI is not set
+# CONFIG_NE2K_PCI is not set
+# CONFIG_8139CP is not set
+# CONFIG_8139TOO is not set
+# CONFIG_SIS900 is not set
+# CONFIG_EPIC100 is not set
+# CONFIG_SUNDANCE is not set
+# CONFIG_TLAN is not set
+# CONFIG_VIA_RHINE is not set
 
 #
 # Ethernet (1000 Mbit)
 #
+# CONFIG_ACENIC is not set
+# CONFIG_DL2K is not set
+CONFIG_E1000=y
+# CONFIG_E1000_NAPI is not set
+# CONFIG_NS83820 is not set
+# CONFIG_HAMACHI is not set
+# CONFIG_YELLOWFIN is not set
+# CONFIG_R8169 is not set
+# CONFIG_SIS190 is not set
+# CONFIG_SKGE is not set
+# CONFIG_SK98LIN is not set
+# CONFIG_VIA_VELOCITY is not set
+# CONFIG_TIGON3 is not set
+# CONFIG_BNX2 is not set
 CONFIG_GIANFAR=y
 # CONFIG_GFAR_NAPI is not set
 
 #
 # Ethernet (10000 Mbit)
 #
+# CONFIG_CHELSIO_T1 is not set
+# CONFIG_IXGB is not set
+# CONFIG_S2IO is not set
 
 #
 # Token Ring devices
 #
+# CONFIG_TR is not set
 
 #
 # Wireless LAN (non-hamradio)
@@ -293,10 +436,14 @@ CONFIG_GIANFAR=y
 # Wan interfaces
 #
 # CONFIG_WAN is not set
+# CONFIG_FDDI is not set
+# CONFIG_HIPPI is not set
 # CONFIG_PPP is not set
 # CONFIG_SLIP is not set
 # CONFIG_SHAPER is not set
 # CONFIG_NETCONSOLE is not set
+# CONFIG_NETPOLL is not set
+# CONFIG_NET_POLL_CONTROLLER is not set
 
 #
 # ISDN subsystem
@@ -322,14 +469,6 @@ CONFIG_INPUT=y
 # CONFIG_INPUT_EVDEV is not set
 # CONFIG_INPUT_EVBUG is not set
 
-#
-# Input I/O drivers
-#
-# CONFIG_GAMEPORT is not set
-CONFIG_SOUND_GAMEPORT=y
-# CONFIG_SERIO is not set
-# CONFIG_SERIO_I8042 is not set
-
 #
 # Input Device Drivers
 #
@@ -339,6 +478,12 @@ CONFIG_SOUND_GAMEPORT=y
 # CONFIG_INPUT_TOUCHSCREEN is not set
 # CONFIG_INPUT_MISC is not set
 
+#
+# Hardware I/O ports
+#
+# CONFIG_SERIO is not set
+# CONFIG_GAMEPORT is not set
+
 #
 # Character devices
 #
@@ -358,6 +503,7 @@ CONFIG_SERIAL_8250_NR_UARTS=4
 #
 CONFIG_SERIAL_CORE=y
 CONFIG_SERIAL_CORE_CONSOLE=y
+# CONFIG_SERIAL_JSM is not set
 CONFIG_UNIX98_PTYS=y
 CONFIG_LEGACY_PTYS=y
 CONFIG_LEGACY_PTY_COUNT=256
@@ -376,6 +522,7 @@ CONFIG_GEN_RTC=y
 # CONFIG_GEN_RTC_X is not set
 # CONFIG_DTLK is not set
 # CONFIG_R3964 is not set
+# CONFIG_APPLICOM is not set
 
 #
 # Ftape, the floppy tape device driver
@@ -384,6 +531,12 @@ CONFIG_GEN_RTC=y
 # CONFIG_DRM is not set
 # CONFIG_RAW_DRIVER is not set
 
+#
+# TPM devices
+#
+# CONFIG_TCG_TPM is not set
+# CONFIG_TELCLOCK is not set
+
 #
 # I2C support
 #
@@ -400,23 +553,68 @@ CONFIG_I2C_CHARDEV=y
 #
 # I2C Hardware Bus support
 #
-# CONFIG_I2C_ISA is not set
+# CONFIG_I2C_ALI1535 is not set
+# CONFIG_I2C_ALI1563 is not set
+# CONFIG_I2C_ALI15X3 is not set
+# CONFIG_I2C_AMD756 is not set
+# CONFIG_I2C_AMD8111 is not set
+# CONFIG_I2C_I801 is not set
+# CONFIG_I2C_I810 is not set
+# CONFIG_I2C_PIIX4 is not set
 CONFIG_I2C_MPC=y
+# CONFIG_I2C_NFORCE2 is not set
 # CONFIG_I2C_PARPORT_LIGHT is not set
+# CONFIG_I2C_PROSAVAGE is not set
+# CONFIG_I2C_SAVAGE4 is not set
+# CONFIG_SCx200_ACB is not set
+# CONFIG_I2C_SIS5595 is not set
+# CONFIG_I2C_SIS630 is not set
+# CONFIG_I2C_SIS96X is not set
+# CONFIG_I2C_VIA is not set
+# CONFIG_I2C_VIAPRO is not set
+# CONFIG_I2C_VOODOO3 is not set
 # CONFIG_I2C_PCA_ISA is not set
 
 #
-# Hardware Sensors Chip support
+# Miscellaneous I2C Chip support
+#
+# CONFIG_SENSORS_DS1337 is not set
+# CONFIG_SENSORS_DS1374 is not set
+# CONFIG_SENSORS_EEPROM is not set
+# CONFIG_SENSORS_PCF8574 is not set
+# CONFIG_SENSORS_PCA9539 is not set
+# CONFIG_SENSORS_PCF8591 is not set
+# CONFIG_SENSORS_RTC8564 is not set
+# CONFIG_SENSORS_M41T00 is not set
+# CONFIG_SENSORS_MAX6875 is not set
+# CONFIG_RTC_X1205_I2C is not set
+# CONFIG_I2C_DEBUG_CORE is not set
+# CONFIG_I2C_DEBUG_ALGO is not set
+# CONFIG_I2C_DEBUG_BUS is not set
+# CONFIG_I2C_DEBUG_CHIP is not set
+
+#
+# Dallas's 1-wire bus
+#
+# CONFIG_W1 is not set
+
+#
+# Hardware Monitoring support
 #
-# CONFIG_I2C_SENSOR is not set
+CONFIG_HWMON=y
+# CONFIG_HWMON_VID is not set
 # CONFIG_SENSORS_ADM1021 is not set
 # CONFIG_SENSORS_ADM1025 is not set
 # CONFIG_SENSORS_ADM1026 is not set
 # CONFIG_SENSORS_ADM1031 is not set
+# CONFIG_SENSORS_ADM9240 is not set
 # CONFIG_SENSORS_ASB100 is not set
+# CONFIG_SENSORS_ATXP1 is not set
 # CONFIG_SENSORS_DS1621 is not set
 # CONFIG_SENSORS_FSCHER is not set
+# CONFIG_SENSORS_FSCPOS is not set
 # CONFIG_SENSORS_GL518SM is not set
+# CONFIG_SENSORS_GL520SM is not set
 # CONFIG_SENSORS_IT87 is not set
 # CONFIG_SENSORS_LM63 is not set
 # CONFIG_SENSORS_LM75 is not set
@@ -427,33 +625,26 @@ CONFIG_I2C_MPC=y
 # CONFIG_SENSORS_LM85 is not set
 # CONFIG_SENSORS_LM87 is not set
 # CONFIG_SENSORS_LM90 is not set
+# CONFIG_SENSORS_LM92 is not set
 # CONFIG_SENSORS_MAX1619 is not set
 # CONFIG_SENSORS_PC87360 is not set
-# CONFIG_SENSORS_SMSC47B397 is not set
+# CONFIG_SENSORS_SIS5595 is not set
 # CONFIG_SENSORS_SMSC47M1 is not set
+# CONFIG_SENSORS_SMSC47B397 is not set
+# CONFIG_SENSORS_VIA686A is not set
 # CONFIG_SENSORS_W83781D is not set
+# CONFIG_SENSORS_W83792D is not set
 # CONFIG_SENSORS_W83L785TS is not set
 # CONFIG_SENSORS_W83627HF is not set
+# CONFIG_SENSORS_W83627EHF is not set
+# CONFIG_HWMON_DEBUG_CHIP is not set
 
 #
-# Other I2C Chip support
-#
-# CONFIG_SENSORS_EEPROM is not set
-# CONFIG_SENSORS_PCF8574 is not set
-# CONFIG_SENSORS_PCF8591 is not set
-# CONFIG_SENSORS_RTC8564 is not set
-# CONFIG_I2C_DEBUG_CORE is not set
-# CONFIG_I2C_DEBUG_ALGO is not set
-# CONFIG_I2C_DEBUG_BUS is not set
-# CONFIG_I2C_DEBUG_CHIP is not set
-
-#
-# Dallas's 1-wire bus
+# Misc devices
 #
-# CONFIG_W1 is not set
 
 #
-# Misc devices
+# Multimedia Capabilities Port drivers
 #
 
 #
@@ -479,11 +670,12 @@ CONFIG_I2C_MPC=y
 #
 # USB support
 #
-# CONFIG_USB_ARCH_HAS_HCD is not set
-# CONFIG_USB_ARCH_HAS_OHCI is not set
+CONFIG_USB_ARCH_HAS_HCD=y
+CONFIG_USB_ARCH_HAS_OHCI=y
+# CONFIG_USB is not set
 
 #
-# NOTE: USB_STORAGE enables SCSI, and 'SCSI disk support' may also be needed; see USB_STORAGE Help for more information
+# NOTE: USB_STORAGE enables SCSI, and 'SCSI disk support'
 #
 
 #
@@ -501,11 +693,16 @@ CONFIG_I2C_MPC=y
 #
 # CONFIG_INFINIBAND is not set
 
+#
+# SN Devices
+#
+
 #
 # File systems
 #
 CONFIG_EXT2_FS=y
 # CONFIG_EXT2_FS_XATTR is not set
+# CONFIG_EXT2_FS_XIP is not set
 CONFIG_EXT3_FS=y
 CONFIG_EXT3_FS_XATTR=y
 # CONFIG_EXT3_FS_POSIX_ACL is not set
@@ -515,17 +712,16 @@ CONFIG_JBD=y
 CONFIG_FS_MBCACHE=y
 # CONFIG_REISERFS_FS is not set
 # CONFIG_JFS_FS is not set
-
-#
-# XFS support
-#
+# CONFIG_FS_POSIX_ACL is not set
 # CONFIG_XFS_FS is not set
 # CONFIG_MINIX_FS is not set
 # CONFIG_ROMFS_FS is not set
+CONFIG_INOTIFY=y
 # CONFIG_QUOTA is not set
 CONFIG_DNOTIFY=y
 # CONFIG_AUTOFS_FS is not set
 # CONFIG_AUTOFS4_FS is not set
+# CONFIG_FUSE_FS is not set
 
 #
 # CD-ROM/DVD Filesystems
@@ -546,12 +742,10 @@ CONFIG_DNOTIFY=y
 CONFIG_PROC_FS=y
 CONFIG_PROC_KCORE=y
 CONFIG_SYSFS=y
-# CONFIG_DEVFS_FS is not set
-# CONFIG_DEVPTS_FS_XATTR is not set
 CONFIG_TMPFS=y
-# CONFIG_TMPFS_XATTR is not set
 # CONFIG_HUGETLB_PAGE is not set
 CONFIG_RAMFS=y
+# CONFIG_RELAYFS_FS is not set
 
 #
 # Miscellaneous filesystems
@@ -580,6 +774,7 @@ CONFIG_NFS_FS=y
 # CONFIG_NFSD is not set
 CONFIG_ROOT_NFS=y
 CONFIG_LOCKD=y
+CONFIG_NFS_COMMON=y
 CONFIG_SUNRPC=y
 # CONFIG_RPCSEC_GSS_KRB5 is not set
 # CONFIG_RPCSEC_GSS_SPKM3 is not set
@@ -588,6 +783,7 @@ CONFIG_SUNRPC=y
 # CONFIG_NCP_FS is not set
 # CONFIG_CODA_FS is not set
 # CONFIG_AFS_FS is not set
+# CONFIG_9P_FS is not set
 
 #
 # Partition Types
@@ -614,6 +810,7 @@ CONFIG_PARTITION_ADVANCED=y
 # Library routines
 #
 # CONFIG_CRC_CCITT is not set
+# CONFIG_CRC16 is not set
 CONFIG_CRC32=y
 # CONFIG_LIBCRC32C is not set
 
@@ -625,7 +822,9 @@ CONFIG_CRC32=y
 #
 # Kernel hacking
 #
+# CONFIG_PRINTK_TIME is not set
 # CONFIG_DEBUG_KERNEL is not set
+CONFIG_LOG_BUF_SHIFT=14
 # CONFIG_SERIAL_TEXT_DEBUG is not set
 
 #
index 11e5b44713f7237e3ec0ecf2b0fc331fff751619..3c4e4cb610743e070d7237ed7df5fff2fa67c75e 100644 (file)
@@ -53,10 +53,6 @@ void default_idle(void)
                }
 #endif
        }
-       if (need_resched())
-               schedule();
-       if (cpu_is_offline(cpu) && system_state == SYSTEM_RUNNING)
-               cpu_die();
 }
 
 /*
@@ -64,11 +60,22 @@ void default_idle(void)
  */
 void cpu_idle(void)
 {
-       for (;;)
-               if (ppc_md.idle != NULL)
-                       ppc_md.idle();
-               else
-                       default_idle();
+       int cpu = smp_processor_id();
+
+       for (;;) {
+               while (need_resched()) {
+                       if (ppc_md.idle != NULL)
+                               ppc_md.idle();
+                       else
+                               default_idle();
+               }
+
+               if (cpu_is_offline(cpu) && system_state == SYSTEM_RUNNING)
+                       cpu_die();
+               preempt_enable_no_resched();
+               schedule();
+               preempt_disable();
+       }
 }
 
 #if defined(CONFIG_SYSCTL) && defined(CONFIG_6xx)
index 3056ede2424d6be4f261674a2635484f813ec1ae..ae6af29938a1efc96513a6b8f33d25667d248f4f 100644 (file)
 #include <asm/thread_info.h>
 #include <asm/asm-offsets.h>
 
+#ifdef CONFIG_8xx
+#define ISYNC_8xx isync
+#else
+#define ISYNC_8xx
+#endif
        .text
 
        .align  5
@@ -800,8 +805,18 @@ _GLOBAL(_insb)
        subi    r4,r4,1
        blelr-
 00:    lbz     r5,0(r3)
-       eieio
-       stbu    r5,1(r4)
+01:    eieio
+02:    stbu    r5,1(r4)
+       ISYNC_8xx
+       .section .fixup,"ax"
+03:    blr
+       .text
+       .section __ex_table, "a"
+               .align 2
+               .long 00b, 03b
+               .long 01b, 03b
+               .long 02b, 03b
+       .text
        bdnz    00b
        blr
 
@@ -811,8 +826,18 @@ _GLOBAL(_outsb)
        subi    r4,r4,1
        blelr-
 00:    lbzu    r5,1(r4)
-       stb     r5,0(r3)
-       eieio
+01:    stb     r5,0(r3)
+02:    eieio
+       ISYNC_8xx
+       .section .fixup,"ax"
+03:    blr
+       .text
+       .section __ex_table, "a"
+               .align 2
+               .long 00b, 03b
+               .long 01b, 03b
+               .long 02b, 03b
+       .text
        bdnz    00b
        blr
 
@@ -822,8 +847,18 @@ _GLOBAL(_insw)
        subi    r4,r4,2
        blelr-
 00:    lhbrx   r5,0,r3
-       eieio
-       sthu    r5,2(r4)
+01:    eieio
+02:    sthu    r5,2(r4)
+       ISYNC_8xx
+       .section .fixup,"ax"
+03:    blr
+       .text
+       .section __ex_table, "a"
+               .align 2
+               .long 00b, 03b
+               .long 01b, 03b
+               .long 02b, 03b
+       .text
        bdnz    00b
        blr
 
@@ -833,8 +868,18 @@ _GLOBAL(_outsw)
        subi    r4,r4,2
        blelr-
 00:    lhzu    r5,2(r4)
-       eieio
-       sthbrx  r5,0,r3
+01:    eieio
+02:    sthbrx  r5,0,r3
+       ISYNC_8xx
+       .section .fixup,"ax"
+03:    blr
+       .text
+       .section __ex_table, "a"
+               .align 2
+               .long 00b, 03b
+               .long 01b, 03b
+               .long 02b, 03b
+       .text
        bdnz    00b
        blr
 
@@ -844,8 +889,18 @@ _GLOBAL(_insl)
        subi    r4,r4,4
        blelr-
 00:    lwbrx   r5,0,r3
-       eieio
-       stwu    r5,4(r4)
+01:    eieio
+02:    stwu    r5,4(r4)
+       ISYNC_8xx
+       .section .fixup,"ax"
+03:    blr
+       .text
+       .section __ex_table, "a"
+               .align 2
+               .long 00b, 03b
+               .long 01b, 03b
+               .long 02b, 03b
+       .text
        bdnz    00b
        blr
 
@@ -855,8 +910,18 @@ _GLOBAL(_outsl)
        subi    r4,r4,4
        blelr-
 00:    lwzu    r5,4(r4)
-       stwbrx  r5,0,r3
-       eieio
+01:    stwbrx  r5,0,r3
+02:    eieio
+       ISYNC_8xx
+       .section .fixup,"ax"
+03:    blr
+       .text
+       .section __ex_table, "a"
+               .align 2
+               .long 00b, 03b
+               .long 01b, 03b
+               .long 02b, 03b
+       .text
        bdnz    00b
        blr
 
@@ -867,8 +932,18 @@ _GLOBAL(_insw_ns)
        subi    r4,r4,2
        blelr-
 00:    lhz     r5,0(r3)
-       eieio
-       sthu    r5,2(r4)
+01:    eieio
+02:    sthu    r5,2(r4)
+       ISYNC_8xx
+       .section .fixup,"ax"
+03:    blr
+       .text
+       .section __ex_table, "a"
+               .align 2
+               .long 00b, 03b
+               .long 01b, 03b
+               .long 02b, 03b
+       .text
        bdnz    00b
        blr
 
@@ -879,8 +954,18 @@ _GLOBAL(_outsw_ns)
        subi    r4,r4,2
        blelr-
 00:    lhzu    r5,2(r4)
-       sth     r5,0(r3)
-       eieio
+01:    sth     r5,0(r3)
+02:    eieio
+       ISYNC_8xx
+       .section .fixup,"ax"
+03:    blr
+       .text
+       .section __ex_table, "a"
+               .align 2
+               .long 00b, 03b
+               .long 01b, 03b
+               .long 02b, 03b
+       .text
        bdnz    00b
        blr
 
@@ -891,8 +976,18 @@ _GLOBAL(_insl_ns)
        subi    r4,r4,4
        blelr-
 00:    lwz     r5,0(r3)
-       eieio
-       stwu    r5,4(r4)
+01:    eieio
+02:    stwu    r5,4(r4)
+       ISYNC_8xx
+       .section .fixup,"ax"
+03:    blr
+       .text
+       .section __ex_table, "a"
+               .align 2
+               .long 00b, 03b
+               .long 01b, 03b
+               .long 02b, 03b
+       .text
        bdnz    00b
        blr
 
@@ -903,8 +998,18 @@ _GLOBAL(_outsl_ns)
        subi    r4,r4,4
        blelr-
 00:    lwzu    r5,4(r4)
-       stw     r5,0(r3)
-       eieio
+01:    stw     r5,0(r3)
+02:    eieio
+       ISYNC_8xx
+       .section .fixup,"ax"
+03:    blr
+       .text
+       .section __ex_table, "a"
+               .align 2
+               .long 00b, 03b
+               .long 01b, 03b
+               .long 02b, 03b
+       .text
        bdnz    00b
        blr
 
index bc5bf1124836adb4013c8a09ceb28c9421feed26..43b8fc2ca591c86388427c4b822eababd6991e11 100644 (file)
@@ -341,6 +341,7 @@ int __devinit start_secondary(void *unused)
        cpu = smp_processor_id();
         smp_store_cpu_info(cpu);
        set_dec(tb_ticks_per_jiffy);
+       preempt_disable();
        cpu_callin_map[cpu] = 1;
 
        printk("CPU %d done callin...\n", cpu);
index 16adde6b429d2641827eade241cf016c22d2889b..9dbc4d28fa281cf6d8c83810e3204acb92eecf48 100644 (file)
@@ -49,7 +49,7 @@ extern int xmon_sstep(struct pt_regs *regs);
 extern int xmon_iabr_match(struct pt_regs *regs);
 extern int xmon_dabr_match(struct pt_regs *regs);
 
-void (*debugger)(struct pt_regs *regs) = xmon;
+int (*debugger)(struct pt_regs *regs) = xmon;
 int (*debugger_bpt)(struct pt_regs *regs) = xmon_bpt;
 int (*debugger_sstep)(struct pt_regs *regs) = xmon_sstep;
 int (*debugger_iabr_match)(struct pt_regs *regs) = xmon_iabr_match;
@@ -57,7 +57,7 @@ int (*debugger_dabr_match)(struct pt_regs *regs) = xmon_dabr_match;
 void (*debugger_fault_handler)(struct pt_regs *regs);
 #else
 #ifdef CONFIG_KGDB
-void (*debugger)(struct pt_regs *regs);
+int (*debugger)(struct pt_regs *regs);
 int (*debugger_bpt)(struct pt_regs *regs);
 int (*debugger_sstep)(struct pt_regs *regs);
 int (*debugger_iabr_match)(struct pt_regs *regs);
@@ -159,7 +159,7 @@ void _exception(int signr, struct pt_regs *regs, int code, unsigned long addr)
  */
 static inline int check_io_access(struct pt_regs *regs)
 {
-#ifdef CONFIG_PPC_PMAC
+#if defined CONFIG_PPC_PMAC || defined CONFIG_8xx
        unsigned long msr = regs->msr;
        const struct exception_table_entry *entry;
        unsigned int *nip = (unsigned int *)regs->nip;
@@ -178,7 +178,11 @@ static inline int check_io_access(struct pt_regs *regs)
                        nip -= 2;
                else if (*nip == 0x4c00012c)    /* isync */
                        --nip;
-               if (*nip == 0x7c0004ac || (*nip >> 26) == 3) {
+               /* eieio from I/O string functions */
+               else if ((*nip) == 0x7c0006ac || *(nip+1) == 0x7c0006ac)
+                       nip += 2;
+               if (*nip == 0x7c0004ac || (*nip >> 26) == 3 ||
+                       (*(nip+1) >> 26) == 3) {
                        /* sync or twi */
                        unsigned int rb;
 
index 79b3f533d0a3a698d2159dbec8f46d39428c2d3b..98edc75f4105b22149a967b3dfd624ffee64e766 100644 (file)
@@ -51,6 +51,9 @@
 
 #include <syslib/ppc83xx_setup.h>
 
+static const char *GFAR_PHY_0 = "phy0:0";
+static const char *GFAR_PHY_1 = "phy0:1";
+
 #ifndef CONFIG_PCI
 unsigned long isa_io_base = 0;
 unsigned long isa_mem_base = 0;
@@ -97,6 +100,7 @@ mpc834x_sys_setup_arch(void)
        bd_t *binfo = (bd_t *) __res;
        unsigned int freq;
        struct gianfar_platform_data *pdata;
+       struct gianfar_mdio_data *mdata;
 
        /* get the core frequency */
        freq = binfo->bi_intfreq;
@@ -111,24 +115,27 @@ mpc834x_sys_setup_arch(void)
 #endif
        mpc83xx_early_serial_map();
 
+       /* setup the board related info for the MDIO bus */
+       mdata = (struct gianfar_mdio_data *) ppc_sys_get_pdata(MPC83xx_MDIO);
+
+       mdata->irq[0] = MPC83xx_IRQ_EXT1;
+       mdata->irq[1] = MPC83xx_IRQ_EXT2;
+       mdata->irq[2] = -1;
+       mdata->irq[31] = -1;
+       mdata->paddr += binfo->bi_immr_base;
+
        /* setup the board related information for the enet controllers */
        pdata = (struct gianfar_platform_data *) ppc_sys_get_pdata(MPC83xx_TSEC1);
        if (pdata) {
                pdata->board_flags = FSL_GIANFAR_BRD_HAS_PHY_INTR;
-               pdata->interruptPHY = MPC83xx_IRQ_EXT1;
-               pdata->phyid = 0;
-               /* fixup phy address */
-               pdata->phy_reg_addr += binfo->bi_immr_base;
+               pdata->bus_id = GFAR_PHY_0;
                memcpy(pdata->mac_addr, binfo->bi_enetaddr, 6);
        }
 
        pdata = (struct gianfar_platform_data *) ppc_sys_get_pdata(MPC83xx_TSEC2);
        if (pdata) {
                pdata->board_flags = FSL_GIANFAR_BRD_HAS_PHY_INTR;
-               pdata->interruptPHY = MPC83xx_IRQ_EXT2;
-               pdata->phyid = 1;
-               /* fixup phy address */
-               pdata->phy_reg_addr += binfo->bi_immr_base;
+               pdata->bus_id = GFAR_PHY_1;
                memcpy(pdata->mac_addr, binfo->bi_enet1addr, 6);
        }
 
index 95fdf4b0680bc6fd8fdcb309c24bcaf283f29781..7bcc6c35a417eda482c0434332aa82db1084d63d 100644 (file)
@@ -21,6 +21,7 @@
 
 #include <linux/config.h>
 #include <linux/init.h>
+#include <linux/seq_file.h>
 #include <asm/ppcboot.h>
 
 #define BOARD_CCSRBAR          ((uint)0xe0000000)
index 5bd33baac24322d85208114089af1b8edcbc7bec..5b7f2b80e56e575f37b7597e867f3addee27064e 100644 (file)
@@ -33,7 +33,6 @@ obj-$(CONFIG_PPC4xx_DMA)      += ppc4xx_dma.o
 obj-$(CONFIG_PPC4xx_EDMA)      += ppc4xx_sgdma.o
 ifeq ($(CONFIG_40x),y)
 obj-$(CONFIG_PCI)              += pci_auto.o ppc405_pci.o
-obj-$(CONFIG_RAPIDIO)          += ppc85xx_rio.o
 endif
 endif
 obj-$(CONFIG_8xx)              += m8xx_setup.o ppc8xx_pic.o $(wdt-mpc8xx-y) \
@@ -96,6 +95,7 @@ obj-$(CONFIG_85xx)            += open_pic.o ppc85xx_common.o ppc85xx_setup.o \
 ifeq ($(CONFIG_85xx),y)
 obj-$(CONFIG_PCI)              += pci_auto.o
 endif
+obj-$(CONFIG_RAPIDIO)          += ppc85xx_rio.o
 obj-$(CONFIG_83xx)             += ipic.o ppc83xx_setup.o ppc_sys.o \
                                        mpc83xx_sys.o mpc83xx_devices.o
 ifeq ($(CONFIG_83xx),y)
index c5ac5ce5d7d2d29e1cdac44f15cd24ee5e95447d..a21632d37e5ab7263f498664ef08ff448625086e 100644 (file)
@@ -14,6 +14,7 @@
 #include <linux/irq.h>
 #include <linux/kernel.h>
 #include <linux/sched.h>
+#include <asm/io.h>
 #include <asm/8xx_immap.h>
 #include <syslib/m8xx_wdt.h>
 
@@ -29,8 +30,8 @@ void m8xx_wdt_reset(void)
 {
        volatile immap_t *imap = (volatile immap_t *)IMAP_ADDR;
 
-       out_be16(imap->im_siu_conf.sc_swsr, 0x556c);    /* write magic1 */
-       out_be16(imap->im_siu_conf.sc_swsr, 0xaa39);    /* write magic2 */
+       out_be16(&imap->im_siu_conf.sc_swsr, 0x556c);   /* write magic1 */
+       out_be16(&imap->im_siu_conf.sc_swsr, 0xaa39);   /* write magic2 */
 }
 
 static irqreturn_t m8xx_wdt_interrupt(int irq, void *dev, struct pt_regs *regs)
@@ -39,7 +40,7 @@ static irqreturn_t m8xx_wdt_interrupt(int irq, void *dev, struct pt_regs *regs)
 
        m8xx_wdt_reset();
 
-       out_be16(imap->im_sit.sit_piscr, in_be16(imap->im_sit.sit_piscr | PISCR_PS));   /* clear irq */
+       out_be16(&imap->im_sit.sit_piscr, in_be16(&imap->im_sit.sit_piscr) | PISCR_PS); /* clear irq */
 
        return IRQ_HANDLED;
 }
@@ -51,7 +52,7 @@ void __init m8xx_wdt_handler_install(bd_t * binfo)
        u32 sypcr;
        u32 pitrtclk;
 
-       sypcr = in_be32(imap->im_siu_conf.sc_sypcr);
+       sypcr = in_be32(&imap->im_siu_conf.sc_sypcr);
 
        if (!(sypcr & 0x04)) {
                printk(KERN_NOTICE "m8xx_wdt: wdt disabled (SYPCR: 0x%08X)\n",
@@ -87,9 +88,9 @@ void __init m8xx_wdt_handler_install(bd_t * binfo)
        else
                pitc = pitrtclk * wdt_timeout / binfo->bi_intfreq / 2;
 
-       out_be32(imap->im_sit.sit_pitc, pitc << 16);
+       out_be32(&imap->im_sit.sit_pitc, pitc << 16);
 
-       out_be16(imap->im_sit.sit_piscr, (mk_int_int_mask(PIT_INTERRUPT) << 8) | PISCR_PIE | PISCR_PTE);
+       out_be16(&imap->im_sit.sit_piscr, (mk_int_int_mask(PIT_INTERRUPT) << 8) | PISCR_PIE | PISCR_PTE);
 
        if (setup_irq(PIT_INTERRUPT, &m8xx_wdt_irqaction))
                panic("m8xx_wdt: error setting up the watchdog irq!");
index dbf8acac507feb0b232dd79fb57cfed0d4e00961..f43fbf9a9389c05cbc4e6303c35f7d64a5909ce7 100644 (file)
  * what IMMRBAR is, will get fixed up by mach_mpc83xx_fixup
  */
 
+struct gianfar_mdio_data mpc83xx_mdio_pdata = {
+       .paddr = 0x24520,
+};
+
 static struct gianfar_platform_data mpc83xx_tsec1_pdata = {
        .device_flags = FSL_GIANFAR_DEV_HAS_GIGABIT |
            FSL_GIANFAR_DEV_HAS_COALESCE | FSL_GIANFAR_DEV_HAS_RMON |
            FSL_GIANFAR_DEV_HAS_MULTI_INTR,
-       .phy_reg_addr = 0x24000,
 };
 
 static struct gianfar_platform_data mpc83xx_tsec2_pdata = {
        .device_flags = FSL_GIANFAR_DEV_HAS_GIGABIT |
            FSL_GIANFAR_DEV_HAS_COALESCE | FSL_GIANFAR_DEV_HAS_RMON |
            FSL_GIANFAR_DEV_HAS_MULTI_INTR,
-       .phy_reg_addr = 0x24000,
 };
 
 static struct fsl_i2c_platform_data mpc83xx_fsl_i2c1_pdata = {
@@ -220,6 +222,12 @@ struct platform_device ppc_sys_platform_devices[] = {
                        },
                },
        },
+       [MPC83xx_MDIO] = {
+               .name = "fsl-gianfar_mdio",
+               .id = 0,
+               .dev.platform_data = &mpc83xx_mdio_pdata,
+               .num_resources = 0,
+       },
 };
 
 static int __init mach_mpc83xx_fixup(struct platform_device *pdev)
index 29aa63350025ca3e57517cedd5ffc0a86f815d45..da743446789b01882ae9375adc55145538e2b48c 100644 (file)
@@ -24,72 +24,72 @@ struct ppc_sys_spec ppc_sys_specs[] = {
                .ppc_sys_name   = "8349E",
                .mask           = 0xFFFF0000,
                .value          = 0x80500000,
-               .num_devices    = 8,
+               .num_devices    = 9,
                .device_list    = (enum ppc_sys_devices[])
                {
                        MPC83xx_TSEC1, MPC83xx_TSEC2, MPC83xx_IIC1,
                        MPC83xx_IIC2, MPC83xx_DUART, MPC83xx_SEC2,
-                       MPC83xx_USB2_DR, MPC83xx_USB2_MPH
+                       MPC83xx_USB2_DR, MPC83xx_USB2_MPH, MPC83xx_MDIO
                },
        },
        {
                .ppc_sys_name   = "8349",
                .mask           = 0xFFFF0000,
                .value          = 0x80510000,
-               .num_devices    = 7,
+               .num_devices    = 8,
                .device_list    = (enum ppc_sys_devices[])
                {
                        MPC83xx_TSEC1, MPC83xx_TSEC2, MPC83xx_IIC1,
                        MPC83xx_IIC2, MPC83xx_DUART,
-                       MPC83xx_USB2_DR, MPC83xx_USB2_MPH
+                       MPC83xx_USB2_DR, MPC83xx_USB2_MPH, MPC83xx_MDIO
                },
        },
        {
                .ppc_sys_name   = "8347E",
                .mask           = 0xFFFF0000,
                .value          = 0x80520000,
-               .num_devices    = 8,
+               .num_devices    = 9,
                .device_list    = (enum ppc_sys_devices[])
                {
                        MPC83xx_TSEC1, MPC83xx_TSEC2, MPC83xx_IIC1,
                        MPC83xx_IIC2, MPC83xx_DUART, MPC83xx_SEC2,
-                       MPC83xx_USB2_DR, MPC83xx_USB2_MPH
+                       MPC83xx_USB2_DR, MPC83xx_USB2_MPH, MPC83xx_MDIO
                },
        },
        {
                .ppc_sys_name   = "8347",
                .mask           = 0xFFFF0000,
                .value          = 0x80530000,
-               .num_devices    = 7,
+               .num_devices    = 8,
                .device_list    = (enum ppc_sys_devices[])
                {
                        MPC83xx_TSEC1, MPC83xx_TSEC2, MPC83xx_IIC1,
                        MPC83xx_IIC2, MPC83xx_DUART,
-                       MPC83xx_USB2_DR, MPC83xx_USB2_MPH
+                       MPC83xx_USB2_DR, MPC83xx_USB2_MPH, MPC83xx_MDIO
                },
        },
        {
                .ppc_sys_name   = "8343E",
                .mask           = 0xFFFF0000,
                .value          = 0x80540000,
-               .num_devices    = 7,
+               .num_devices    = 8,
                .device_list    = (enum ppc_sys_devices[])
                {
                        MPC83xx_TSEC1, MPC83xx_TSEC2, MPC83xx_IIC1,
                        MPC83xx_IIC2, MPC83xx_DUART, MPC83xx_SEC2,
-                       MPC83xx_USB2_DR,
+                       MPC83xx_USB2_DR, MPC83xx_MDIO
                },
        },
        {
                .ppc_sys_name   = "8343",
                .mask           = 0xFFFF0000,
                .value          = 0x80550000,
-               .num_devices    = 6,
+               .num_devices    = 7,
                .device_list    = (enum ppc_sys_devices[])
                {
                        MPC83xx_TSEC1, MPC83xx_TSEC2, MPC83xx_IIC1,
                        MPC83xx_IIC2, MPC83xx_DUART,
-                       MPC83xx_USB2_DR,
+                       MPC83xx_USB2_DR, MPC83xx_MDIO
                },
        },
        {       /* default match */
index 1b9aa0d6a924f5259446c9bbf9a09ac58c0cbfe4..af4deace49e0bcf5aab48660ec9a8d88c543495b 100644 (file)
@@ -13,7 +13,6 @@
 #include <linux/kernel.h>
 #include <linux/string.h>
 #include <linux/init.h>
-#include <linux/version.h>
 #include <linux/threads.h>
 #include <linux/spinlock.h>
 #include <linux/ioport.h>
@@ -1165,7 +1164,7 @@ get_property(struct device_node *np, const char *name, int *lenp)
 /*
  * Add a property to a node
  */
-void
+int
 prom_add_property(struct device_node* np, struct property* prop)
 {
        struct property **next = &np->properties;
@@ -1174,6 +1173,8 @@ prom_add_property(struct device_node* np, struct property* prop)
        while (*next)
                next = &(*next)->next;
        *next = prop;
+
+       return 0;
 }
 
 /* I quickly hacked that one, check against spec ! */
index 7f15136830f4fbf38fe38e3a5418e85e51e47b96..df14422ae1c606b072b055d3b34c2243eb6bdaad 100644 (file)
@@ -9,7 +9,6 @@
 #include <linux/kernel.h>
 #include <linux/string.h>
 #include <linux/init.h>
-#include <linux/version.h>
 #include <linux/threads.h>
 #include <linux/spinlock.h>
 #include <linux/ioport.h>
index 66bfaa3211a262fb1a748d636119df5e41cb2024..2b483b4f1602b12a73d2b60ba55fea20faa53e31 100644 (file)
@@ -220,8 +220,7 @@ static void get_tb(unsigned *p)
        p[1] = lo;
 }
 
-void
-xmon(struct pt_regs *excp)
+int xmon(struct pt_regs *excp)
 {
        struct pt_regs regs;
        int msr, cmd;
@@ -290,6 +289,8 @@ xmon(struct pt_regs *excp)
 #endif /* CONFIG_SMP */
        set_msr(msr);           /* restore interrupt enable */
        get_tb(start_tb[smp_processor_id()]);
+
+       return cmd != 'X';
 }
 
 irqreturn_t
index 2130cc31595753643d1db643a57e610ea97265cd..29552348e58165db414bf6f609ae19e31e9fad7a 100644 (file)
@@ -56,6 +56,7 @@ config PPC_STD_MMU
 # max order + 1
 config FORCE_MAX_ZONEORDER
        int
+       default "9" if PPC_64K_PAGES
        default "13"
 
 source "init/Kconfig"
@@ -173,6 +174,16 @@ config KEXEC
          support.  As of this writing the exact hardware interface is
          strongly in flux, so no good recommendation can be made.
 
+source "drivers/cpufreq/Kconfig"
+
+config CPU_FREQ_PMAC64
+       bool "Support for some Apple G5s"
+       depends on CPU_FREQ && PMAC_SMU && PPC64
+       select CPU_FREQ_TABLE
+       help
+         This adds support for frequency switching on Apple iMac G5,
+         and some of the more recent desktop G5 machines as well.
+
 config IBMVIO
        depends on PPC_PSERIES || PPC_ISERIES
        bool
index f16a5030527bd1e8f8818dc7337d49ba049054f3..b258c9314a1bda2b2bdf4f6e962e600a0ce206ba 100644 (file)
@@ -55,10 +55,6 @@ config XMON_DEFAULT
          xmon is normally disabled unless booted with 'xmon=on'.
          Use 'xmon=off' to disable xmon init during runtime.
 
-config PPCDBG
-       bool "Include PPCDBG realtime debugging"
-       depends on DEBUG_KERNEL
-
 config IRQSTACKS
        bool "Use separate kernel stacks when processing interrupts"
        help
index 8abd2ad928325e3cc29876859cddae39577d7542..715bc0e71e0f4dbc45327ce08a59a5a1ab58a335 100644 (file)
 #include <asm/time.h>
 #include <asm/systemcfg.h>
 #include <asm/machdep.h>
+#include <asm/smp.h>
 
 extern void power4_idle(void);
 
 void default_idle(void)
 {
-       long oldval;
        unsigned int cpu = smp_processor_id();
+       set_thread_flag(TIF_POLLING_NRFLAG);
 
        while (1) {
-               oldval = test_and_clear_thread_flag(TIF_NEED_RESCHED);
-
-               if (!oldval) {
-                       set_thread_flag(TIF_POLLING_NRFLAG);
-
+               if (!need_resched()) {
                        while (!need_resched() && !cpu_is_offline(cpu)) {
                                ppc64_runlatch_off();
 
@@ -54,13 +51,12 @@ void default_idle(void)
                        }
 
                        HMT_medium();
-                       clear_thread_flag(TIF_POLLING_NRFLAG);
-               } else {
-                       set_need_resched();
                }
 
                ppc64_runlatch_on();
+               preempt_enable_no_resched();
                schedule();
+               preempt_disable();
                if (cpu_is_offline(cpu) && system_state == SYSTEM_RUNNING)
                        cpu_die();
        }
@@ -76,7 +72,9 @@ void native_idle(void)
 
                if (need_resched()) {
                        ppc64_runlatch_on();
+                       preempt_enable_no_resched();
                        schedule();
+                       preempt_disable();
                }
 
                if (cpu_is_offline(smp_processor_id()) &&
index ff8679f260f3819a61bcf0f791c36fe677b18757..07ea03598c004774cfed9fde43bf0c587592eec8 100644 (file)
@@ -24,6 +24,7 @@
 #include <asm/mmu.h>
 #include <asm/sections.h>      /* _end */
 #include <asm/prom.h>
+#include <asm/smp.h>
 
 #define HASH_GROUP_SIZE 0x80   /* size of each hash group, asm/mmu.h */
 
index 077507ffbab80e1601b69e037ccb970d0956f6c6..914632ec587d46fea767a47375160b1b0c2a2ab1 100644 (file)
@@ -560,7 +560,7 @@ _GLOBAL(real_readb)
        isync
        blr
 
-       /*
+/*
  * Do an IO access in real mode
  */
 _GLOBAL(real_writeb)
@@ -592,6 +592,76 @@ _GLOBAL(real_writeb)
        blr
 #endif /* defined(CONFIG_PPC_PMAC) || defined(CONFIG_PPC_MAPLE) */
 
+/*
+ * SCOM access functions for 970 (FX only for now)
+ *
+ * unsigned long scom970_read(unsigned int address);
+ * void scom970_write(unsigned int address, unsigned long value);
+ *
+ * The address passed in is the 24 bits register address. This code
+ * is 970 specific and will not check the status bits, so you should
+ * know what you are doing.
+ */
+_GLOBAL(scom970_read)
+       /* interrupts off */
+       mfmsr   r4
+       ori     r0,r4,MSR_EE
+       xori    r0,r0,MSR_EE
+       mtmsrd  r0,1
+
+       /* rotate 24 bits SCOM address 8 bits left and mask out it's low 8 bits
+        * (including parity). On current CPUs they must be 0'd,
+        * and finally or in RW bit
+        */
+       rlwinm  r3,r3,8,0,15
+       ori     r3,r3,0x8000
+
+       /* do the actual scom read */
+       sync
+       mtspr   SPRN_SCOMC,r3
+       isync
+       mfspr   r3,SPRN_SCOMD
+       isync
+       mfspr   r0,SPRN_SCOMC
+       isync
+
+       /* XXX: fixup result on some buggy 970's (ouch ! we lost a bit, bah
+        * that's the best we can do). Not implemented yet as we don't use
+        * the scom on any of the bogus CPUs yet, but may have to be done
+        * ultimately
+        */
+
+       /* restore interrupts */
+       mtmsrd  r4,1
+       blr
+
+
+_GLOBAL(scom970_write)
+       /* interrupts off */
+       mfmsr   r5
+       ori     r0,r5,MSR_EE
+       xori    r0,r0,MSR_EE
+       mtmsrd  r0,1
+
+       /* rotate 24 bits SCOM address 8 bits left and mask out it's low 8 bits
+        * (including parity). On current CPUs they must be 0'd.
+        */
+
+       rlwinm  r3,r3,8,0,15
+
+       sync
+       mtspr   SPRN_SCOMD,r4      /* write data */
+       isync
+       mtspr   SPRN_SCOMC,r3      /* write command */
+       isync
+       mfspr   3,SPRN_SCOMC
+       isync
+
+       /* restore interrupts */
+       mtmsrd  r5,1
+       blr
+
+
 /*
  * Create a kernel thread
  *   kernel_thread(fn, arg, flags)
index 3d2106b022a11f1376947255374278e2b6d30fcb..30247ff74972d3ef3a4048b3baca0d24141e5420 100644 (file)
@@ -295,8 +295,8 @@ static void pci_parse_of_addrs(struct device_node *node, struct pci_dev *dev)
        }
 }
 
-static struct pci_dev *of_create_pci_dev(struct device_node *node,
-                                        struct pci_bus *bus, int devfn)
+struct pci_dev *of_create_pci_dev(struct device_node *node,
+                                struct pci_bus *bus, int devfn)
 {
        struct pci_dev *dev;
        const char *type;
@@ -354,10 +354,9 @@ static struct pci_dev *of_create_pci_dev(struct device_node *node,
 
        return dev;
 }
+EXPORT_SYMBOL(of_create_pci_dev);
 
-static void of_scan_pci_bridge(struct device_node *node, struct pci_dev *dev);
-
-static void __devinit of_scan_bus(struct device_node *node,
+void __devinit of_scan_bus(struct device_node *node,
                                  struct pci_bus *bus)
 {
        struct device_node *child = NULL;
@@ -381,9 +380,10 @@ static void __devinit of_scan_bus(struct device_node *node,
 
        do_bus_setup(bus);
 }
+EXPORT_SYMBOL(of_scan_bus);
 
-static void __devinit of_scan_pci_bridge(struct device_node *node,
-                                        struct pci_dev *dev)
+void __devinit of_scan_pci_bridge(struct device_node *node,
+                               struct pci_dev *dev)
 {
        struct pci_bus *bus;
        u32 *busrange, *ranges;
@@ -464,9 +464,10 @@ static void __devinit of_scan_pci_bridge(struct device_node *node,
        else if (mode == PCI_PROBE_NORMAL)
                pci_scan_child_bus(bus);
 }
+EXPORT_SYMBOL(of_scan_pci_bridge);
 #endif /* CONFIG_PPC_MULTIPLATFORM */
 
-static void __devinit scan_phb(struct pci_controller *hose)
+void __devinit scan_phb(struct pci_controller *hose)
 {
        struct pci_bus *bus;
        struct device_node *node = hose->arch_data;
index dece31e58bc4b69c4cf8aaf4a05be977584d65cc..3402fbee62c74af1faf5ccd7013afc4199c4ce2b 100644 (file)
@@ -31,6 +31,7 @@
 #include <linux/initrd.h>
 #include <linux/bitops.h>
 #include <linux/module.h>
+#include <linux/module.h>
 
 #include <asm/prom.h>
 #include <asm/rtas.h>
@@ -46,7 +47,6 @@
 #include <asm/pgtable.h>
 #include <asm/pci.h>
 #include <asm/iommu.h>
-#include <asm/ppcdebug.h>
 #include <asm/btext.h>
 #include <asm/sections.h>
 #include <asm/machdep.h>
@@ -1866,17 +1866,32 @@ get_property(struct device_node *np, const char *name, int *lenp)
 EXPORT_SYMBOL(get_property);
 
 /*
- * Add a property to a node
+ * Add a property to a node.
  */
-void
+int
 prom_add_property(struct device_node* np, struct property* prop)
 {
-       struct property **next = &np->properties;
+       struct property **next;
 
        prop->next = NULL;      
-       while (*next)
+       write_lock(&devtree_lock);
+       next = &np->properties;
+       while (*next) {
+               if (strcmp(prop->name, (*next)->name) == 0) {
+                       /* duplicate ! don't insert it */
+                       write_unlock(&devtree_lock);
+                       return -1;
+               }
                next = &(*next)->next;
+       }
        *next = prop;
+       write_unlock(&devtree_lock);
+
+       /* try to add to proc as well if it was initialized */
+       if (np->pde)
+               proc_device_tree_add_prop(np->pde, prop);
+
+       return 0;
 }
 
 #if 0
index a4bbca6dbb8b4624f01d150840ebeff031f0860b..e4c880dab997bf9cc7baeb33efe3cd54bcca22fc 100644 (file)
@@ -44,7 +44,6 @@
 #include <asm/pgtable.h>
 #include <asm/pci.h>
 #include <asm/iommu.h>
-#include <asm/ppcdebug.h>
 #include <asm/btext.h>
 #include <asm/sections.h>
 #include <asm/machdep.h>
@@ -1825,7 +1824,7 @@ static void __init fixup_device_tree(void)
        if (prom_getprop(u3, "device-rev", &u3_rev, sizeof(u3_rev))
            == PROM_ERROR)
                return;
-       if (u3_rev != 0x35 && u3_rev != 0x37)
+       if (u3_rev < 0x35 || u3_rev > 0x39)
                return;
        /* does it need fixup ? */
        if (prom_getproplen(i2c, "interrupts") > 0)
index 3ad15c90fbbd29f55017735666719c96e79a561c..3c3f19192fcc9e164feab51b342e4d4344c94047 100644 (file)
@@ -440,7 +440,6 @@ struct pci_controller * __devinit init_phb_dynamic(struct device_node *dn)
        struct device_node *root = of_find_node_by_path("/");
        unsigned int root_size_cells = 0;
        struct pci_controller *phb;
-       struct pci_bus *bus;
        int primary;
 
        root_size_cells = prom_n_size_cells(root);
@@ -456,10 +455,7 @@ struct pci_controller * __devinit init_phb_dynamic(struct device_node *dn)
        of_node_put(root);
 
        pci_devs_phb_init_dynamic(phb);
-       phb->last_busno = 0xff;
-       bus = pci_scan_bus(phb->first_busno, phb->ops, phb->arch_data);
-       phb->bus = bus;
-       phb->last_busno = bus->subordinate;
+       scan_phb(phb);
 
        return phb;
 }
index d49c3613c8ece531898535748256ec5af39796bb..0d878e72fc449257623c78a778434becd0aa6eda 100644 (file)
  */
 
 #include <stdarg.h>
-#define WANT_PPCDBG_TAB /* Only defined here */
 #include <linux/config.h>
 #include <linux/types.h>
 #include <linux/sched.h>
 #include <linux/console.h>
-#include <asm/ppcdebug.h>
 #include <asm/processor.h>
 
 void (*udbg_putc)(unsigned char c);
@@ -89,59 +87,6 @@ void udbg_printf(const char *fmt, ...)
        va_end(args);
 }
 
-/* PPCDBG stuff */
-
-u64 ppc64_debug_switch;
-
-/* Special print used by PPCDBG() macro */
-void udbg_ppcdbg(unsigned long debug_flags, const char *fmt, ...)
-{
-       unsigned long active_debugs = debug_flags & ppc64_debug_switch;
-
-       if (active_debugs) {
-               va_list ap;
-               unsigned char buf[UDBG_BUFSIZE];
-               unsigned long i, len = 0;
-
-               for (i=0; i < PPCDBG_NUM_FLAGS; i++) {
-                       if (((1U << i) & active_debugs) && 
-                           trace_names[i]) {
-                               len += strlen(trace_names[i]); 
-                               udbg_puts(trace_names[i]);
-                               break;
-                       }
-               }
-
-               snprintf(buf, UDBG_BUFSIZE, " [%s]: ", current->comm);
-               len += strlen(buf); 
-               udbg_puts(buf);
-
-               while (len < 18) {
-                       udbg_puts(" ");
-                       len++;
-               }
-
-               va_start(ap, fmt);
-               vsnprintf(buf, UDBG_BUFSIZE, fmt, ap);
-               udbg_puts(buf);
-               va_end(ap);
-       }
-}
-
-unsigned long udbg_ifdebug(unsigned long flags)
-{
-       return (flags & ppc64_debug_switch);
-}
-
-/*
- * Initialize the PPCDBG state.  Called before relocation has been enabled.
- */
-void __init ppcdbg_initialize(void)
-{
-       ppc64_debug_switch = PPC_DEBUG_DEFAULT; /* | PPCDBG_BUSWALK | */
-       /* PPCDBG_PHBINIT | PPCDBG_MM | PPCDBG_MMINIT | PPCDBG_TCEINIT | PPCDBG_TCE */;
-}
-
 /*
  * Early boot console based on udbg
  */
index c9f2f60cfa5808929e9d4515d709cad7f726a5c6..dee6ab54984d03d6358a54476191aa18fb2ee05d 100644 (file)
@@ -592,12 +592,15 @@ int appldata_register_ops(struct appldata_ops *ops)
  */
 void appldata_unregister_ops(struct appldata_ops *ops)
 {
+       void *table;
        spin_lock(&appldata_ops_lock);
-       unregister_sysctl_table(ops->sysctl_header);
        list_del(&ops->list);
-       kfree(ops->ctl_table);
+       /* at that point any incoming access will fail */
+       table = ops->ctl_table;
        ops->ctl_table = NULL;
        spin_unlock(&appldata_ops_lock);
+       unregister_sysctl_table(ops->sysctl_header);
+       kfree(table);
        P_INFO("%s-ops unregistered!\n", ops->name);
 }
 /********************** module-ops management <END> **************************/
index bc59282da7620408fd98aec3b8e3b643759e47e0..896d39d0e4ce4b5d17587107093b0669b7d1a396 100644 (file)
@@ -486,7 +486,7 @@ out:
  * - goto next entry in p_info
  */
 
-extern inline int
+static inline int
 debug_next_entry(file_private_info_t *p_info)
 {
        debug_info_t *id;
@@ -800,7 +800,7 @@ debug_set_level(debug_info_t* id, int new_level)
  * - set active entry to next in the ring buffer
  */
 
-extern inline void
+static inline void
 proceed_active_entry(debug_info_t * id)
 {
        if ((id->active_entries[id->active_area] += id->entry_size)
@@ -817,7 +817,7 @@ proceed_active_entry(debug_info_t * id)
  * - set active area to next in the ring buffer
  */
 
-extern inline void
+static inline void
 proceed_active_area(debug_info_t * id)
 {
        id->active_area++;
@@ -828,7 +828,7 @@ proceed_active_area(debug_info_t * id)
  * get_active_entry:
  */
 
-extern inline debug_entry_t*
+static inline debug_entry_t*
 get_active_entry(debug_info_t * id)
 {
        return (debug_entry_t *) (((char *) id->areas[id->active_area]
@@ -841,7 +841,7 @@ get_active_entry(debug_info_t * id)
  * - set timestamp, caller address, cpu number etc.
  */
 
-extern inline void
+static inline void
 debug_finish_entry(debug_info_t * id, debug_entry_t* active, int level,
                        int exception)
 {
@@ -971,7 +971,7 @@ debug_entry_t
  * counts arguments in format string for sprintf view
  */
 
-extern inline int
+static inline int
 debug_count_numargs(char *string)
 {
        int numargs=0;
index 9f3dff6c0b72286a7c769787dcb0d9046bc29d93..78b64fe5e7c236ddaf53aba506bd44ea8c59f579 100644 (file)
@@ -99,15 +99,15 @@ void default_idle(void)
 {
        int cpu, rc;
 
+       /* CPU is going idle. */
+       cpu = smp_processor_id();
+
        local_irq_disable();
-        if (need_resched()) {
+       if (need_resched()) {
                local_irq_enable();
-                schedule();
-                return;
-        }
+               return;
+       }
 
-       /* CPU is going idle. */
-       cpu = smp_processor_id();
        rc = notifier_call_chain(&idle_chain, CPU_IDLE, (void *)(long) cpu);
        if (rc != NOTIFY_OK && rc != NOTIFY_DONE)
                BUG();
@@ -120,7 +120,7 @@ void default_idle(void)
        __ctl_set_bit(8, 15);
 
 #ifdef CONFIG_HOTPLUG_CPU
-       if (cpu_is_offline(smp_processor_id()))
+       if (cpu_is_offline(cpu))
                cpu_die();
 #endif
 
@@ -139,8 +139,14 @@ void default_idle(void)
 
 void cpu_idle(void)
 {
-       for (;;)
-               default_idle();
+       for (;;) {
+               while (!need_resched())
+                       default_idle();
+
+               preempt_enable_no_resched();
+               schedule();
+               preempt_disable();
+       }
 }
 
 void show_regs(struct pt_regs *regs)
index e13c87b446b2e58051797dbe88b25d930fa5376a..5856b3fda6bfeabf598a94f42d17c1abb311691d 100644 (file)
@@ -533,6 +533,7 @@ int __devinit start_secondary(void *cpuvoid)
 {
         /* Setup the cpu */
         cpu_init();
+       preempt_disable();
         /* init per CPU timer */
         init_cpu_timer();
 #ifdef CONFIG_VIRT_TIMER
index 64e32da777541b69f053d18ec7a3508b0ea40c0b..fb2607c369edf323fe7ace88dd6817263a0b28fc 100644 (file)
@@ -160,7 +160,7 @@ static void do_sigsegv(struct pt_regs *regs, unsigned long error_code,
  *   11       Page translation     ->  Not present       (nullification)
  *   3b       Region third trans.  ->  Not present       (nullification)
  */
-extern inline void
+static inline void
 do_exception(struct pt_regs *regs, unsigned long error_code, int is_protection)
 {
         struct task_struct *tsk;
index 6dce9d0b81f8b8d53d4ac78378e4af0c5cbd82db..fd4f240b833d5fc55af05e6de0520eaf9847d248 100644 (file)
@@ -51,28 +51,24 @@ void enable_hlt(void)
 
 EXPORT_SYMBOL(enable_hlt);
 
-void default_idle(void)
+void cpu_idle(void)
 {
        /* endless idle loop with no priority at all */
        while (1) {
                if (hlt_counter) {
-                       while (1)
-                               if (need_resched())
-                                       break;
+                       while (!need_resched())
+                               cpu_relax();
                } else {
                        while (!need_resched())
                                cpu_sleep();
                }
 
+               preempt_enable_no_resched();
                schedule();
+               preempt_disable();
        }
 }
 
-void cpu_idle(void)
-{
-       default_idle();
-}
-
 void machine_restart(char * __unused)
 {
        /* SR.BL=1 and invoke address error to let CPU reset (manual reset) */
index 5ecefc02896a3a07e030a3013b0023da96c15e9e..59e49b18252c47ff49e3b4790c0c0a7ab8a9a883 100644 (file)
@@ -112,7 +112,9 @@ int __cpu_up(unsigned int cpu)
 
 int start_secondary(void *unused)
 {
-       unsigned int cpu = smp_processor_id();
+       unsigned int cpu;
+
+       cpu = smp_processor_id();
 
        atomic_inc(&init_mm.mm_count);
        current->active_mm = &init_mm;
@@ -120,6 +122,7 @@ int start_secondary(void *unused)
        smp_store_cpu_info(cpu);
 
        __smp_slave_init(cpu);
+       preempt_disable();
        per_cpu_trap_init();
        
        atomic_inc(&cpus_booted);
index efde41c0cd669388142dcb58dd7c87f5818e2d58..b95d041418554196350b64096a7486e1a7d6a4cb 100644 (file)
@@ -307,23 +307,19 @@ __setup("hlt", hlt_setup);
 
 static inline void hlt(void)
 {
-       if (hlt_counter)
-               return;
-
        __asm__ __volatile__ ("sleep" : : : "memory");
 }
 
 /*
  * The idle loop on a uniprocessor SH..
  */
-void default_idle(void)
+void cpu_idle(void)
 {
        /* endless idle loop with no priority at all */
        while (1) {
                if (hlt_counter) {
-                       while (1)
-                               if (need_resched())
-                                       break;
+                       while (!need_resched())
+                               cpu_relax();
                } else {
                        local_irq_disable();
                        while (!need_resched()) {
@@ -334,13 +330,11 @@ void default_idle(void)
                        }
                        local_irq_enable();
                }
+               preempt_enable_no_resched();
                schedule();
+               preempt_disable();
        }
-}
 
-void cpu_idle(void)
-{
-       default_idle();
 }
 
 void machine_restart(char * __unused)
index 29e72b57d4fd2cee97e6e9bc8b8ed63812c448f5..ea86474114627f267d739def93a6c33d2b4c9c4d 100644 (file)
@@ -67,13 +67,6 @@ extern void fpsave(unsigned long *, unsigned long *, void *, unsigned long *);
 struct task_struct *last_task_used_math = NULL;
 struct thread_info *current_set[NR_CPUS];
 
-/*
- * default_idle is new in 2.5. XXX Review, currently stolen from sparc64.
- */
-void default_idle(void)
-{
-}
-
 #ifndef CONFIG_SMP
 
 #define SUN4C_FAULT_HIGH 100
@@ -92,12 +85,11 @@ void cpu_idle(void)
                        static unsigned long fps;
                        unsigned long now;
                        unsigned long faults;
-                       unsigned long flags;
 
                        extern unsigned long sun4c_kernel_faults;
                        extern void sun4c_grow_kernel_ring(void);
 
-                       local_irq_save(flags);
+                       local_irq_disable();
                        now = jiffies;
                        count -= (now - last_jiffies);
                        last_jiffies = now;
@@ -113,14 +105,19 @@ void cpu_idle(void)
                                        sun4c_grow_kernel_ring();
                                }
                        }
-                       local_irq_restore(flags);
+                       local_irq_enable();
                }
 
-               while((!need_resched()) && pm_idle) {
-                       (*pm_idle)();
+               if (pm_idle) {
+                       while (!need_resched())
+                               (*pm_idle)();
+               } else {
+                       while (!need_resched())
+                               cpu_relax();
                }
-
+               preempt_enable_no_resched();
                schedule();
+               preempt_disable();
                check_pgt_cache();
        }
 }
@@ -130,13 +127,15 @@ void cpu_idle(void)
 /* This is being executed in task 0 'user space'. */
 void cpu_idle(void)
 {
+        set_thread_flag(TIF_POLLING_NRFLAG);
        /* endless idle loop with no priority at all */
        while(1) {
-               if(need_resched()) {
-                       schedule();
-                       check_pgt_cache();
-               }
-               barrier(); /* or else gcc optimizes... */
+               while (!need_resched())
+                       cpu_relax();
+               preempt_enable_no_resched();
+               schedule();
+               preempt_disable();
+               check_pgt_cache();
        }
 }
 
index 92e26304de90b76fe87bdaf091f197503983ba7a..c2e96daa5ab30767ef3915205ed4c8a77d7a8af8 100644 (file)
@@ -92,10 +92,8 @@ static int fbiogscursor(unsigned int fd, unsigned int cmd, unsigned long arg)
        return sys_ioctl (fd, FBIOSCURSOR, (unsigned long)p);
 }
 
-typedef int (* ioctl32_handler_t)(unsigned int, unsigned int, unsigned long, struct file *);
-
 #define COMPATIBLE_IOCTL(cmd)          HANDLE_IOCTL((cmd),sys_ioctl)
-#define HANDLE_IOCTL(cmd,handler)      { (cmd), (ioctl32_handler_t)(handler), NULL },
+#define HANDLE_IOCTL(cmd,handler)      { (cmd), (ioctl_trans_handler_t)(handler), NULL },
 #define IOCTL_TABLE_START \
        struct ioctl_trans ioctl_start[] = {
 #define IOCTL_TABLE_END \
index 7d10b03970919c63b6d1c1dd138b203f6fa42568..02f9dec1d459d79731a8d32658db102940cce2cc 100644 (file)
@@ -74,7 +74,9 @@ void cpu_idle(void)
                while (!need_resched())
                        barrier();
 
+               preempt_enable_no_resched();
                schedule();
+               preempt_disable();
                check_pgt_cache();
        }
 }
@@ -83,21 +85,31 @@ void cpu_idle(void)
 
 /*
  * the idle loop on a UltraMultiPenguin...
+ *
+ * TIF_POLLING_NRFLAG is set because we do not sleep the cpu
+ * inside of the idler task, so an interrupt is not needed
+ * to get a clean fast response.
+ *
+ * XXX Reverify this assumption... -DaveM
+ *
+ * Addendum: We do want it to do something for the signal
+ *           delivery case, we detect that by just seeing
+ *           if we are trying to send this to an idler or not.
  */
-#define idle_me_harder()       (cpu_data(smp_processor_id()).idle_volume += 1)
-#define unidle_me()            (cpu_data(smp_processor_id()).idle_volume = 0)
 void cpu_idle(void)
 {
+       cpuinfo_sparc *cpuinfo = &local_cpu_data();
        set_thread_flag(TIF_POLLING_NRFLAG);
+
        while(1) {
                if (need_resched()) {
-                       unidle_me();
-                       clear_thread_flag(TIF_POLLING_NRFLAG);
+                       cpuinfo->idle_volume = 0;
+                       preempt_enable_no_resched();
                        schedule();
-                       set_thread_flag(TIF_POLLING_NRFLAG);
+                       preempt_disable();
                        check_pgt_cache();
                }
-               idle_me_harder();
+               cpuinfo->idle_volume++;
 
                /* The store ordering is so that IRQ handlers on
                 * other cpus see our increasing idleness for the buddy
index 5d90ee9aebf1a29eb1d18e165b73551875b9c584..797a65493fb848cc836ca4248171e19149f42bc3 100644 (file)
@@ -168,6 +168,9 @@ void __init smp_callin(void)
                rmb();
 
        cpu_set(cpuid, cpu_online_map);
+
+       /* idle thread is expected to have preempt disabled */
+       preempt_disable();
 }
 
 void cpu_panic(void)
@@ -1149,20 +1152,9 @@ void __init smp_cpus_done(unsigned int max_cpus)
               (bogosum/(5000/HZ))%100);
 }
 
-/* This needn't do anything as we do not sleep the cpu
- * inside of the idler task, so an interrupt is not needed
- * to get a clean fast response.
- *
- * XXX Reverify this assumption... -DaveM
- *
- * Addendum: We do want it to do something for the signal
- *           delivery case, we detect that by just seeing
- *           if we are trying to send this to an idler or not.
- */
 void smp_send_reschedule(int cpu)
 {
-       if (cpu_data(cpu).idle_volume == 0)
-               smp_receive_signal(cpu);
+       smp_receive_signal(cpu);
 }
 
 /* This is a nop because we capture all other cpus
index 31fbc67719a1f653f643c346615a261173541a98..3be278d916dbcaeb679fafdefc3f03cb01a78c16 100644 (file)
@@ -109,7 +109,7 @@ static void bad_kernel_pc(struct pt_regs *regs)
  * this. Additionally, to prevent kswapd from ripping ptes from
  * under us, raise interrupts around the time that we look at the
  * pte, kswapd will have to wait to get his smp ipi response from
- * us. This saves us having to get page_table_lock.
+ * us. vmtruncate likewise. This saves us having to get pte lock.
  */
 static unsigned int get_user_insn(unsigned long tpc)
 {
index 9c708c32c1f077bd9f51aa99cd8a4b88d9fe3f22..39cf247cdae4ef4dcbe4d4fa3563432a520f1531 100644 (file)
@@ -36,11 +36,8 @@ extern void ret_from_fork (void);
 /* The idle loop.  */
 void default_idle (void)
 {
-       while (1) {
-               while (! need_resched ())
-                       asm ("halt; nop; nop; nop; nop; nop" ::: "cc");
-               schedule ();
-       }
+       while (! need_resched ())
+               asm ("halt; nop; nop; nop; nop; nop" ::: "cc");
 }
 
 void (*idle)(void) = default_idle;
@@ -54,7 +51,14 @@ void (*idle)(void) = default_idle;
 void cpu_idle (void)
 {
        /* endless idle loop with no priority at all */
-       (*idle) ();
+       while (1) {
+               while (!need_resched())
+                       (*idle) ();
+
+               preempt_enable_no_resched();
+               schedule();
+               preempt_disable();
+       }
 }
 
 /*
index 4ba0e293d5e5faccdcf8362521c4c15649ac096f..e335bd0b637d705a4c73e28f6c773340617da072 100644 (file)
@@ -64,12 +64,6 @@ struct ioctl_trans ioctl_start[] = {
 #include <linux/compat_ioctl.h>
 #define DECLARES
 #include "compat_ioctl.c"
-COMPATIBLE_IOCTL(HDIO_SET_KEEPSETTINGS)
-COMPATIBLE_IOCTL(HDIO_SCAN_HWIF)
-COMPATIBLE_IOCTL(BLKRASET)
-COMPATIBLE_IOCTL(0x4B50)   /* KDGHWCLK - not in the kernel, but don't complain */
-COMPATIBLE_IOCTL(0x4B51)   /* KDSHWCLK - not in the kernel, but don't complain */
-COMPATIBLE_IOCTL(FIOQSIZE)
 
 /* And these ioctls need translation */
 /* realtime device */
index b5a89c0bdf5914851fe32710b0b808587dfb6c32..59be85d9a4bc166284ac102aea770d52c77a69cf 100644 (file)
@@ -86,12 +86,22 @@ EXPORT_SYMBOL(enable_hlt);
  */
 void default_idle(void)
 {
+       local_irq_enable();
+
        if (!atomic_read(&hlt_counter)) {
-               local_irq_disable();
-               if (!need_resched())
-                       safe_halt();
-               else
-                       local_irq_enable();
+               clear_thread_flag(TIF_POLLING_NRFLAG);
+               smp_mb__after_clear_bit();
+               while (!need_resched()) {
+                       local_irq_disable();
+                       if (!need_resched())
+                               safe_halt();
+                       else
+                               local_irq_enable();
+               }
+               set_thread_flag(TIF_POLLING_NRFLAG);
+       } else {
+               while (!need_resched())
+                       cpu_relax();
        }
 }
 
@@ -102,30 +112,16 @@ void default_idle(void)
  */
 static void poll_idle (void)
 {
-       int oldval;
-
        local_irq_enable();
 
-       /*
-        * Deal with another CPU just having chosen a thread to
-        * run here:
-        */
-       oldval = test_and_clear_thread_flag(TIF_NEED_RESCHED);
-
-       if (!oldval) {
-               set_thread_flag(TIF_POLLING_NRFLAG); 
-               asm volatile(
-                       "2:"
-                       "testl %0,%1;"
-                       "rep; nop;"
-                       "je 2b;"
-                       : :
-                       "i" (_TIF_NEED_RESCHED), 
-                       "m" (current_thread_info()->flags));
-               clear_thread_flag(TIF_POLLING_NRFLAG);
-       } else {
-               set_need_resched();
-       }
+       asm volatile(
+               "2:"
+               "testl %0,%1;"
+               "rep; nop;"
+               "je 2b;"
+               : :
+               "i" (_TIF_NEED_RESCHED),
+               "m" (current_thread_info()->flags));
 }
 
 void cpu_idle_wait(void)
@@ -187,6 +183,8 @@ static inline void play_dead(void)
  */
 void cpu_idle (void)
 {
+       set_thread_flag(TIF_POLLING_NRFLAG);
+
        /* endless idle loop with no priority at all */
        while (1) {
                while (!need_resched()) {
@@ -204,7 +202,9 @@ void cpu_idle (void)
                        idle();
                }
 
+               preempt_enable_no_resched();
                schedule();
+               preempt_disable();
        }
 }
 
@@ -219,15 +219,12 @@ static void mwait_idle(void)
 {
        local_irq_enable();
 
-       if (!need_resched()) {
-               set_thread_flag(TIF_POLLING_NRFLAG);
-               do {
-                       __monitor((void *)&current_thread_info()->flags, 0, 0);
-                       if (need_resched())
-                               break;
-                       __mwait(0, 0);
-               } while (!need_resched());
-               clear_thread_flag(TIF_POLLING_NRFLAG);
+       while (!need_resched()) {
+               __monitor((void *)&current_thread_info()->flags, 0, 0);
+               smp_mb();
+               if (need_resched())
+                       break;
+               __mwait(0, 0);
        }
 }
 
index 4b5b088ec1022a5d28c6e0e2dae76df9c4eed785..c4e59bbdc1872b4ce599f452b125183603cf8f8e 100644 (file)
@@ -472,6 +472,7 @@ void __cpuinit start_secondary(void)
         * things done here to the most necessary things.
         */
        cpu_init();
+       preempt_disable();
        smp_callin();
 
        /* otherwise gcc will move up the smp_processor_id before the cpu_init */
index 08ef6d82ee5144d1e30d98195a9d91de57af5806..6a44b54ae8173718b8e4a50518511e4777a43392 100644 (file)
@@ -96,8 +96,9 @@ void cpu_idle(void)
        while (1) {
                while (!need_resched())
                        platform_idle();
-               preempt_enable();
+               preempt_enable_no_resched();
                schedule();
+               preempt_disable();
        }
 }
 
index 161db4acfb91de2d26ddbde096688de93322f93c..573b6a97bb1f9276f79ad3090c67027047a7549b 100644 (file)
@@ -167,6 +167,19 @@ acpi_processor_power_activate(struct acpi_processor *pr,
        return;
 }
 
+static void acpi_safe_halt(void)
+{
+       int polling = test_thread_flag(TIF_POLLING_NRFLAG);
+       if (polling) {
+               clear_thread_flag(TIF_POLLING_NRFLAG);
+               smp_mb__after_clear_bit();
+       }
+       if (!need_resched())
+               safe_halt();
+       if (polling)
+               set_thread_flag(TIF_POLLING_NRFLAG);
+}
+
 static atomic_t c3_cpu_count;
 
 static void acpi_processor_idle(void)
@@ -177,7 +190,7 @@ static void acpi_processor_idle(void)
        int sleep_ticks = 0;
        u32 t1, t2 = 0;
 
-       pr = processors[raw_smp_processor_id()];
+       pr = processors[smp_processor_id()];
        if (!pr)
                return;
 
@@ -197,8 +210,13 @@ static void acpi_processor_idle(void)
        }
 
        cx = pr->power.state;
-       if (!cx)
-               goto easy_out;
+       if (!cx) {
+               if (pm_idle_save)
+                       pm_idle_save();
+               else
+                       acpi_safe_halt();
+               return;
+       }
 
        /*
         * Check BM Activity
@@ -278,7 +296,8 @@ static void acpi_processor_idle(void)
                if (pm_idle_save)
                        pm_idle_save();
                else
-                       safe_halt();
+                       acpi_safe_halt();
+
                /*
                 * TBD: Can't get time duration while in C1, as resumes
                 *      go to an ISR rather than here.  Need to instrument
@@ -414,16 +433,6 @@ static void acpi_processor_idle(void)
         */
        if (next_state != pr->power.state)
                acpi_processor_power_activate(pr, next_state);
-
-       return;
-
-      easy_out:
-       /* do C1 instead of busy loop */
-       if (pm_idle_save)
-               pm_idle_save();
-       else
-               safe_halt();
-       return;
 }
 
 static int acpi_processor_set_power_policy(struct acpi_processor *pr)
index 1468e8cf712d501ec69ca8aea740e8567776b50d..0acbfff8ad284ecb0d7adb7c57f32787f6e071c2 100644 (file)
@@ -1816,7 +1816,6 @@ out_blkdev:
 }
 
 #ifdef MODULE
-#include <linux/version.h>
 
 int init_module(void)
 {
index 5eadbb9d4d71afdff8d74ae5e5e4f5b00c05a996..28002de783b62cabd88e2c779501afda5a2d7dd9 100644 (file)
@@ -3714,6 +3714,12 @@ static int floppy_open(struct inode *inode, struct file *filp)
                USETF(FD_VERIFY);
        }
 
+       /* set underlying gendisk policy to reflect real ro/rw status */
+       if (UTESTF(FD_DISK_WRITABLE))
+               inode->i_bdev->bd_disk->policy = 0;
+       else
+               inode->i_bdev->bd_disk->policy = 1;
+
        if (UDRS->fd_ref == -1 || (UDRS->fd_ref && (filp->f_flags & O_EXCL)))
                goto out2;
 
@@ -3770,8 +3776,7 @@ static int floppy_open(struct inode *inode, struct file *filp)
        /* Allow ioctls if we have write-permissions even if read-only open.
         * Needed so that programs such as fdrawcmd still can work on write
         * protected disks */
-       if (filp->f_mode & 2
-           || permission(filp->f_dentry->d_inode, 2, NULL) == 0)
+       if ((filp->f_mode & FMODE_WRITE) || !file_permission(filp, MAY_WRITE))
                filp->private_data = (void *)8;
 
        if (UFDCS->rawcmd == 1)
index a280e679b1cad14b256db0b7b5d747bd2b76662d..59e5982a5db35bb0b2c18a2ebe6ca7870bd71b67 100644 (file)
@@ -511,14 +511,11 @@ static void pkt_queue_bio(struct pktcdvd_device *pd, struct bio *bio)
  */
 static void pkt_iosched_process_queue(struct pktcdvd_device *pd)
 {
-       request_queue_t *q;
 
        if (atomic_read(&pd->iosched.attention) == 0)
                return;
        atomic_set(&pd->iosched.attention, 0);
 
-       q = bdev_get_queue(pd->bdev);
-
        for (;;) {
                struct bio *bio;
                int reads_queued, writes_queued;
index e425ad3eebba80618be8c56f6282f9ed99bad740..af7cb2bfd67051d02b568fed8b24e3aea3e8e44b 100644 (file)
@@ -28,6 +28,7 @@
 #include <linux/devfs_fs_kernel.h>
 #include <linux/interrupt.h>
 #include <linux/module.h>
+#include <linux/spinlock.h>
 #include <asm/io.h>
 #include <asm/dbdma.h>
 #include <asm/prom.h>
@@ -176,6 +177,7 @@ struct swim3 {
 
 struct floppy_state {
        enum swim_state state;
+       spinlock_t lock;
        struct swim3 __iomem *swim3;    /* hardware registers */
        struct dbdma_regs __iomem *dma; /* DMA controller registers */
        int     swim3_intr;     /* interrupt number for SWIM3 */
@@ -304,7 +306,6 @@ static void do_fd_request(request_queue_t * q)
 #endif /* CONFIG_PMAC_MEDIABAY */
                start_request(&floppy_states[i]);
        }
-       sti();
 }
 
 static void start_request(struct floppy_state *fs)
@@ -370,7 +371,7 @@ static void set_timeout(struct floppy_state *fs, int nticks,
 {
        unsigned long flags;
 
-       save_flags(flags); cli();
+       spin_lock_irqsave(&fs->lock, flags);
        if (fs->timeout_pending)
                del_timer(&fs->timeout);
        fs->timeout.expires = jiffies + nticks;
@@ -378,7 +379,7 @@ static void set_timeout(struct floppy_state *fs, int nticks,
        fs->timeout.data = (unsigned long) fs;
        add_timer(&fs->timeout);
        fs->timeout_pending = 1;
-       restore_flags(flags);
+       spin_unlock_irqrestore(&fs->lock, flags);
 }
 
 static inline void scan_track(struct floppy_state *fs)
@@ -790,14 +791,13 @@ static int grab_drive(struct floppy_state *fs, enum swim_state state,
 {
        unsigned long flags;
 
-       save_flags(flags);
-       cli();
+       spin_lock_irqsave(&fs->lock, flags);
        if (fs->state != idle) {
                ++fs->wanted;
                while (fs->state != available) {
                        if (interruptible && signal_pending(current)) {
                                --fs->wanted;
-                               restore_flags(flags);
+                               spin_unlock_irqrestore(&fs->lock, flags);
                                return -EINTR;
                        }
                        interruptible_sleep_on(&fs->wait);
@@ -805,7 +805,7 @@ static int grab_drive(struct floppy_state *fs, enum swim_state state,
                --fs->wanted;
        }
        fs->state = state;
-       restore_flags(flags);
+       spin_unlock_irqrestore(&fs->lock, flags);
        return 0;
 }
 
@@ -813,11 +813,10 @@ static void release_drive(struct floppy_state *fs)
 {
        unsigned long flags;
 
-       save_flags(flags);
-       cli();
+       spin_lock_irqsave(&fs->lock, flags);
        fs->state = idle;
        start_request(fs);
-       restore_flags(flags);
+       spin_unlock_irqrestore(&fs->lock, flags);
 }
 
 static int fd_eject(struct floppy_state *fs)
@@ -1109,6 +1108,7 @@ static int swim3_add_device(struct device_node *swim)
                pmac_call_feature(PMAC_FTR_SWIM3_ENABLE, swim, 0, 1);
        
        memset(fs, 0, sizeof(*fs));
+       spin_lock_init(&fs->lock);
        fs->state = idle;
        fs->swim3 = (struct swim3 __iomem *)
                ioremap(swim->addrs[0].address, 0x200);
index ecbeb7eaba8e25c3c45ee0a8de1cd8163a8446b8..394796315adcb18decd1ca61d13b62e1aae4ffe6 100644 (file)
@@ -84,8 +84,8 @@ struct bpa10x_data {
 
 struct hci_vendor_hdr {
        __u8    type;
-       __u16   snum;
-       __u16   dlen;
+       __le16  snum;
+       __le16  dlen;
 } __attribute__ ((packed));
 
 static void bpa10x_recv_bulk(struct bpa10x_data *data, unsigned char *buf, int count)
index f510b25b2c59010c0967e4488eebccbeaee994cc..057cb2b6e6d1f537723051c122eca2d59fec0c82 100644 (file)
@@ -65,6 +65,7 @@
 #endif
 
 static int ignore = 0;
+static int ignore_dga = 0;
 static int ignore_csr = 0;
 static int ignore_sniffer = 0;
 static int reset = 0;
@@ -841,6 +842,9 @@ static int hci_usb_probe(struct usb_interface *intf, const struct usb_device_id
        if (ignore || id->driver_info & HCI_IGNORE)
                return -ENODEV;
 
+       if (ignore_dga && id->driver_info & HCI_DIGIANSWER)
+               return -ENODEV;
+
        if (ignore_csr && id->driver_info & HCI_CSR)
                return -ENODEV;
 
@@ -1070,6 +1074,9 @@ module_exit(hci_usb_exit);
 module_param(ignore, bool, 0644);
 MODULE_PARM_DESC(ignore, "Ignore devices from the matching table");
 
+module_param(ignore_dga, bool, 0644);
+MODULE_PARM_DESC(ignore_dga, "Ignore devices with id 08fd:0001");
+
 module_param(ignore_csr, bool, 0644);
 MODULE_PARM_DESC(ignore_csr, "Ignore devices with id 0a12:0001");
 
index 6d3fec160bffb1841db17a38f86abca07cc5d6e1..efff0eec618c23c28fc78c1eb55dfe409cb7730c 100644 (file)
@@ -203,10 +203,10 @@ int drm_ati_pcigart_init(drm_device_t * dev, drm_ati_pcigart_info * gart_info)
 
                for (j = 0; j < (PAGE_SIZE / ATI_PCIGART_PAGE_SIZE); j++) {
                        if (gart_info->is_pcie)
-                               *pci_gart = (cpu_to_le32(page_base) >> 8) | 0xc;
+                               *pci_gart = cpu_to_le32((page_base >> 8) | 0xc);
                        else
                                *pci_gart = cpu_to_le32(page_base);
-                       *pci_gart++;
+                       pci_gart++;
                        page_base += ATI_PCIGART_PAGE_SIZE;
                }
        }
index 6cd12f23aa58b6f078ebdec185e8ba57019beb3e..7cadfc6ef35283bce433a7204960b70de43b622e 100644 (file)
@@ -7,7 +7,6 @@
 //
 
 #include <linux/module.h>
-#include <linux/version.h>
 #include <linux/init.h>
 #include <linux/wait.h>
 
index d6c72e0934e23e7bb805ebf852679d09155a6c3d..cc3e54dd72346735b0d0ec96bb873547a0545e99 100644 (file)
@@ -46,7 +46,6 @@
 *      First release to the public
 */
 
-#include <linux/version.h>
 #include <linux/interrupt.h>
 #include <linux/kernel.h>
 #include <linux/ptrace.h>
index 3b965a651da4352cf91b91ca6f9a11fd7663929c..26448f176803e1b551fd21e8689d76911a400b48 100644 (file)
@@ -38,7 +38,6 @@
 
 #include <linux/config.h>
 #include <linux/module.h>
-#include <linux/version.h>
 #include <linux/autoconf.h>
 #include <linux/errno.h>
 #include <linux/signal.h>
index 352547eabf7b171bb4a676d7d772f65a1e575a15..0bbfce43031c9d6be2e4041db9c8fc6f1eea0203 100644 (file)
@@ -90,7 +90,6 @@
 #include <linux/fcntl.h>
 #include <linux/major.h>
 #include <linux/delay.h>
-#include <linux/version.h>
 #include <linux/pci.h>
 #include <linux/init.h>
 #include <asm/uaccess.h>
index feb25158c8ee99c6a00363da01b4ea69c63fe4eb..145275ebdd7ee2d6b0a43062838baa6e82ba8ea3 100644 (file)
@@ -354,7 +354,7 @@ struct sysrq_key_op *__sysrq_get_key_op (int key) {
         return op_p;
 }
 
-void __sysrq_put_key_op (int key, struct sysrq_key_op *op_p) {
+static void __sysrq_put_key_op (int key, struct sysrq_key_op *op_p) {
         int i;
 
        i = sysrq_key_table_key2index(key);
@@ -419,7 +419,7 @@ void handle_sysrq(int key, struct pt_regs *pt_regs, struct tty_struct *tty)
        __handle_sysrq(key, pt_regs, tty, 1);
 }
 
-int __sysrq_swap_key_ops(int key, struct sysrq_key_op *insert_op_p,
+static int __sysrq_swap_key_ops(int key, struct sysrq_key_op *insert_op_p,
                                 struct sysrq_key_op *remove_op_p) {
 
        int retval;
index 99a60496ecc65e3fb1e8907213ae00367bc2a423..9293bcc4dc624cb5a61df076bcda36dbaa1f88fa 100644 (file)
@@ -19,7 +19,6 @@
  * 
  */
 #include <linux/module.h>
-#include <linux/version.h>
 #include <linux/pci.h>
 #include <linux/delay.h>
 #include <linux/fs.h>
index 98601c7d04a92bfe58a79a280fe28dd228c05d6b..4d75c261f98a8faf2835b382982f235ee116fa23 100644 (file)
@@ -26,7 +26,6 @@
  * Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
  */
 #include <linux/config.h>
-#include <linux/version.h>
 #include <linux/kernel.h>
 #include <linux/proc_fs.h>
 #include <linux/errno.h>
index 867cc4e418c777aca7f8d993d0dd5c7584825a37..60aabdb4a046975ead521046aa1353216d3cfbf2 100644 (file)
@@ -32,7 +32,6 @@
  * iseries/vio.h
  */
 #include <linux/config.h>
-#include <linux/version.h>
 #include <linux/module.h>
 #include <linux/kernel.h>
 #include <linux/errno.h>
index 25acf478c9e82c5f2d40cd6c89e9c8fcdb2862be..23a63207d74702f15aff24b0ab422cd1a724ac4c 100644 (file)
@@ -38,7 +38,6 @@ static struct cpufreq_driver          *cpufreq_driver;
 static struct cpufreq_policy   *cpufreq_cpu_data[NR_CPUS];
 static DEFINE_SPINLOCK(cpufreq_driver_lock);
 
-
 /* internal prototypes */
 static int __cpufreq_governor(struct cpufreq_policy *policy, unsigned int event);
 static void handle_update(void *data);
@@ -1115,24 +1114,21 @@ int __cpufreq_driver_target(struct cpufreq_policy *policy,
        int retval = -EINVAL;
 
        /*
-        * Converted the lock_cpu_hotplug to preempt_disable()
-        * and preempt_enable(). This is a bit kludgy and relies on how cpu
-        * hotplug works. All we need is a guarantee that cpu hotplug won't make
-        * progress on any cpu. Once we do preempt_disable(), this would ensure
-        * that hotplug threads don't get onto this cpu, thereby delaying
-        * the cpu remove process.
-        *
-        * We removed the lock_cpu_hotplug since we need to call this function
-        * via cpu hotplug callbacks, which result in locking the cpu hotplug
-        * thread itself. Agree this is not very clean, cpufreq community
-        * could improve this if required. - Ashok Raj <ashok.raj@intel.com>
+        * If we are already in context of hotplug thread, we dont need to
+        * acquire the hotplug lock. Otherwise acquire cpucontrol to prevent
+        * hotplug from removing this cpu that we are working on.
         */
-       preempt_disable();
+       if (!current_in_cpu_hotplug())
+               lock_cpu_hotplug();
+
        dprintk("target for CPU %u: %u kHz, relation %u\n", policy->cpu,
                target_freq, relation);
        if (cpu_online(policy->cpu) && cpufreq_driver->target)
                retval = cpufreq_driver->target(policy, target_freq, relation);
-       preempt_enable();
+
+       if (!current_in_cpu_hotplug())
+               unlock_cpu_hotplug();
+
        return retval;
 }
 EXPORT_SYMBOL_GPL(__cpufreq_driver_target);
index ba17292eb2902b5c7acb676beeb7fb840813414a..6d83299e7c9b1123c6bd06479c39606dae41c596 100644 (file)
@@ -34,7 +34,6 @@
  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  * GNU General Public License for more details.
  */
-#include <linux/version.h>
 #include <linux/config.h>
 #include <linux/init.h>
 #include <linux/module.h>
index d8c3d8ebad302dc7569dfccfe1dab300a6506110..b3e65a65d202c268a276657c0451ca7a37d565bf 100644 (file)
@@ -497,16 +497,19 @@ pmu_hd_blink_init(void)
        if (pmu_get_model() != PMU_KEYLARGO_BASED)
                return 0;
        
-       dt = find_devices("device-tree");
+       dt = of_find_node_by_path("/");
        if (dt == NULL)
                return 0;
        model = (const char *)get_property(dt, "model", NULL);
        if (model == NULL)
                return 0;
        if (strncmp(model, "PowerBook", strlen("PowerBook")) != 0 &&
-           strncmp(model, "iBook", strlen("iBook")) != 0)
+           strncmp(model, "iBook", strlen("iBook")) != 0) {
+               of_node_put(dt);
                return 0;
-       
+       }
+       of_node_put(dt);
+
        pmu_blink_on.complete = 1;
        pmu_blink_off.complete = 1;
        spin_lock_init(&pmu_blink_lock);
index 2687e34aa5bce07dc3bcbebf70df98998f961230..321a3a10e69baabad357caba9a208c3d24a4b8b8 100644 (file)
@@ -32,7 +32,6 @@
  * $Id: ib_srp.c 3932 2005-11-01 17:19:29Z roland $
  */
 
-#include <linux/version.h>
 #include <linux/module.h>
 #include <linux/init.h>
 #include <linux/slab.h>
index 0879915b14d5af21ec6a4ed0f3383962a595bc2c..c8ae2bb054e026c4e4e2cf44214c26316737f0dc 100644 (file)
@@ -669,7 +669,7 @@ static int input_dev_hotplug(struct class_device *cdev, char **envp,
                INPUT_ADD_HOTPLUG_VAR("NAME=\"%s\"", dev->name);
        if (dev->phys)
                INPUT_ADD_HOTPLUG_VAR("PHYS=\"%s\"", dev->phys);
-       if (dev->phys)
+       if (dev->uniq)
                INPUT_ADD_HOTPLUG_VAR("UNIQ=\"%s\"", dev->uniq);
 
        INPUT_ADD_HOTPLUG_BM_VAR("EV=", dev->evbit, EV_MAX);
index 434e684f5dbbba51cec432eed8f6913f399302f4..2f7c9fc2e898b5d52fc20b628b1d4d5a7d7fac31 100644 (file)
@@ -10,7 +10,6 @@
  */
 
 #include <linux/module.h>
-#include <linux/version.h>
 #include <linux/init.h>
 #include <linux/kernel.h>
 
index 0b0ea26023e59994e5c9b3836317d082d5fd33b0..1b37d86d5ee13f4b3cb0dac5714eb4ecf44f043e 100644 (file)
@@ -11,7 +11,6 @@
 
 #include <linux/config.h>
 #include <linux/module.h>
-#include <linux/version.h>
 #include <linux/poll.h>
 #include <linux/smp_lock.h>
 #ifdef CONFIG_PROC_FS
index 0bfd698726a68f90444a5b9c6cc0b28f92da2559..f1a1f9a9b88e5c44dcc2aee82c01cba8e303b0de 100644 (file)
@@ -9,7 +9,6 @@
  *
  */
 
-#include <linux/version.h>
 #include <linux/proc_fs.h>
 
 #include "isdn_divert.h"
index b4d795d40154232a217c86943f26281212ba0eee..dc7ef957e89708903b5620d175b8a110119091de 100644 (file)
@@ -23,7 +23,6 @@
  * o tx_skb at PH_DEACTIVATE time
  */
 
-#include <linux/version.h>
 #include <linux/module.h>
 #include <linux/init.h>
 #include <linux/pci.h>
index 2cf5d1a6df6c321fe334ca1c4c05e56df75ab2de..8e192a3a34906ca80118f30c2b4ecff3bb6b2019 100644 (file)
@@ -25,7 +25,6 @@
  */
 
 #include <linux/config.h>
-#include <linux/version.h>
 #include <linux/module.h>
 #include <linux/init.h>
 #include <linux/usb.h>
index 1fd3d4e5f2849b5e9eb699c75cdb6374654d203a..acc1d3cceebb35214018fd34fd898cd0518824bb 100644 (file)
@@ -11,7 +11,6 @@
  */
 
 #include <linux/module.h>
-#include <linux/version.h>
 #include <linux/signal.h>
 #include <linux/kernel.h>
 #include <linux/skbuff.h>
index 12c8137b5161427eef3c8c85305d584da00de24c..cb791f8e793ae6335308a8afeeb164c42ebc546d 100644 (file)
@@ -13,7 +13,6 @@
 #include <linux/config.h>
 #include <linux/module.h>
 #include <linux/init.h>
-#include <linux/version.h>
 #include <linux/poll.h>
 #include <linux/vmalloc.h>
 #include <linux/slab.h>
index babec8157ae650aebd0c37354ffe72c072ae96f7..aa01628d74c6f7db0459e26e0988098a3c471962 100644 (file)
@@ -14,7 +14,6 @@
  */
 
 #include <linux/module.h>
-#include <linux/version.h>
 #include <linux/signal.h>
 #include <linux/kernel.h>
 #include <linux/netdevice.h>
index 87f59a0e2a959cbabd23ded727e53949dc49eb75..40e56143c768fcecfd96296e53ebe1edfd173edb 100644 (file)
@@ -12,7 +12,6 @@
  */
 
 #include <linux/module.h>
-#include <linux/version.h>
 #include <linux/poll.h>
 #include <linux/proc_fs.h>
 #include <linux/pci.h>
index 4d57011c5737646025e5844820065acce465a364..6c26f1efabd52299c8a90fdc2eb170ff7510b738 100644 (file)
@@ -11,7 +11,6 @@
  */
 
 #include <linux/module.h>
-#include <linux/version.h>
 #include <linux/poll.h>
 #include <linux/proc_fs.h>
 #include <linux/pci.h>
index 8a7d54a5c97d6634525d31e536aa3af098087a5a..4643df097bfebe62d80358c18ba7f87f6ee8ff6c 100644 (file)
@@ -14,7 +14,6 @@
 #include <linux/config.h>
 #include <linux/module.h>
 #include <linux/init.h>
-#include <linux/version.h>
 #include <linux/poll.h>
 #include <linux/vmalloc.h>
 #include <linux/isdn.h>
index 9028cc3b50717be5a0afa0da1c789aebe3d9254a..7d7245fb0b32971d40110972a6ff7abf4363fa97 100644 (file)
@@ -35,7 +35,6 @@ typedef struct icn_cdef {
 #ifdef __KERNEL__
 /* Kernel includes */
 
-#include <linux/version.h>
 #include <linux/errno.h>
 #include <linux/fs.h>
 #include <linux/major.h>
index 8fb7bc1bfe0f801a1dce06331b1881c0ca6c48fe..d699fe53e1c37a4ae906323aa415e89f420cf4ec 100644 (file)
@@ -33,7 +33,6 @@ typedef struct isdnloop_sdef {
 #ifdef __KERNEL__
 /* Kernel includes */
 
-#include <linux/version.h>
 #include <linux/errno.h>
 #include <linux/fs.h>
 #include <linux/major.h>
index 4611da6e9231635221269888e670d5ceea8246c3..5286e0c810a9f4c26254e9638a049bf2d38c501f 100644 (file)
@@ -4,7 +4,6 @@
  *
  */
 
-#include <linux/version.h>
 #include <linux/errno.h>
 #include <asm/io.h>
 #include <linux/delay.h>
index bc3e096d84f75a5660e1c98ba9db99d955a1a075..a0ea44c3e8b10ec9ca68689718c3da6423961e3b 100644 (file)
@@ -169,6 +169,25 @@ config THERM_PM72
          This driver provides thermostat and fan control for the desktop
          G5 machines. 
 
+config WINDFARM
+       tristate "New PowerMac thermal control infrastructure"
+
+config WINDFARM_PM81
+       tristate "Support for thermal management on iMac G5"
+       depends on WINDFARM && I2C && CPU_FREQ_PMAC64 && PMAC_SMU
+       select I2C_PMAC_SMU
+       help
+         This driver provides thermal control for the iMacG5
+
+config WINDFARM_PM91
+       tristate "Support for thermal management on PowerMac9,1"
+       depends on WINDFARM && I2C && CPU_FREQ_PMAC64 && PMAC_SMU
+       select I2C_PMAC_SMU
+       help
+         This driver provides thermal control for the PowerMac9,1
+          which is the recent (SMU based) single CPU desktop G5
+
+
 config ANSLCD
        tristate "Support for ANS LCD display"
        depends on ADB_CUDA && PPC_PMAC
index 236291bd48a4117fe4e7eb12ae8075a9142a2ebd..f4657aa81fb0474d92f1c525af90015db1d5a6c3 100644 (file)
@@ -26,3 +26,12 @@ obj-$(CONFIG_ADB_MACIO)              += macio-adb.o
 obj-$(CONFIG_THERM_PM72)       += therm_pm72.o
 obj-$(CONFIG_THERM_WINDTUNNEL) += therm_windtunnel.o
 obj-$(CONFIG_THERM_ADT746X)    += therm_adt746x.o
+obj-$(CONFIG_WINDFARM)         += windfarm_core.o
+obj-$(CONFIG_WINDFARM_PM81)     += windfarm_smu_controls.o \
+                                  windfarm_smu_sensors.o \
+                                  windfarm_lm75_sensor.o windfarm_pid.o \
+                                  windfarm_cpufreq_clamp.o windfarm_pm81.o
+obj-$(CONFIG_WINDFARM_PM91)     += windfarm_smu_controls.o \
+                                  windfarm_smu_sensors.o \
+                                  windfarm_lm75_sensor.o windfarm_pid.o \
+                                  windfarm_cpufreq_clamp.o windfarm_pm91.o
index 34f3c7e2d832921e783e21e9c22b806d07b71421..e8378274d710f02f0d93facd8de2fa050ec6e4f4 100644 (file)
 #include <asm/uaccess.h>
 #include <asm/of_device.h>
 
-#define VERSION "0.6"
+#define VERSION "0.7"
 #define AUTHOR  "(c) 2005 Benjamin Herrenschmidt, IBM Corp."
 
 #undef DEBUG_SMU
 
 #ifdef DEBUG_SMU
-#define DPRINTK(fmt, args...) do { printk(KERN_DEBUG fmt , ##args); } while (0)
+#define DPRINTK(fmt, args...) do { udbg_printf(KERN_DEBUG fmt , ##args); } while (0)
 #else
 #define DPRINTK(fmt, args...) do { } while (0)
 #endif
@@ -92,7 +92,7 @@ struct smu_device {
  * for now, just hard code that
  */
 static struct smu_device       *smu;
-
+static DECLARE_MUTEX(smu_part_access);
 
 /*
  * SMU driver low level stuff
@@ -113,9 +113,11 @@ static void smu_start_cmd(void)
 
        DPRINTK("SMU: starting cmd %x, %d bytes data\n", cmd->cmd,
                cmd->data_len);
-       DPRINTK("SMU: data buffer: %02x %02x %02x %02x ...\n",
+       DPRINTK("SMU: data buffer: %02x %02x %02x %02x %02x %02x %02x %02x\n",
                ((u8 *)cmd->data_buf)[0], ((u8 *)cmd->data_buf)[1],
-               ((u8 *)cmd->data_buf)[2], ((u8 *)cmd->data_buf)[3]);
+               ((u8 *)cmd->data_buf)[2], ((u8 *)cmd->data_buf)[3],
+               ((u8 *)cmd->data_buf)[4], ((u8 *)cmd->data_buf)[5],
+               ((u8 *)cmd->data_buf)[6], ((u8 *)cmd->data_buf)[7]);
 
        /* Fill the SMU command buffer */
        smu->cmd_buf->cmd = cmd->cmd;
@@ -440,7 +442,7 @@ int smu_present(void)
 EXPORT_SYMBOL(smu_present);
 
 
-int smu_init (void)
+int __init smu_init (void)
 {
        struct device_node *np;
        u32 *data;
@@ -588,6 +590,8 @@ static void smu_expose_childs(void *unused)
                        sprintf(name, "smu-i2c-%02x", *reg);
                        of_platform_device_create(np, name, &smu->of_dev->dev);
                }
+               if (device_is_compatible(np, "smu-sensors"))
+                       of_platform_device_create(np, "smu-sensors", &smu->of_dev->dev);
        }
 
 }
@@ -845,6 +849,156 @@ int smu_queue_i2c(struct smu_i2c_cmd *cmd)
        return 0;
 }
 
+/*
+ * Handling of "partitions"
+ */
+
+static int smu_read_datablock(u8 *dest, unsigned int addr, unsigned int len)
+{
+       DECLARE_COMPLETION(comp);
+       unsigned int chunk;
+       struct smu_cmd cmd;
+       int rc;
+       u8 params[8];
+
+       /* We currently use a chunk size of 0xe. We could check the
+        * SMU firmware version and use bigger sizes though
+        */
+       chunk = 0xe;
+
+       while (len) {
+               unsigned int clen = min(len, chunk);
+
+               cmd.cmd = SMU_CMD_MISC_ee_COMMAND;
+               cmd.data_len = 7;
+               cmd.data_buf = params;
+               cmd.reply_len = chunk;
+               cmd.reply_buf = dest;
+               cmd.done = smu_done_complete;
+               cmd.misc = &comp;
+               params[0] = SMU_CMD_MISC_ee_GET_DATABLOCK_REC;
+               params[1] = 0x4;
+               *((u32 *)&params[2]) = addr;
+               params[6] = clen;
+
+               rc = smu_queue_cmd(&cmd);
+               if (rc)
+                       return rc;
+               wait_for_completion(&comp);
+               if (cmd.status != 0)
+                       return rc;
+               if (cmd.reply_len != clen) {
+                       printk(KERN_DEBUG "SMU: short read in "
+                              "smu_read_datablock, got: %d, want: %d\n",
+                              cmd.reply_len, clen);
+                       return -EIO;
+               }
+               len -= clen;
+               addr += clen;
+               dest += clen;
+       }
+       return 0;
+}
+
+static struct smu_sdbp_header *smu_create_sdb_partition(int id)
+{
+       DECLARE_COMPLETION(comp);
+       struct smu_simple_cmd cmd;
+       unsigned int addr, len, tlen;
+       struct smu_sdbp_header *hdr;
+       struct property *prop;
+
+       /* First query the partition info */
+       smu_queue_simple(&cmd, SMU_CMD_PARTITION_COMMAND, 2,
+                        smu_done_complete, &comp,
+                        SMU_CMD_PARTITION_LATEST, id);
+       wait_for_completion(&comp);
+
+       /* Partition doesn't exist (or other error) */
+       if (cmd.cmd.status != 0 || cmd.cmd.reply_len != 6)
+               return NULL;
+
+       /* Fetch address and length from reply */
+       addr = *((u16 *)cmd.buffer);
+       len = cmd.buffer[3] << 2;
+       /* Calucluate total length to allocate, including the 17 bytes
+        * for "sdb-partition-XX" that we append at the end of the buffer
+        */
+       tlen = sizeof(struct property) + len + 18;
+
+       prop = kcalloc(tlen, 1, GFP_KERNEL);
+       if (prop == NULL)
+               return NULL;
+       hdr = (struct smu_sdbp_header *)(prop + 1);
+       prop->name = ((char *)prop) + tlen - 18;
+       sprintf(prop->name, "sdb-partition-%02x", id);
+       prop->length = len;
+       prop->value = (unsigned char *)hdr;
+       prop->next = NULL;
+
+       /* Read the datablock */
+       if (smu_read_datablock((u8 *)hdr, addr, len)) {
+               printk(KERN_DEBUG "SMU: datablock read failed while reading "
+                      "partition %02x !\n", id);
+               goto failure;
+       }
+
+       /* Got it, check a few things and create the property */
+       if (hdr->id != id) {
+               printk(KERN_DEBUG "SMU: Reading partition %02x and got "
+                      "%02x !\n", id, hdr->id);
+               goto failure;
+       }
+       if (prom_add_property(smu->of_node, prop)) {
+               printk(KERN_DEBUG "SMU: Failed creating sdb-partition-%02x "
+                      "property !\n", id);
+               goto failure;
+       }
+
+       return hdr;
+ failure:
+       kfree(prop);
+       return NULL;
+}
+
+/* Note: Only allowed to return error code in pointers (using ERR_PTR)
+ * when interruptible is 1
+ */
+struct smu_sdbp_header *__smu_get_sdb_partition(int id, unsigned int *size,
+                                               int interruptible)
+{
+       char pname[32];
+       struct smu_sdbp_header *part;
+
+       if (!smu)
+               return NULL;
+
+       sprintf(pname, "sdb-partition-%02x", id);
+
+       if (interruptible) {
+               int rc;
+               rc = down_interruptible(&smu_part_access);
+               if (rc)
+                       return ERR_PTR(rc);
+       } else
+               down(&smu_part_access);
+
+       part = (struct smu_sdbp_header *)get_property(smu->of_node,
+                                                     pname, size);
+       if (part == NULL) {
+               part = smu_create_sdb_partition(id);
+               if (part != NULL && size)
+                       *size = part->len << 2;
+       }
+       up(&smu_part_access);
+       return part;
+}
+
+struct smu_sdbp_header *smu_get_sdb_partition(int id, unsigned int *size)
+{
+       return __smu_get_sdb_partition(id, size, 0);
+}
+EXPORT_SYMBOL(smu_get_sdb_partition);
 
 
 /*
@@ -918,6 +1072,14 @@ static ssize_t smu_write(struct file *file, const char __user *buf,
        else if (hdr.cmdtype == SMU_CMDTYPE_WANTS_EVENTS) {
                pp->mode = smu_file_events;
                return 0;
+       } else if (hdr.cmdtype == SMU_CMDTYPE_GET_PARTITION) {
+               struct smu_sdbp_header *part;
+               part = __smu_get_sdb_partition(hdr.cmd, NULL, 1);
+               if (part == NULL)
+                       return -EINVAL;
+               else if (IS_ERR(part))
+                       return PTR_ERR(part);
+               return 0;
        } else if (hdr.cmdtype != SMU_CMDTYPE_SMU)
                return -EINVAL;
        else if (pp->mode != smu_file_commands)
index 9bc6cc6e384546faee4b068fa5aa87e0e350fe5d..5640435085694fdbefddf0e7c1a18bef2e221b75 100644 (file)
@@ -2053,6 +2053,7 @@ pmu_register_sleep_notifier(struct pmu_sleep_notifier *n)
        __list_add(&n->list, list->prev, list);
        return 0;
 }
+EXPORT_SYMBOL(pmu_register_sleep_notifier);
 
 int
 pmu_unregister_sleep_notifier(struct pmu_sleep_notifier* n)
@@ -2063,6 +2064,7 @@ pmu_unregister_sleep_notifier(struct pmu_sleep_notifier* n)
        n->list.next = NULL;
        return 0;
 }
+EXPORT_SYMBOL(pmu_unregister_sleep_notifier);
 #endif /* CONFIG_PM */
 
 #if defined(CONFIG_PM) && defined(CONFIG_PPC32)
@@ -2667,10 +2669,10 @@ powerbook_sleep_3400(void)
        asleep = 1;
 
        /* Put the CPU into sleep mode */
-       asm volatile("mfspr %0,1008" : "=r" (hid0) :);
+       hid0 = mfspr(SPRN_HID0);
        hid0 = (hid0 & ~(HID0_NAP | HID0_DOZE)) | HID0_SLEEP;
-       asm volatile("mtspr 1008,%0" : : "r" (hid0));
-       _nmask_and_or_msr(0, MSR_POW | MSR_EE);
+       mtspr(SPRN_HID0, hid0);
+       mtmsr(mfmsr() | MSR_POW | MSR_EE);
        udelay(10);
 
        /* OK, we're awake again, start restoring things */
@@ -3139,8 +3141,6 @@ EXPORT_SYMBOL(pmu_i2c_stdsub_write);
 EXPORT_SYMBOL(pmu_i2c_simple_read);
 EXPORT_SYMBOL(pmu_i2c_simple_write);
 #if defined(CONFIG_PM) && defined(CONFIG_PPC32)
-EXPORT_SYMBOL(pmu_register_sleep_notifier);
-EXPORT_SYMBOL(pmu_unregister_sleep_notifier);
 EXPORT_SYMBOL(pmu_enable_irled);
 EXPORT_SYMBOL(pmu_battery_count);
 EXPORT_SYMBOL(pmu_batteries);
diff --git a/drivers/macintosh/windfarm.h b/drivers/macintosh/windfarm.h
new file mode 100644 (file)
index 0000000..3f0cb03
--- /dev/null
@@ -0,0 +1,131 @@
+/*
+ * Windfarm PowerMac thermal control.
+ *
+ * (c) Copyright 2005 Benjamin Herrenschmidt, IBM Corp.
+ *                    <benh@kernel.crashing.org>
+ *
+ * Released under the term of the GNU GPL v2.
+ */
+
+#ifndef __WINDFARM_H__
+#define __WINDFARM_H__
+
+#include <linux/kref.h>
+#include <linux/list.h>
+#include <linux/module.h>
+#include <linux/notifier.h>
+
+/* Display a 16.16 fixed point value */
+#define FIX32TOPRINT(f)        ((f) >> 16),((((f) & 0xffff) * 1000) >> 16)
+
+/*
+ * Control objects
+ */
+
+struct wf_control;
+
+struct wf_control_ops {
+       int                     (*set_value)(struct wf_control *ct, s32 val);
+       int                     (*get_value)(struct wf_control *ct, s32 *val);
+       s32                     (*get_min)(struct wf_control *ct);
+       s32                     (*get_max)(struct wf_control *ct);
+       void                    (*release)(struct wf_control *ct);
+       struct module           *owner;
+};
+
+struct wf_control {
+       struct list_head        link;
+       struct wf_control_ops   *ops;
+       char                    *name;
+       int                     type;
+       struct kref             ref;
+};
+
+#define WF_CONTROL_TYPE_GENERIC                0
+#define WF_CONTROL_RPM_FAN             1
+#define WF_CONTROL_PWM_FAN             2
+
+
+/* Note about lifetime rules: wf_register_control() will initialize
+ * the kref and wf_unregister_control will decrement it, thus the
+ * object creating/disposing a given control shouldn't assume it
+ * still exists after wf_unregister_control has been called.
+ * wf_find_control will inc the refcount for you
+ */
+extern int wf_register_control(struct wf_control *ct);
+extern void wf_unregister_control(struct wf_control *ct);
+extern struct wf_control * wf_find_control(const char *name);
+extern int wf_get_control(struct wf_control *ct);
+extern void wf_put_control(struct wf_control *ct);
+
+static inline int wf_control_set_max(struct wf_control *ct)
+{
+       s32 vmax = ct->ops->get_max(ct);
+       return ct->ops->set_value(ct, vmax);
+}
+
+static inline int wf_control_set_min(struct wf_control *ct)
+{
+       s32 vmin = ct->ops->get_min(ct);
+       return ct->ops->set_value(ct, vmin);
+}
+
+/*
+ * Sensor objects
+ */
+
+struct wf_sensor;
+
+struct wf_sensor_ops {
+       int                     (*get_value)(struct wf_sensor *sr, s32 *val);
+       void                    (*release)(struct wf_sensor *sr);
+       struct module           *owner;
+};
+
+struct wf_sensor {
+       struct list_head        link;
+       struct wf_sensor_ops    *ops;
+       char                    *name;
+       struct kref             ref;
+};
+
+/* Same lifetime rules as controls */
+extern int wf_register_sensor(struct wf_sensor *sr);
+extern void wf_unregister_sensor(struct wf_sensor *sr);
+extern struct wf_sensor * wf_find_sensor(const char *name);
+extern int wf_get_sensor(struct wf_sensor *sr);
+extern void wf_put_sensor(struct wf_sensor *sr);
+
+/* For use by clients. Note that we are a bit racy here since
+ * notifier_block doesn't have a module owner field. I may fix
+ * it one day ...
+ *
+ * LOCKING NOTE !
+ *
+ * All "events" except WF_EVENT_TICK are called with an internal mutex
+ * held which will deadlock if you call basically any core routine.
+ * So don't ! Just take note of the event and do your actual operations
+ * from the ticker.
+ *
+ */
+extern int wf_register_client(struct notifier_block *nb);
+extern int wf_unregister_client(struct notifier_block *nb);
+
+/* Overtemp conditions. Those are refcounted */
+extern void wf_set_overtemp(void);
+extern void wf_clear_overtemp(void);
+extern int wf_is_overtemp(void);
+
+#define WF_EVENT_NEW_CONTROL   0 /* param is wf_control * */
+#define WF_EVENT_NEW_SENSOR    1 /* param is wf_sensor * */
+#define WF_EVENT_OVERTEMP      2 /* no param */
+#define WF_EVENT_NORMALTEMP    3 /* overtemp condition cleared */
+#define WF_EVENT_TICK          4 /* 1 second tick */
+
+/* Note: If that driver gets more broad use, we could replace the
+ * simplistic overtemp bits with "environmental conditions". That
+ * could then be used to also notify of things like fan failure,
+ * case open, battery conditions, ...
+ */
+
+#endif /* __WINDFARM_H__ */
diff --git a/drivers/macintosh/windfarm_core.c b/drivers/macintosh/windfarm_core.c
new file mode 100644 (file)
index 0000000..6c2a471
--- /dev/null
@@ -0,0 +1,426 @@
+/*
+ * Windfarm PowerMac thermal control. Core
+ *
+ * (c) Copyright 2005 Benjamin Herrenschmidt, IBM Corp.
+ *                    <benh@kernel.crashing.org>
+ *
+ * Released under the term of the GNU GPL v2.
+ *
+ * This core code tracks the list of sensors & controls, register
+ * clients, and holds the kernel thread used for control.
+ *
+ * TODO:
+ *
+ * Add some information about sensor/control type and data format to
+ * sensors/controls, and have the sysfs attribute stuff be moved
+ * generically here instead of hard coded in the platform specific
+ * driver as it us currently
+ *
+ * This however requires solving some annoying lifetime issues with
+ * sysfs which doesn't seem to have lifetime rules for struct attribute,
+ * I may have to create full features kobjects for every sensor/control
+ * instead which is a bit of an overkill imho
+ */
+
+#include <linux/types.h>
+#include <linux/errno.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/spinlock.h>
+#include <linux/smp_lock.h>
+#include <linux/kthread.h>
+#include <linux/jiffies.h>
+#include <linux/reboot.h>
+#include <linux/device.h>
+#include <linux/platform_device.h>
+
+#include "windfarm.h"
+
+#define VERSION "0.2"
+
+#undef DEBUG
+
+#ifdef DEBUG
+#define DBG(args...)   printk(args)
+#else
+#define DBG(args...)   do { } while(0)
+#endif
+
+static LIST_HEAD(wf_controls);
+static LIST_HEAD(wf_sensors);
+static DECLARE_MUTEX(wf_lock);
+static struct notifier_block *wf_client_list;
+static int wf_client_count;
+static unsigned int wf_overtemp;
+static unsigned int wf_overtemp_counter;
+struct task_struct *wf_thread;
+
+/*
+ * Utilities & tick thread
+ */
+
+static inline void wf_notify(int event, void *param)
+{
+       notifier_call_chain(&wf_client_list, event, param);
+}
+
+int wf_critical_overtemp(void)
+{
+       static char * critical_overtemp_path = "/sbin/critical_overtemp";
+       char *argv[] = { critical_overtemp_path, NULL };
+       static char *envp[] = { "HOME=/",
+                               "TERM=linux",
+                               "PATH=/sbin:/usr/sbin:/bin:/usr/bin",
+                               NULL };
+
+       return call_usermodehelper(critical_overtemp_path, argv, envp, 0);
+}
+EXPORT_SYMBOL_GPL(wf_critical_overtemp);
+
+static int wf_thread_func(void *data)
+{
+       unsigned long next, delay;
+
+       next = jiffies;
+
+       DBG("wf: thread started\n");
+
+       while(!kthread_should_stop()) {
+               try_to_freeze();
+
+               if (time_after_eq(jiffies, next)) {
+                       wf_notify(WF_EVENT_TICK, NULL);
+                       if (wf_overtemp) {
+                               wf_overtemp_counter++;
+                               /* 10 seconds overtemp, notify userland */
+                               if (wf_overtemp_counter > 10)
+                                       wf_critical_overtemp();
+                               /* 30 seconds, shutdown */
+                               if (wf_overtemp_counter > 30) {
+                                       printk(KERN_ERR "windfarm: Overtemp "
+                                              "for more than 30"
+                                              " seconds, shutting down\n");
+                                       machine_power_off();
+                               }
+                       }
+                       next += HZ;
+               }
+
+               delay = next - jiffies;
+               if (delay <= HZ)
+                       schedule_timeout_interruptible(delay);
+
+               /* there should be no signal, but oh well */
+               if (signal_pending(current)) {
+                       printk(KERN_WARNING "windfarm: thread got sigl !\n");
+                       break;
+               }
+       }
+
+       DBG("wf: thread stopped\n");
+
+       return 0;
+}
+
+static void wf_start_thread(void)
+{
+       wf_thread = kthread_run(wf_thread_func, NULL, "kwindfarm");
+       if (IS_ERR(wf_thread)) {
+               printk(KERN_ERR "windfarm: failed to create thread,err %ld\n",
+                      PTR_ERR(wf_thread));
+               wf_thread = NULL;
+       }
+}
+
+
+static void wf_stop_thread(void)
+{
+       if (wf_thread)
+               kthread_stop(wf_thread);
+       wf_thread = NULL;
+}
+
+/*
+ * Controls
+ */
+
+static void wf_control_release(struct kref *kref)
+{
+       struct wf_control *ct = container_of(kref, struct wf_control, ref);
+
+       DBG("wf: Deleting control %s\n", ct->name);
+
+       if (ct->ops && ct->ops->release)
+               ct->ops->release(ct);
+       else
+               kfree(ct);
+}
+
+int wf_register_control(struct wf_control *new_ct)
+{
+       struct wf_control *ct;
+
+       down(&wf_lock);
+       list_for_each_entry(ct, &wf_controls, link) {
+               if (!strcmp(ct->name, new_ct->name)) {
+                       printk(KERN_WARNING "windfarm: trying to register"
+                              " duplicate control %s\n", ct->name);
+                       up(&wf_lock);
+                       return -EEXIST;
+               }
+       }
+       kref_init(&new_ct->ref);
+       list_add(&new_ct->link, &wf_controls);
+
+       DBG("wf: Registered control %s\n", new_ct->name);
+
+       wf_notify(WF_EVENT_NEW_CONTROL, new_ct);
+       up(&wf_lock);
+
+       return 0;
+}
+EXPORT_SYMBOL_GPL(wf_register_control);
+
+void wf_unregister_control(struct wf_control *ct)
+{
+       down(&wf_lock);
+       list_del(&ct->link);
+       up(&wf_lock);
+
+       DBG("wf: Unregistered control %s\n", ct->name);
+
+       kref_put(&ct->ref, wf_control_release);
+}
+EXPORT_SYMBOL_GPL(wf_unregister_control);
+
+struct wf_control * wf_find_control(const char *name)
+{
+       struct wf_control *ct;
+
+       down(&wf_lock);
+       list_for_each_entry(ct, &wf_controls, link) {
+               if (!strcmp(ct->name, name)) {
+                       if (wf_get_control(ct))
+                               ct = NULL;
+                       up(&wf_lock);
+                       return ct;
+               }
+       }
+       up(&wf_lock);
+       return NULL;
+}
+EXPORT_SYMBOL_GPL(wf_find_control);
+
+int wf_get_control(struct wf_control *ct)
+{
+       if (!try_module_get(ct->ops->owner))
+               return -ENODEV;
+       kref_get(&ct->ref);
+       return 0;
+}
+EXPORT_SYMBOL_GPL(wf_get_control);
+
+void wf_put_control(struct wf_control *ct)
+{
+       struct module *mod = ct->ops->owner;
+       kref_put(&ct->ref, wf_control_release);
+       module_put(mod);
+}
+EXPORT_SYMBOL_GPL(wf_put_control);
+
+
+/*
+ * Sensors
+ */
+
+
+static void wf_sensor_release(struct kref *kref)
+{
+       struct wf_sensor *sr = container_of(kref, struct wf_sensor, ref);
+
+       DBG("wf: Deleting sensor %s\n", sr->name);
+
+       if (sr->ops && sr->ops->release)
+               sr->ops->release(sr);
+       else
+               kfree(sr);
+}
+
+int wf_register_sensor(struct wf_sensor *new_sr)
+{
+       struct wf_sensor *sr;
+
+       down(&wf_lock);
+       list_for_each_entry(sr, &wf_sensors, link) {
+               if (!strcmp(sr->name, new_sr->name)) {
+                       printk(KERN_WARNING "windfarm: trying to register"
+                              " duplicate sensor %s\n", sr->name);
+                       up(&wf_lock);
+                       return -EEXIST;
+               }
+       }
+       kref_init(&new_sr->ref);
+       list_add(&new_sr->link, &wf_sensors);
+
+       DBG("wf: Registered sensor %s\n", new_sr->name);
+
+       wf_notify(WF_EVENT_NEW_SENSOR, new_sr);
+       up(&wf_lock);
+
+       return 0;
+}
+EXPORT_SYMBOL_GPL(wf_register_sensor);
+
+void wf_unregister_sensor(struct wf_sensor *sr)
+{
+       down(&wf_lock);
+       list_del(&sr->link);
+       up(&wf_lock);
+
+       DBG("wf: Unregistered sensor %s\n", sr->name);
+
+       wf_put_sensor(sr);
+}
+EXPORT_SYMBOL_GPL(wf_unregister_sensor);
+
+struct wf_sensor * wf_find_sensor(const char *name)
+{
+       struct wf_sensor *sr;
+
+       down(&wf_lock);
+       list_for_each_entry(sr, &wf_sensors, link) {
+               if (!strcmp(sr->name, name)) {
+                       if (wf_get_sensor(sr))
+                               sr = NULL;
+                       up(&wf_lock);
+                       return sr;
+               }
+       }
+       up(&wf_lock);
+       return NULL;
+}
+EXPORT_SYMBOL_GPL(wf_find_sensor);
+
+int wf_get_sensor(struct wf_sensor *sr)
+{
+       if (!try_module_get(sr->ops->owner))
+               return -ENODEV;
+       kref_get(&sr->ref);
+       return 0;
+}
+EXPORT_SYMBOL_GPL(wf_get_sensor);
+
+void wf_put_sensor(struct wf_sensor *sr)
+{
+       struct module *mod = sr->ops->owner;
+       kref_put(&sr->ref, wf_sensor_release);
+       module_put(mod);
+}
+EXPORT_SYMBOL_GPL(wf_put_sensor);
+
+
+/*
+ * Client & notification
+ */
+
+int wf_register_client(struct notifier_block *nb)
+{
+       int rc;
+       struct wf_control *ct;
+       struct wf_sensor *sr;
+
+       down(&wf_lock);
+       rc = notifier_chain_register(&wf_client_list, nb);
+       if (rc != 0)
+               goto bail;
+       wf_client_count++;
+       list_for_each_entry(ct, &wf_controls, link)
+               wf_notify(WF_EVENT_NEW_CONTROL, ct);
+       list_for_each_entry(sr, &wf_sensors, link)
+               wf_notify(WF_EVENT_NEW_SENSOR, sr);
+       if (wf_client_count == 1)
+               wf_start_thread();
+ bail:
+       up(&wf_lock);
+       return rc;
+}
+EXPORT_SYMBOL_GPL(wf_register_client);
+
+int wf_unregister_client(struct notifier_block *nb)
+{
+       down(&wf_lock);
+       notifier_chain_unregister(&wf_client_list, nb);
+       wf_client_count++;
+       if (wf_client_count == 0)
+               wf_stop_thread();
+       up(&wf_lock);
+
+       return 0;
+}
+EXPORT_SYMBOL_GPL(wf_unregister_client);
+
+void wf_set_overtemp(void)
+{
+       down(&wf_lock);
+       wf_overtemp++;
+       if (wf_overtemp == 1) {
+               printk(KERN_WARNING "windfarm: Overtemp condition detected !\n");
+               wf_overtemp_counter = 0;
+               wf_notify(WF_EVENT_OVERTEMP, NULL);
+       }
+       up(&wf_lock);
+}
+EXPORT_SYMBOL_GPL(wf_set_overtemp);
+
+void wf_clear_overtemp(void)
+{
+       down(&wf_lock);
+       WARN_ON(wf_overtemp == 0);
+       if (wf_overtemp == 0) {
+               up(&wf_lock);
+               return;
+       }
+       wf_overtemp--;
+       if (wf_overtemp == 0) {
+               printk(KERN_WARNING "windfarm: Overtemp condition cleared !\n");
+               wf_notify(WF_EVENT_NORMALTEMP, NULL);
+       }
+       up(&wf_lock);
+}
+EXPORT_SYMBOL_GPL(wf_clear_overtemp);
+
+int wf_is_overtemp(void)
+{
+       return (wf_overtemp != 0);
+}
+EXPORT_SYMBOL_GPL(wf_is_overtemp);
+
+static struct platform_device wf_platform_device = {
+       .name   = "windfarm",
+};
+
+static int __init windfarm_core_init(void)
+{
+       DBG("wf: core loaded\n");
+
+       platform_device_register(&wf_platform_device);
+       return 0;
+}
+
+static void __exit windfarm_core_exit(void)
+{
+       BUG_ON(wf_client_count != 0);
+
+       DBG("wf: core unloaded\n");
+
+       platform_device_unregister(&wf_platform_device);
+}
+
+
+module_init(windfarm_core_init);
+module_exit(windfarm_core_exit);
+
+MODULE_AUTHOR("Benjamin Herrenschmidt <benh@kernel.crashing.org>");
+MODULE_DESCRIPTION("Core component of PowerMac thermal control");
+MODULE_LICENSE("GPL");
+
diff --git a/drivers/macintosh/windfarm_cpufreq_clamp.c b/drivers/macintosh/windfarm_cpufreq_clamp.c
new file mode 100644 (file)
index 0000000..607dbac
--- /dev/null
@@ -0,0 +1,105 @@
+#include <linux/config.h>
+#include <linux/types.h>
+#include <linux/errno.h>
+#include <linux/kernel.h>
+#include <linux/delay.h>
+#include <linux/slab.h>
+#include <linux/init.h>
+#include <linux/wait.h>
+#include <linux/cpufreq.h>
+
+#include "windfarm.h"
+
+#define VERSION "0.3"
+
+static int clamped;
+static struct wf_control *clamp_control;
+
+static int clamp_notifier_call(struct notifier_block *self,
+                              unsigned long event, void *data)
+{
+       struct cpufreq_policy *p = data;
+       unsigned long max_freq;
+
+       if (event != CPUFREQ_ADJUST)
+               return 0;
+
+       max_freq = clamped ? (p->cpuinfo.min_freq) : (p->cpuinfo.max_freq);
+       cpufreq_verify_within_limits(p, 0, max_freq);
+
+       return 0;
+}
+
+static struct notifier_block clamp_notifier = {
+       .notifier_call = clamp_notifier_call,
+};
+
+static int clamp_set(struct wf_control *ct, s32 value)
+{
+       if (value)
+               printk(KERN_INFO "windfarm: Clamping CPU frequency to "
+                      "minimum !\n");
+       else
+               printk(KERN_INFO "windfarm: CPU frequency unclamped !\n");
+       clamped = value;
+       cpufreq_update_policy(0);
+       return 0;
+}
+
+static int clamp_get(struct wf_control *ct, s32 *value)
+{
+       *value = clamped;
+       return 0;
+}
+
+static s32 clamp_min(struct wf_control *ct)
+{
+       return 0;
+}
+
+static s32 clamp_max(struct wf_control *ct)
+{
+       return 1;
+}
+
+static struct wf_control_ops clamp_ops = {
+       .set_value      = clamp_set,
+       .get_value      = clamp_get,
+       .get_min        = clamp_min,
+       .get_max        = clamp_max,
+       .owner          = THIS_MODULE,
+};
+
+static int __init wf_cpufreq_clamp_init(void)
+{
+       struct wf_control *clamp;
+
+       clamp = kmalloc(sizeof(struct wf_control), GFP_KERNEL);
+       if (clamp == NULL)
+               return -ENOMEM;
+       cpufreq_register_notifier(&clamp_notifier, CPUFREQ_POLICY_NOTIFIER);
+       clamp->ops = &clamp_ops;
+       clamp->name = "cpufreq-clamp";
+       if (wf_register_control(clamp))
+               goto fail;
+       clamp_control = clamp;
+       return 0;
+ fail:
+       kfree(clamp);
+       return -ENODEV;
+}
+
+static void __exit wf_cpufreq_clamp_exit(void)
+{
+       if (clamp_control)
+               wf_unregister_control(clamp_control);
+}
+
+
+module_init(wf_cpufreq_clamp_init);
+module_exit(wf_cpufreq_clamp_exit);
+
+MODULE_AUTHOR("Benjamin Herrenschmidt <benh@kernel.crashing.org>");
+MODULE_DESCRIPTION("CPU frequency clamp for PowerMacs thermal control");
+MODULE_LICENSE("GPL");
+
diff --git a/drivers/macintosh/windfarm_lm75_sensor.c b/drivers/macintosh/windfarm_lm75_sensor.c
new file mode 100644 (file)
index 0000000..a0a41ad
--- /dev/null
@@ -0,0 +1,263 @@
+/*
+ * Windfarm PowerMac thermal control. LM75 sensor
+ *
+ * (c) Copyright 2005 Benjamin Herrenschmidt, IBM Corp.
+ *                    <benh@kernel.crashing.org>
+ *
+ * Released under the term of the GNU GPL v2.
+ */
+
+#include <linux/types.h>
+#include <linux/errno.h>
+#include <linux/kernel.h>
+#include <linux/delay.h>
+#include <linux/slab.h>
+#include <linux/init.h>
+#include <linux/wait.h>
+#include <linux/i2c.h>
+#include <linux/i2c-dev.h>
+#include <asm/prom.h>
+#include <asm/machdep.h>
+#include <asm/io.h>
+#include <asm/system.h>
+#include <asm/sections.h>
+
+#include "windfarm.h"
+
+#define VERSION "0.1"
+
+#undef DEBUG
+
+#ifdef DEBUG
+#define DBG(args...)   printk(args)
+#else
+#define DBG(args...)   do { } while(0)
+#endif
+
+struct wf_lm75_sensor {
+       int                     ds1775 : 1;
+       int                     inited : 1;
+       struct  i2c_client      i2c;
+       struct  wf_sensor       sens;
+};
+#define wf_to_lm75(c) container_of(c, struct wf_lm75_sensor, sens)
+#define i2c_to_lm75(c) container_of(c, struct wf_lm75_sensor, i2c)
+
+static int wf_lm75_attach(struct i2c_adapter *adapter);
+static int wf_lm75_detach(struct i2c_client *client);
+
+static struct i2c_driver wf_lm75_driver = {
+       .owner          = THIS_MODULE,
+       .name           = "wf_lm75",
+       .flags          = I2C_DF_NOTIFY,
+       .attach_adapter = wf_lm75_attach,
+       .detach_client  = wf_lm75_detach,
+};
+
+static int wf_lm75_get(struct wf_sensor *sr, s32 *value)
+{
+       struct wf_lm75_sensor *lm = wf_to_lm75(sr);
+       s32 data;
+
+       if (lm->i2c.adapter == NULL)
+               return -ENODEV;
+
+       /* Init chip if necessary */
+       if (!lm->inited) {
+               u8 cfg_new, cfg = (u8)i2c_smbus_read_byte_data(&lm->i2c, 1);
+
+               DBG("wf_lm75: Initializing %s, cfg was: %02x\n",
+                   sr->name, cfg);
+
+               /* clear shutdown bit, keep other settings as left by
+                * the firmware for now
+                */
+               cfg_new = cfg & ~0x01;
+               i2c_smbus_write_byte_data(&lm->i2c, 1, cfg_new);
+               lm->inited = 1;
+
+               /* If we just powered it up, let's wait 200 ms */
+               msleep(200);
+       }
+
+       /* Read temperature register */
+       data = (s32)le16_to_cpu(i2c_smbus_read_word_data(&lm->i2c, 0));
+       data <<= 8;
+       *value = data;
+
+       return 0;
+}
+
+static void wf_lm75_release(struct wf_sensor *sr)
+{
+       struct wf_lm75_sensor *lm = wf_to_lm75(sr);
+
+       /* check if client is registered and detach from i2c */
+       if (lm->i2c.adapter) {
+               i2c_detach_client(&lm->i2c);
+               lm->i2c.adapter = NULL;
+       }
+
+       kfree(lm);
+}
+
+static struct wf_sensor_ops wf_lm75_ops = {
+       .get_value      = wf_lm75_get,
+       .release        = wf_lm75_release,
+       .owner          = THIS_MODULE,
+};
+
+static struct wf_lm75_sensor *wf_lm75_create(struct i2c_adapter *adapter,
+                                            u8 addr, int ds1775,
+                                            const char *loc)
+{
+       struct wf_lm75_sensor *lm;
+
+       DBG("wf_lm75: creating  %s device at address 0x%02x\n",
+           ds1775 ? "ds1775" : "lm75", addr);
+
+       lm = kmalloc(sizeof(struct wf_lm75_sensor), GFP_KERNEL);
+       if (lm == NULL)
+               return NULL;
+       memset(lm, 0, sizeof(struct wf_lm75_sensor));
+
+       /* Usual rant about sensor names not beeing very consistent in
+        * the device-tree, oh well ...
+        * Add more entries below as you deal with more setups
+        */
+       if (!strcmp(loc, "Hard drive") || !strcmp(loc, "DRIVE BAY"))
+               lm->sens.name = "hd-temp";
+       else
+               goto fail;
+
+       lm->inited = 0;
+       lm->sens.ops = &wf_lm75_ops;
+       lm->ds1775 = ds1775;
+       lm->i2c.addr = (addr >> 1) & 0x7f;
+       lm->i2c.adapter = adapter;
+       lm->i2c.driver = &wf_lm75_driver;
+       strncpy(lm->i2c.name, lm->sens.name, I2C_NAME_SIZE-1);
+
+       if (i2c_attach_client(&lm->i2c)) {
+               printk(KERN_ERR "windfarm: failed to attach %s %s to i2c\n",
+                      ds1775 ? "ds1775" : "lm75", lm->i2c.name);
+               goto fail;
+       }
+
+       if (wf_register_sensor(&lm->sens)) {
+               i2c_detach_client(&lm->i2c);
+               goto fail;
+       }
+
+       return lm;
+ fail:
+       kfree(lm);
+       return NULL;
+}
+
+static int wf_lm75_attach(struct i2c_adapter *adapter)
+{
+       u8 bus_id;
+       struct device_node *smu, *bus, *dev;
+
+       /* We currently only deal with LM75's hanging off the SMU
+        * i2c busses. If we extend that driver to other/older
+        * machines, we should split this function into SMU-i2c,
+        * keywest-i2c, PMU-i2c, ...
+        */
+
+       DBG("wf_lm75: adapter %s detected\n", adapter->name);
+
+       if (strncmp(adapter->name, "smu-i2c-", 8) != 0)
+               return 0;
+       smu = of_find_node_by_type(NULL, "smu");
+       if (smu == NULL)
+               return 0;
+
+       /* Look for the bus in the device-tree */
+       bus_id = (u8)simple_strtoul(adapter->name + 8, NULL, 16);
+
+       DBG("wf_lm75: bus ID is %x\n", bus_id);
+
+       /* Look for sensors subdir */
+       for (bus = NULL;
+            (bus = of_get_next_child(smu, bus)) != NULL;) {
+               u32 *reg;
+
+               if (strcmp(bus->name, "i2c"))
+                       continue;
+               reg = (u32 *)get_property(bus, "reg", NULL);
+               if (reg == NULL)
+                       continue;
+               if (bus_id == *reg)
+                       break;
+       }
+       of_node_put(smu);
+       if (bus == NULL) {
+               printk(KERN_WARNING "windfarm: SMU i2c bus 0x%x not found"
+                      " in device-tree !\n", bus_id);
+               return 0;
+       }
+
+       DBG("wf_lm75: bus found, looking for device...\n");
+
+       /* Now look for lm75(s) in there */
+       for (dev = NULL;
+            (dev = of_get_next_child(bus, dev)) != NULL;) {
+               const char *loc =
+                       get_property(dev, "hwsensor-location", NULL);
+               u32 *reg = (u32 *)get_property(dev, "reg", NULL);
+               DBG(" dev: %s... (loc: %p, reg: %p)\n", dev->name, loc, reg);
+               if (loc == NULL || reg == NULL)
+                       continue;
+               /* real lm75 */
+               if (device_is_compatible(dev, "lm75"))
+                       wf_lm75_create(adapter, *reg, 0, loc);
+               /* ds1775 (compatible, better resolution */
+               else if (device_is_compatible(dev, "ds1775"))
+                       wf_lm75_create(adapter, *reg, 1, loc);
+       }
+
+       of_node_put(bus);
+
+       return 0;
+}
+
+static int wf_lm75_detach(struct i2c_client *client)
+{
+       struct wf_lm75_sensor *lm = i2c_to_lm75(client);
+
+       DBG("wf_lm75: i2c detatch called for %s\n", lm->sens.name);
+
+       /* Mark client detached */
+       lm->i2c.adapter = NULL;
+
+       /* release sensor */
+       wf_unregister_sensor(&lm->sens);
+
+       return 0;
+}
+
+static int __init wf_lm75_sensor_init(void)
+{
+       int rc;
+
+       rc = i2c_add_driver(&wf_lm75_driver);
+       if (rc < 0)
+               return rc;
+       return 0;
+}
+
+static void __exit wf_lm75_sensor_exit(void)
+{
+       i2c_del_driver(&wf_lm75_driver);
+}
+
+
+module_init(wf_lm75_sensor_init);
+module_exit(wf_lm75_sensor_exit);
+
+MODULE_AUTHOR("Benjamin Herrenschmidt <benh@kernel.crashing.org>");
+MODULE_DESCRIPTION("LM75 sensor objects for PowerMacs thermal control");
+MODULE_LICENSE("GPL");
+
diff --git a/drivers/macintosh/windfarm_pid.c b/drivers/macintosh/windfarm_pid.c
new file mode 100644 (file)
index 0000000..2e803b3
--- /dev/null
@@ -0,0 +1,145 @@
+/*
+ * Windfarm PowerMac thermal control. Generic PID helpers
+ *
+ * (c) Copyright 2005 Benjamin Herrenschmidt, IBM Corp.
+ *                    <benh@kernel.crashing.org>
+ *
+ * Released under the term of the GNU GPL v2.
+ */
+
+#include <linux/types.h>
+#include <linux/errno.h>
+#include <linux/kernel.h>
+#include <linux/string.h>
+#include <linux/module.h>
+
+#include "windfarm_pid.h"
+
+#undef DEBUG
+
+#ifdef DEBUG
+#define DBG(args...)   printk(args)
+#else
+#define DBG(args...)   do { } while(0)
+#endif
+
+void wf_pid_init(struct wf_pid_state *st, struct wf_pid_param *param)
+{
+       memset(st, 0, sizeof(struct wf_pid_state));
+       st->param = *param;
+       st->first = 1;
+}
+EXPORT_SYMBOL_GPL(wf_pid_init);
+
+s32 wf_pid_run(struct wf_pid_state *st, s32 new_sample)
+{
+       s64     error, integ, deriv;
+       s32     target;
+       int     i, hlen = st->param.history_len;
+
+       /* Calculate error term */
+       error = new_sample - st->param.itarget;
+
+       /* Get samples into our history buffer */
+       if (st->first) {
+               for (i = 0; i < hlen; i++) {
+                       st->samples[i] = new_sample;
+                       st->errors[i] = error;
+               }
+               st->first = 0;
+               st->index = 0;
+       } else {
+               st->index = (st->index + 1) % hlen;
+               st->samples[st->index] = new_sample;
+               st->errors[st->index] = error;
+       }
+
+       /* Calculate integral term */
+       for (i = 0, integ = 0; i < hlen; i++)
+               integ += st->errors[(st->index + hlen - i) % hlen];
+       integ *= st->param.interval;
+
+       /* Calculate derivative term */
+       deriv = st->errors[st->index] -
+               st->errors[(st->index + hlen - 1) % hlen];
+       deriv /= st->param.interval;
+
+       /* Calculate target */
+       target = (s32)((integ * (s64)st->param.gr + deriv * (s64)st->param.gd +
+                 error * (s64)st->param.gp) >> 36);
+       if (st->param.additive)
+               target += st->target;
+       target = max(target, st->param.min);
+       target = min(target, st->param.max);
+       st->target = target;
+
+       return st->target;
+}
+EXPORT_SYMBOL_GPL(wf_pid_run);
+
+void wf_cpu_pid_init(struct wf_cpu_pid_state *st,
+                    struct wf_cpu_pid_param *param)
+{
+       memset(st, 0, sizeof(struct wf_cpu_pid_state));
+       st->param = *param;
+       st->first = 1;
+}
+EXPORT_SYMBOL_GPL(wf_cpu_pid_init);
+
+s32 wf_cpu_pid_run(struct wf_cpu_pid_state *st, s32 new_power, s32 new_temp)
+{
+       s64     error, integ, deriv, prop;
+       s32     target, sval, adj;
+       int     i, hlen = st->param.history_len;
+
+       /* Calculate error term */
+       error = st->param.pmaxadj - new_power;
+
+       /* Get samples into our history buffer */
+       if (st->first) {
+               for (i = 0; i < hlen; i++) {
+                       st->powers[i] = new_power;
+                       st->errors[i] = error;
+               }
+               st->temps[0] = st->temps[1] = new_temp;
+               st->first = 0;
+               st->index = st->tindex = 0;
+       } else {
+               st->index = (st->index + 1) % hlen;
+               st->powers[st->index] = new_power;
+               st->errors[st->index] = error;
+               st->tindex = (st->tindex + 1) % 2;
+               st->temps[st->tindex] = new_temp;
+       }
+
+       /* Calculate integral term */
+       for (i = 0, integ = 0; i < hlen; i++)
+               integ += st->errors[(st->index + hlen - i) % hlen];
+       integ *= st->param.interval;
+       integ *= st->param.gr;
+       sval = st->param.tmax - ((integ >> 20) & 0xffffffff);
+       adj = min(st->param.ttarget, sval);
+
+       DBG("integ: %lx, sval: %lx, adj: %lx\n", integ, sval, adj);
+
+       /* Calculate derivative term */
+       deriv = st->temps[st->tindex] -
+               st->temps[(st->tindex + 2 - 1) % 2];
+       deriv /= st->param.interval;
+       deriv *= st->param.gd;
+
+       /* Calculate proportional term */
+       prop = (new_temp - adj);
+       prop *= st->param.gp;
+
+       DBG("deriv: %lx, prop: %lx\n", deriv, prop);
+
+       /* Calculate target */
+       target = st->target + (s32)((deriv + prop) >> 36);
+       target = max(target, st->param.min);
+       target = min(target, st->param.max);
+       st->target = target;
+
+       return st->target;
+}
+EXPORT_SYMBOL_GPL(wf_cpu_pid_run);
diff --git a/drivers/macintosh/windfarm_pid.h b/drivers/macintosh/windfarm_pid.h
new file mode 100644 (file)
index 0000000..a364c2a
--- /dev/null
@@ -0,0 +1,84 @@
+/*
+ * Windfarm PowerMac thermal control. Generic PID helpers
+ *
+ * (c) Copyright 2005 Benjamin Herrenschmidt, IBM Corp.
+ *                    <benh@kernel.crashing.org>
+ *
+ * Released under the term of the GNU GPL v2.
+ *
+ * This is a pair of generic PID helpers that can be used by
+ * control loops. One is the basic PID implementation, the
+ * other one is more specifically tailored to the loops used
+ * for CPU control with 2 input sample types (temp and power)
+ */
+
+/*
+ * *** Simple PID ***
+ */
+
+#define WF_PID_MAX_HISTORY     32
+
+/* This parameter array is passed to the PID algorithm. Currently,
+ * we don't support changing parameters on the fly as it's not needed
+ * but could be implemented (with necessary adjustment of the history
+ * buffer
+ */
+struct wf_pid_param {
+       int     interval;       /* Interval between samples in seconds */
+       int     history_len;    /* Size of history buffer */
+       int     additive;       /* 1: target relative to previous value */
+       s32     gd, gp, gr;     /* PID gains */
+       s32     itarget;        /* PID input target */
+       s32     min,max;        /* min and max target values */
+};
+
+struct wf_pid_state {
+       int     first;                          /* first run of the loop */
+       int     index;                          /* index of current sample */
+       s32     target;                         /* current target value */
+       s32     samples[WF_PID_MAX_HISTORY];    /* samples history buffer */
+       s32     errors[WF_PID_MAX_HISTORY];     /* error history buffer */
+
+       struct wf_pid_param param;
+};
+
+extern void wf_pid_init(struct wf_pid_state *st, struct wf_pid_param *param);
+extern s32 wf_pid_run(struct wf_pid_state *st, s32 sample);
+
+
+/*
+ * *** CPU PID ***
+ */
+
+#define WF_CPU_PID_MAX_HISTORY 32
+
+/* This parameter array is passed to the CPU PID algorithm. Currently,
+ * we don't support changing parameters on the fly as it's not needed
+ * but could be implemented (with necessary adjustment of the history
+ * buffer
+ */
+struct wf_cpu_pid_param {
+       int     interval;       /* Interval between samples in seconds */
+       int     history_len;    /* Size of history buffer */
+       s32     gd, gp, gr;     /* PID gains */
+       s32     pmaxadj;        /* PID max power adjust */
+       s32     ttarget;        /* PID input target */
+       s32     tmax;           /* PID input max */
+       s32     min,max;        /* min and max target values */
+};
+
+struct wf_cpu_pid_state {
+       int     first;                          /* first run of the loop */
+       int     index;                          /* index of current power */
+       int     tindex;                         /* index of current temp */
+       s32     target;                         /* current target value */
+       s32     powers[WF_PID_MAX_HISTORY];     /* power history buffer */
+       s32     errors[WF_PID_MAX_HISTORY];     /* error history buffer */
+       s32     temps[2];                       /* temp. history buffer */
+
+       struct wf_cpu_pid_param param;
+};
+
+extern void wf_cpu_pid_init(struct wf_cpu_pid_state *st,
+                           struct wf_cpu_pid_param *param);
+extern s32 wf_cpu_pid_run(struct wf_cpu_pid_state *st, s32 power, s32 temp);
diff --git a/drivers/macintosh/windfarm_pm81.c b/drivers/macintosh/windfarm_pm81.c
new file mode 100644 (file)
index 0000000..322c74b
--- /dev/null
@@ -0,0 +1,879 @@
+/*
+ * Windfarm PowerMac thermal control. iMac G5
+ *
+ * (c) Copyright 2005 Benjamin Herrenschmidt, IBM Corp.
+ *                    <benh@kernel.crashing.org>
+ *
+ * Released under the term of the GNU GPL v2.
+ *
+ * The algorithm used is the PID control algorithm, used the same
+ * way the published Darwin code does, using the same values that
+ * are present in the Darwin 8.2 snapshot property lists (note however
+ * that none of the code has been re-used, it's a complete re-implementation
+ *
+ * The various control loops found in Darwin config file are:
+ *
+ * PowerMac8,1 and PowerMac8,2
+ * ===========================
+ *
+ * System Fans control loop. Different based on models. In addition to the
+ * usual PID algorithm, the control loop gets 2 additional pairs of linear
+ * scaling factors (scale/offsets) expressed as 4.12 fixed point values
+ * signed offset, unsigned scale)
+ *
+ * The targets are modified such as:
+ *  - the linked control (second control) gets the target value as-is
+ *    (typically the drive fan)
+ *  - the main control (first control) gets the target value scaled with
+ *    the first pair of factors, and is then modified as below
+ *  - the value of the target of the CPU Fan control loop is retreived,
+ *    scaled with the second pair of factors, and the max of that and
+ *    the scaled target is applied to the main control.
+ *
+ * # model_id: 2
+ *   controls       : system-fan, drive-bay-fan
+ *   sensors        : hd-temp
+ *   PID params     : G_d = 0x15400000
+ *                    G_p = 0x00200000
+ *                    G_r = 0x000002fd
+ *                    History = 2 entries
+ *                    Input target = 0x3a0000
+ *                    Interval = 5s
+ *   linear-factors : offset = 0xff38 scale  = 0x0ccd
+ *                    offset = 0x0208 scale  = 0x07ae
+ *
+ * # model_id: 3
+ *   controls       : system-fan, drive-bay-fan
+ *   sensors        : hd-temp
+ *   PID params     : G_d = 0x08e00000
+ *                    G_p = 0x00566666
+ *                    G_r = 0x0000072b
+ *                    History = 2 entries
+ *                    Input target = 0x350000
+ *                    Interval = 5s
+ *   linear-factors : offset = 0xff38 scale  = 0x0ccd
+ *                    offset = 0x0000 scale  = 0x0000
+ *
+ * # model_id: 5
+ *   controls       : system-fan
+ *   sensors        : hd-temp
+ *   PID params     : G_d = 0x15400000
+ *                    G_p = 0x00233333
+ *                    G_r = 0x000002fd
+ *                    History = 2 entries
+ *                    Input target = 0x3a0000
+ *                    Interval = 5s
+ *   linear-factors : offset = 0x0000 scale  = 0x1000
+ *                    offset = 0x0091 scale  = 0x0bae
+ *
+ * CPU Fan control loop. The loop is identical for all models. it
+ * has an additional pair of scaling factor. This is used to scale the
+ * systems fan control loop target result (the one before it gets scaled
+ * by the System Fans control loop itself). Then, the max value of the
+ * calculated target value and system fan value is sent to the fans
+ *
+ *   controls       : cpu-fan
+ *   sensors        : cpu-temp cpu-power
+ *   PID params     : From SMU sdb partition
+ *   linear-factors : offset = 0xfb50 scale  = 0x1000
+ *
+ * CPU Slew control loop. Not implemented. The cpufreq driver in linux is
+ * completely separate for now, though we could find a way to link it, either
+ * as a client reacting to overtemp notifications, or directling monitoring
+ * the CPU temperature
+ *
+ * WARNING ! The CPU control loop requires the CPU tmax for the current
+ * operating point. However, we currently are completely separated from
+ * the cpufreq driver and thus do not know what the current operating
+ * point is. Fortunately, we also do not have any hardware supporting anything
+ * but operating point 0 at the moment, thus we just peek that value directly
+ * from the SDB partition. If we ever end up with actually slewing the system
+ * clock and thus changing operating points, we'll have to find a way to
+ * communicate with the CPU freq driver;
+ *
+ */
+
+#include <linux/types.h>
+#include <linux/errno.h>
+#include <linux/kernel.h>
+#include <linux/delay.h>
+#include <linux/slab.h>
+#include <linux/init.h>
+#include <linux/spinlock.h>
+#include <linux/wait.h>
+#include <linux/kmod.h>
+#include <linux/device.h>
+#include <linux/platform_device.h>
+#include <asm/prom.h>
+#include <asm/machdep.h>
+#include <asm/io.h>
+#include <asm/system.h>
+#include <asm/sections.h>
+#include <asm/smu.h>
+
+#include "windfarm.h"
+#include "windfarm_pid.h"
+
+#define VERSION "0.4"
+
+#undef DEBUG
+
+#ifdef DEBUG
+#define DBG(args...)   printk(args)
+#else
+#define DBG(args...)   do { } while(0)
+#endif
+
+/* define this to force CPU overtemp to 74 degree, useful for testing
+ * the overtemp code
+ */
+#undef HACKED_OVERTEMP
+
+static int wf_smu_mach_model;  /* machine model id */
+
+static struct device *wf_smu_dev;
+
+/* Controls & sensors */
+static struct wf_sensor        *sensor_cpu_power;
+static struct wf_sensor        *sensor_cpu_temp;
+static struct wf_sensor        *sensor_hd_temp;
+static struct wf_control *fan_cpu_main;
+static struct wf_control *fan_hd;
+static struct wf_control *fan_system;
+static struct wf_control *cpufreq_clamp;
+
+/* Set to kick the control loop into life */
+static int wf_smu_all_controls_ok, wf_smu_all_sensors_ok, wf_smu_started;
+
+/* Failure handling.. could be nicer */
+#define FAILURE_FAN            0x01
+#define FAILURE_SENSOR         0x02
+#define FAILURE_OVERTEMP       0x04
+
+static unsigned int wf_smu_failure_state;
+static int wf_smu_readjust, wf_smu_skipping;
+
+/*
+ * ****** System Fans Control Loop ******
+ *
+ */
+
+/* Parameters for the System Fans control loop. Parameters
+ * not in this table such as interval, history size, ...
+ * are common to all versions and thus hard coded for now.
+ */
+struct wf_smu_sys_fans_param {
+       int     model_id;
+       s32     itarget;
+       s32     gd, gp, gr;
+
+       s16     offset0;
+       u16     scale0;
+       s16     offset1;
+       u16     scale1;
+};
+
+#define WF_SMU_SYS_FANS_INTERVAL       5
+#define WF_SMU_SYS_FANS_HISTORY_SIZE   2
+
+/* State data used by the system fans control loop
+ */
+struct wf_smu_sys_fans_state {
+       int                     ticks;
+       s32                     sys_setpoint;
+       s32                     hd_setpoint;
+       s16                     offset0;
+       u16                     scale0;
+       s16                     offset1;
+       u16                     scale1;
+       struct wf_pid_state     pid;
+};
+
+/*
+ * Configs for SMU Sytem Fan control loop
+ */
+static struct wf_smu_sys_fans_param wf_smu_sys_all_params[] = {
+       /* Model ID 2 */
+       {
+               .model_id       = 2,
+               .itarget        = 0x3a0000,
+               .gd             = 0x15400000,
+               .gp             = 0x00200000,
+               .gr             = 0x000002fd,
+               .offset0        = 0xff38,
+               .scale0         = 0x0ccd,
+               .offset1        = 0x0208,
+               .scale1         = 0x07ae,
+       },
+       /* Model ID 3 */
+       {
+               .model_id       = 2,
+               .itarget        = 0x350000,
+               .gd             = 0x08e00000,
+               .gp             = 0x00566666,
+               .gr             = 0x0000072b,
+               .offset0        = 0xff38,
+               .scale0         = 0x0ccd,
+               .offset1        = 0x0000,
+               .scale1         = 0x0000,
+       },
+       /* Model ID 5 */
+       {
+               .model_id       = 2,
+               .itarget        = 0x3a0000,
+               .gd             = 0x15400000,
+               .gp             = 0x00233333,
+               .gr             = 0x000002fd,
+               .offset0        = 0x0000,
+               .scale0         = 0x1000,
+               .offset1        = 0x0091,
+               .scale1         = 0x0bae,
+       },
+};
+#define WF_SMU_SYS_FANS_NUM_CONFIGS ARRAY_SIZE(wf_smu_sys_all_params)
+
+static struct wf_smu_sys_fans_state *wf_smu_sys_fans;
+
+/*
+ * ****** CPU Fans Control Loop ******
+ *
+ */
+
+
+#define WF_SMU_CPU_FANS_INTERVAL       1
+#define WF_SMU_CPU_FANS_MAX_HISTORY    16
+#define WF_SMU_CPU_FANS_SIBLING_SCALE  0x00001000
+#define WF_SMU_CPU_FANS_SIBLING_OFFSET 0xfffffb50
+
+/* State data used by the cpu fans control loop
+ */
+struct wf_smu_cpu_fans_state {
+       int                     ticks;
+       s32                     cpu_setpoint;
+       s32                     scale;
+       s32                     offset;
+       struct wf_cpu_pid_state pid;
+};
+
+static struct wf_smu_cpu_fans_state *wf_smu_cpu_fans;
+
+
+
+/*
+ * ***** Implementation *****
+ *
+ */
+
+static void wf_smu_create_sys_fans(void)
+{
+       struct wf_smu_sys_fans_param *param = NULL;
+       struct wf_pid_param pid_param;
+       int i;
+
+       /* First, locate the params for this model */
+       for (i = 0; i < WF_SMU_SYS_FANS_NUM_CONFIGS; i++)
+               if (wf_smu_sys_all_params[i].model_id == wf_smu_mach_model) {
+                       param = &wf_smu_sys_all_params[i];
+                       break;
+               }
+
+       /* No params found, put fans to max */
+       if (param == NULL) {
+               printk(KERN_WARNING "windfarm: System fan config not found "
+                      "for this machine model, max fan speed\n");
+               goto fail;
+       }
+
+       /* Alloc & initialize state */
+       wf_smu_sys_fans = kmalloc(sizeof(struct wf_smu_sys_fans_state),
+                                 GFP_KERNEL);
+       if (wf_smu_sys_fans == NULL) {
+               printk(KERN_WARNING "windfarm: Memory allocation error"
+                      " max fan speed\n");
+               goto fail;
+       }
+       wf_smu_sys_fans->ticks = 1;
+       wf_smu_sys_fans->scale0 = param->scale0;
+       wf_smu_sys_fans->offset0 = param->offset0;
+       wf_smu_sys_fans->scale1 = param->scale1;
+       wf_smu_sys_fans->offset1 = param->offset1;
+
+       /* Fill PID params */
+       pid_param.gd = param->gd;
+       pid_param.gp = param->gp;
+       pid_param.gr = param->gr;
+       pid_param.interval = WF_SMU_SYS_FANS_INTERVAL;
+       pid_param.history_len = WF_SMU_SYS_FANS_HISTORY_SIZE;
+       pid_param.itarget = param->itarget;
+       pid_param.min = fan_system->ops->get_min(fan_system);
+       pid_param.max = fan_system->ops->get_max(fan_system);
+       if (fan_hd) {
+               pid_param.min =
+                       max(pid_param.min,fan_hd->ops->get_min(fan_hd));
+               pid_param.max =
+                       min(pid_param.max,fan_hd->ops->get_max(fan_hd));
+       }
+       wf_pid_init(&wf_smu_sys_fans->pid, &pid_param);
+
+       DBG("wf: System Fan control initialized.\n");
+       DBG("    itarged=%d.%03d, min=%d RPM, max=%d RPM\n",
+           FIX32TOPRINT(pid_param.itarget), pid_param.min, pid_param.max);
+       return;
+
+ fail:
+
+       if (fan_system)
+               wf_control_set_max(fan_system);
+       if (fan_hd)
+               wf_control_set_max(fan_hd);
+}
+
+static void wf_smu_sys_fans_tick(struct wf_smu_sys_fans_state *st)
+{
+       s32 new_setpoint, temp, scaled, cputarget;
+       int rc;
+
+       if (--st->ticks != 0) {
+               if (wf_smu_readjust)
+                       goto readjust;
+               return;
+       }
+       st->ticks = WF_SMU_SYS_FANS_INTERVAL;
+
+       rc = sensor_hd_temp->ops->get_value(sensor_hd_temp, &temp);
+       if (rc) {
+               printk(KERN_WARNING "windfarm: HD temp sensor error %d\n",
+                      rc);
+               wf_smu_failure_state |= FAILURE_SENSOR;
+               return;
+       }
+
+       DBG("wf_smu: System Fans tick ! HD temp: %d.%03d\n",
+           FIX32TOPRINT(temp));
+
+       if (temp > (st->pid.param.itarget + 0x50000))
+               wf_smu_failure_state |= FAILURE_OVERTEMP;
+
+       new_setpoint = wf_pid_run(&st->pid, temp);
+
+       DBG("wf_smu: new_setpoint: %d RPM\n", (int)new_setpoint);
+
+       scaled = ((((s64)new_setpoint) * (s64)st->scale0) >> 12) + st->offset0;
+
+       DBG("wf_smu: scaled setpoint: %d RPM\n", (int)scaled);
+
+       cputarget = wf_smu_cpu_fans ? wf_smu_cpu_fans->pid.target : 0;
+       cputarget = ((((s64)cputarget) * (s64)st->scale1) >> 12) + st->offset1;
+       scaled = max(scaled, cputarget);
+       scaled = max(scaled, st->pid.param.min);
+       scaled = min(scaled, st->pid.param.max);
+
+       DBG("wf_smu: adjusted setpoint: %d RPM\n", (int)scaled);
+
+       if (st->sys_setpoint == scaled && new_setpoint == st->hd_setpoint)
+               return;
+       st->sys_setpoint = scaled;
+       st->hd_setpoint = new_setpoint;
+ readjust:
+       if (fan_system && wf_smu_failure_state == 0) {
+               rc = fan_system->ops->set_value(fan_system, st->sys_setpoint);
+               if (rc) {
+                       printk(KERN_WARNING "windfarm: Sys fan error %d\n",
+                              rc);
+                       wf_smu_failure_state |= FAILURE_FAN;
+               }
+       }
+       if (fan_hd && wf_smu_failure_state == 0) {
+               rc = fan_hd->ops->set_value(fan_hd, st->hd_setpoint);
+               if (rc) {
+                       printk(KERN_WARNING "windfarm: HD fan error %d\n",
+                              rc);
+                       wf_smu_failure_state |= FAILURE_FAN;
+               }
+       }
+}
+
+static void wf_smu_create_cpu_fans(void)
+{
+       struct wf_cpu_pid_param pid_param;
+       struct smu_sdbp_header *hdr;
+       struct smu_sdbp_cpupiddata *piddata;
+       struct smu_sdbp_fvt *fvt;
+       s32 tmax, tdelta, maxpow, powadj;
+
+       /* First, locate the PID params in SMU SBD */
+       hdr = smu_get_sdb_partition(SMU_SDB_CPUPIDDATA_ID, NULL);
+       if (hdr == 0) {
+               printk(KERN_WARNING "windfarm: CPU PID fan config not found "
+                      "max fan speed\n");
+               goto fail;
+       }
+       piddata = (struct smu_sdbp_cpupiddata *)&hdr[1];
+
+       /* Get the FVT params for operating point 0 (the only supported one
+        * for now) in order to get tmax
+        */
+       hdr = smu_get_sdb_partition(SMU_SDB_FVT_ID, NULL);
+       if (hdr) {
+               fvt = (struct smu_sdbp_fvt *)&hdr[1];
+               tmax = ((s32)fvt->maxtemp) << 16;
+       } else
+               tmax = 0x5e0000; /* 94 degree default */
+
+       /* Alloc & initialize state */
+       wf_smu_cpu_fans = kmalloc(sizeof(struct wf_smu_cpu_fans_state),
+                                 GFP_KERNEL);
+       if (wf_smu_cpu_fans == NULL)
+               goto fail;
+               wf_smu_cpu_fans->ticks = 1;
+
+       wf_smu_cpu_fans->scale = WF_SMU_CPU_FANS_SIBLING_SCALE;
+       wf_smu_cpu_fans->offset = WF_SMU_CPU_FANS_SIBLING_OFFSET;
+
+       /* Fill PID params */
+       pid_param.interval = WF_SMU_CPU_FANS_INTERVAL;
+       pid_param.history_len = piddata->history_len;
+       if (pid_param.history_len > WF_CPU_PID_MAX_HISTORY) {
+               printk(KERN_WARNING "windfarm: History size overflow on "
+                      "CPU control loop (%d)\n", piddata->history_len);
+               pid_param.history_len = WF_CPU_PID_MAX_HISTORY;
+       }
+       pid_param.gd = piddata->gd;
+       pid_param.gp = piddata->gp;
+       pid_param.gr = piddata->gr / pid_param.history_len;
+
+       tdelta = ((s32)piddata->target_temp_delta) << 16;
+       maxpow = ((s32)piddata->max_power) << 16;
+       powadj = ((s32)piddata->power_adj) << 16;
+
+       pid_param.tmax = tmax;
+       pid_param.ttarget = tmax - tdelta;
+       pid_param.pmaxadj = maxpow - powadj;
+
+       pid_param.min = fan_cpu_main->ops->get_min(fan_cpu_main);
+       pid_param.max = fan_cpu_main->ops->get_max(fan_cpu_main);
+
+       wf_cpu_pid_init(&wf_smu_cpu_fans->pid, &pid_param);
+
+       DBG("wf: CPU Fan control initialized.\n");
+       DBG("    ttarged=%d.%03d, tmax=%d.%03d, min=%d RPM, max=%d RPM\n",
+           FIX32TOPRINT(pid_param.ttarget), FIX32TOPRINT(pid_param.tmax),
+           pid_param.min, pid_param.max);
+
+       return;
+
+ fail:
+       printk(KERN_WARNING "windfarm: CPU fan config not found\n"
+              "for this machine model, max fan speed\n");
+
+       if (cpufreq_clamp)
+               wf_control_set_max(cpufreq_clamp);
+       if (fan_cpu_main)
+               wf_control_set_max(fan_cpu_main);
+}
+
+static void wf_smu_cpu_fans_tick(struct wf_smu_cpu_fans_state *st)
+{
+       s32 new_setpoint, temp, power, systarget;
+       int rc;
+
+       if (--st->ticks != 0) {
+               if (wf_smu_readjust)
+                       goto readjust;
+               return;
+       }
+       st->ticks = WF_SMU_CPU_FANS_INTERVAL;
+
+       rc = sensor_cpu_temp->ops->get_value(sensor_cpu_temp, &temp);
+       if (rc) {
+               printk(KERN_WARNING "windfarm: CPU temp sensor error %d\n",
+                      rc);
+               wf_smu_failure_state |= FAILURE_SENSOR;
+               return;
+       }
+
+       rc = sensor_cpu_power->ops->get_value(sensor_cpu_power, &power);
+       if (rc) {
+               printk(KERN_WARNING "windfarm: CPU power sensor error %d\n",
+                      rc);
+               wf_smu_failure_state |= FAILURE_SENSOR;
+               return;
+       }
+
+       DBG("wf_smu: CPU Fans tick ! CPU temp: %d.%03d, power: %d.%03d\n",
+           FIX32TOPRINT(temp), FIX32TOPRINT(power));
+
+#ifdef HACKED_OVERTEMP
+       if (temp > 0x4a0000)
+               wf_smu_failure_state |= FAILURE_OVERTEMP;
+#else
+       if (temp > st->pid.param.tmax)
+               wf_smu_failure_state |= FAILURE_OVERTEMP;
+#endif
+       new_setpoint = wf_cpu_pid_run(&st->pid, power, temp);
+
+       DBG("wf_smu: new_setpoint: %d RPM\n", (int)new_setpoint);
+
+       systarget = wf_smu_sys_fans ? wf_smu_sys_fans->pid.target : 0;
+       systarget = ((((s64)systarget) * (s64)st->scale) >> 12)
+               + st->offset;
+       new_setpoint = max(new_setpoint, systarget);
+       new_setpoint = max(new_setpoint, st->pid.param.min);
+       new_setpoint = min(new_setpoint, st->pid.param.max);
+
+       DBG("wf_smu: adjusted setpoint: %d RPM\n", (int)new_setpoint);
+
+       if (st->cpu_setpoint == new_setpoint)
+               return;
+       st->cpu_setpoint = new_setpoint;
+ readjust:
+       if (fan_cpu_main && wf_smu_failure_state == 0) {
+               rc = fan_cpu_main->ops->set_value(fan_cpu_main,
+                                                 st->cpu_setpoint);
+               if (rc) {
+                       printk(KERN_WARNING "windfarm: CPU main fan"
+                              " error %d\n", rc);
+                       wf_smu_failure_state |= FAILURE_FAN;
+               }
+       }
+}
+
+
+/*
+ * ****** Attributes ******
+ *
+ */
+
+#define BUILD_SHOW_FUNC_FIX(name, data)                                \
+static ssize_t show_##name(struct device *dev,                  \
+                          struct device_attribute *attr,       \
+                          char *buf)                           \
+{                                                              \
+       ssize_t r;                                              \
+       s32 val = 0;                                            \
+       data->ops->get_value(data, &val);                       \
+       r = sprintf(buf, "%d.%03d", FIX32TOPRINT(val));         \
+       return r;                                               \
+}                                                               \
+static DEVICE_ATTR(name,S_IRUGO,show_##name, NULL);
+
+
+#define BUILD_SHOW_FUNC_INT(name, data)                                \
+static ssize_t show_##name(struct device *dev,                  \
+                          struct device_attribute *attr,       \
+                          char *buf)                           \
+{                                                              \
+       s32 val = 0;                                            \
+       data->ops->get_value(data, &val);                       \
+       return sprintf(buf, "%d", val);                         \
+}                                                               \
+static DEVICE_ATTR(name,S_IRUGO,show_##name, NULL);
+
+BUILD_SHOW_FUNC_INT(cpu_fan, fan_cpu_main);
+BUILD_SHOW_FUNC_INT(sys_fan, fan_system);
+BUILD_SHOW_FUNC_INT(hd_fan, fan_hd);
+
+BUILD_SHOW_FUNC_FIX(cpu_temp, sensor_cpu_temp);
+BUILD_SHOW_FUNC_FIX(cpu_power, sensor_cpu_power);
+BUILD_SHOW_FUNC_FIX(hd_temp, sensor_hd_temp);
+
+/*
+ * ****** Setup / Init / Misc ... ******
+ *
+ */
+
+static void wf_smu_tick(void)
+{
+       unsigned int last_failure = wf_smu_failure_state;
+       unsigned int new_failure;
+
+       if (!wf_smu_started) {
+               DBG("wf: creating control loops !\n");
+               wf_smu_create_sys_fans();
+               wf_smu_create_cpu_fans();
+               wf_smu_started = 1;
+       }
+
+       /* Skipping ticks */
+       if (wf_smu_skipping && --wf_smu_skipping)
+               return;
+
+       wf_smu_failure_state = 0;
+       if (wf_smu_sys_fans)
+               wf_smu_sys_fans_tick(wf_smu_sys_fans);
+       if (wf_smu_cpu_fans)
+               wf_smu_cpu_fans_tick(wf_smu_cpu_fans);
+
+       wf_smu_readjust = 0;
+       new_failure = wf_smu_failure_state & ~last_failure;
+
+       /* If entering failure mode, clamp cpufreq and ramp all
+        * fans to full speed.
+        */
+       if (wf_smu_failure_state && !last_failure) {
+               if (cpufreq_clamp)
+                       wf_control_set_max(cpufreq_clamp);
+               if (fan_system)
+                       wf_control_set_max(fan_system);
+               if (fan_cpu_main)
+                       wf_control_set_max(fan_cpu_main);
+               if (fan_hd)
+                       wf_control_set_max(fan_hd);
+       }
+
+       /* If leaving failure mode, unclamp cpufreq and readjust
+        * all fans on next iteration
+        */
+       if (!wf_smu_failure_state && last_failure) {
+               if (cpufreq_clamp)
+                       wf_control_set_min(cpufreq_clamp);
+               wf_smu_readjust = 1;
+       }
+
+       /* Overtemp condition detected, notify and start skipping a couple
+        * ticks to let the temperature go down
+        */
+       if (new_failure & FAILURE_OVERTEMP) {
+               wf_set_overtemp();
+               wf_smu_skipping = 2;
+       }
+
+       /* We only clear the overtemp condition if overtemp is cleared
+        * _and_ no other failure is present. Since a sensor error will
+        * clear the overtemp condition (can't measure temperature) at
+        * the control loop levels, but we don't want to keep it clear
+        * here in this case
+        */
+       if (new_failure == 0 && last_failure & FAILURE_OVERTEMP)
+               wf_clear_overtemp();
+}
+
+static void wf_smu_new_control(struct wf_control *ct)
+{
+       if (wf_smu_all_controls_ok)
+               return;
+
+       if (fan_cpu_main == NULL && !strcmp(ct->name, "cpu-fan")) {
+               if (wf_get_control(ct) == 0) {
+                       fan_cpu_main = ct;
+                       device_create_file(wf_smu_dev, &dev_attr_cpu_fan);
+               }
+       }
+
+       if (fan_system == NULL && !strcmp(ct->name, "system-fan")) {
+               if (wf_get_control(ct) == 0) {
+                       fan_system = ct;
+                       device_create_file(wf_smu_dev, &dev_attr_sys_fan);
+               }
+       }
+
+       if (cpufreq_clamp == NULL && !strcmp(ct->name, "cpufreq-clamp")) {
+               if (wf_get_control(ct) == 0)
+                       cpufreq_clamp = ct;
+       }
+
+       /* Darwin property list says the HD fan is only for model ID
+        * 0, 1, 2 and 3
+        */
+
+       if (wf_smu_mach_model > 3) {
+               if (fan_system && fan_cpu_main && cpufreq_clamp)
+                       wf_smu_all_controls_ok = 1;
+               return;
+       }
+
+       if (fan_hd == NULL && !strcmp(ct->name, "drive-bay-fan")) {
+               if (wf_get_control(ct) == 0) {
+                       fan_hd = ct;
+                       device_create_file(wf_smu_dev, &dev_attr_hd_fan);
+               }
+       }
+
+       if (fan_system && fan_hd && fan_cpu_main && cpufreq_clamp)
+               wf_smu_all_controls_ok = 1;
+}
+
+static void wf_smu_new_sensor(struct wf_sensor *sr)
+{
+       if (wf_smu_all_sensors_ok)
+               return;
+
+       if (sensor_cpu_power == NULL && !strcmp(sr->name, "cpu-power")) {
+               if (wf_get_sensor(sr) == 0) {
+                       sensor_cpu_power = sr;
+                       device_create_file(wf_smu_dev, &dev_attr_cpu_power);
+               }
+       }
+
+       if (sensor_cpu_temp == NULL && !strcmp(sr->name, "cpu-temp")) {
+               if (wf_get_sensor(sr) == 0) {
+                       sensor_cpu_temp = sr;
+                       device_create_file(wf_smu_dev, &dev_attr_cpu_temp);
+               }
+       }
+
+       if (sensor_hd_temp == NULL && !strcmp(sr->name, "hd-temp")) {
+               if (wf_get_sensor(sr) == 0) {
+                       sensor_hd_temp = sr;
+                       device_create_file(wf_smu_dev, &dev_attr_hd_temp);
+               }
+       }
+
+       if (sensor_cpu_power && sensor_cpu_temp && sensor_hd_temp)
+               wf_smu_all_sensors_ok = 1;
+}
+
+
+static int wf_smu_notify(struct notifier_block *self,
+                              unsigned long event, void *data)
+{
+       switch(event) {
+       case WF_EVENT_NEW_CONTROL:
+               DBG("wf: new control %s detected\n",
+                   ((struct wf_control *)data)->name);
+               wf_smu_new_control(data);
+               wf_smu_readjust = 1;
+               break;
+       case WF_EVENT_NEW_SENSOR:
+               DBG("wf: new sensor %s detected\n",
+                   ((struct wf_sensor *)data)->name);
+               wf_smu_new_sensor(data);
+               break;
+       case WF_EVENT_TICK:
+               if (wf_smu_all_controls_ok && wf_smu_all_sensors_ok)
+                       wf_smu_tick();
+       }
+
+       return 0;
+}
+
+static struct notifier_block wf_smu_events = {
+       .notifier_call  = wf_smu_notify,
+};
+
+static int wf_init_pm(void)
+{
+       struct smu_sdbp_header *hdr;
+
+       hdr = smu_get_sdb_partition(SMU_SDB_SENSORTREE_ID, NULL);
+       if (hdr != 0) {
+               struct smu_sdbp_sensortree *st =
+                       (struct smu_sdbp_sensortree *)&hdr[1];
+               wf_smu_mach_model = st->model_id;
+       }
+
+       printk(KERN_INFO "windfarm: Initializing for iMacG5 model ID %d\n",
+              wf_smu_mach_model);
+
+       return 0;
+}
+
+static int wf_smu_probe(struct device *ddev)
+{
+       wf_smu_dev = ddev;
+
+       wf_register_client(&wf_smu_events);
+
+       return 0;
+}
+
+static int wf_smu_remove(struct device *ddev)
+{
+       wf_unregister_client(&wf_smu_events);
+
+       /* XXX We don't have yet a guarantee that our callback isn't
+        * in progress when returning from wf_unregister_client, so
+        * we add an arbitrary delay. I'll have to fix that in the core
+        */
+       msleep(1000);
+
+       /* Release all sensors */
+       /* One more crappy race: I don't think we have any guarantee here
+        * that the attribute callback won't race with the sensor beeing
+        * disposed of, and I'm not 100% certain what best way to deal
+        * with that except by adding locks all over... I'll do that
+        * eventually but heh, who ever rmmod this module anyway ?
+        */
+       if (sensor_cpu_power) {
+               device_remove_file(wf_smu_dev, &dev_attr_cpu_power);
+               wf_put_sensor(sensor_cpu_power);
+       }
+       if (sensor_cpu_temp) {
+               device_remove_file(wf_smu_dev, &dev_attr_cpu_temp);
+               wf_put_sensor(sensor_cpu_temp);
+       }
+       if (sensor_hd_temp) {
+               device_remove_file(wf_smu_dev, &dev_attr_hd_temp);
+               wf_put_sensor(sensor_hd_temp);
+       }
+
+       /* Release all controls */
+       if (fan_cpu_main) {
+               device_remove_file(wf_smu_dev, &dev_attr_cpu_fan);
+               wf_put_control(fan_cpu_main);
+       }
+       if (fan_hd) {
+               device_remove_file(wf_smu_dev, &dev_attr_hd_fan);
+               wf_put_control(fan_hd);
+       }
+       if (fan_system) {
+               device_remove_file(wf_smu_dev, &dev_attr_sys_fan);
+               wf_put_control(fan_system);
+       }
+       if (cpufreq_clamp)
+               wf_put_control(cpufreq_clamp);
+
+       /* Destroy control loops state structures */
+       if (wf_smu_sys_fans)
+               kfree(wf_smu_sys_fans);
+       if (wf_smu_cpu_fans)
+               kfree(wf_smu_cpu_fans);
+
+       wf_smu_dev = NULL;
+
+       return 0;
+}
+
+static struct device_driver wf_smu_driver = {
+        .name = "windfarm",
+        .bus = &platform_bus_type,
+        .probe = wf_smu_probe,
+        .remove = wf_smu_remove,
+};
+
+
+static int __init wf_smu_init(void)
+{
+       int rc = -ENODEV;
+
+       if (machine_is_compatible("PowerMac8,1") ||
+           machine_is_compatible("PowerMac8,2"))
+               rc = wf_init_pm();
+
+       if (rc == 0) {
+#ifdef MODULE
+               request_module("windfarm_smu_controls");
+               request_module("windfarm_smu_sensors");
+               request_module("windfarm_lm75_sensor");
+
+#endif /* MODULE */
+               driver_register(&wf_smu_driver);
+       }
+
+       return rc;
+}
+
+static void __exit wf_smu_exit(void)
+{
+
+       driver_unregister(&wf_smu_driver);
+}
+
+
+module_init(wf_smu_init);
+module_exit(wf_smu_exit);
+
+MODULE_AUTHOR("Benjamin Herrenschmidt <benh@kernel.crashing.org>");
+MODULE_DESCRIPTION("Thermal control logic for iMac G5");
+MODULE_LICENSE("GPL");
+
diff --git a/drivers/macintosh/windfarm_pm91.c b/drivers/macintosh/windfarm_pm91.c
new file mode 100644 (file)
index 0000000..43243cf
--- /dev/null
@@ -0,0 +1,814 @@
+/*
+ * Windfarm PowerMac thermal control. SMU based 1 CPU desktop control loops
+ *
+ * (c) Copyright 2005 Benjamin Herrenschmidt, IBM Corp.
+ *                    <benh@kernel.crashing.org>
+ *
+ * Released under the term of the GNU GPL v2.
+ *
+ * The algorithm used is the PID control algorithm, used the same
+ * way the published Darwin code does, using the same values that
+ * are present in the Darwin 8.2 snapshot property lists (note however
+ * that none of the code has been re-used, it's a complete re-implementation
+ *
+ * The various control loops found in Darwin config file are:
+ *
+ * PowerMac9,1
+ * ===========
+ *
+ * Has 3 control loops: CPU fans is similar to PowerMac8,1 (though it doesn't
+ * try to play with other control loops fans). Drive bay is rather basic PID
+ * with one sensor and one fan. Slots area is a bit different as the Darwin
+ * driver is supposed to be capable of working in a special "AGP" mode which
+ * involves the presence of an AGP sensor and an AGP fan (possibly on the
+ * AGP card itself). I can't deal with that special mode as I don't have
+ * access to those additional sensor/fans for now (though ultimately, it would
+ * be possible to add sensor objects for them) so I'm only implementing the
+ * basic PCI slot control loop
+ */
+
+#include <linux/types.h>
+#include <linux/errno.h>
+#include <linux/kernel.h>
+#include <linux/delay.h>
+#include <linux/slab.h>
+#include <linux/init.h>
+#include <linux/spinlock.h>
+#include <linux/wait.h>
+#include <linux/kmod.h>
+#include <linux/device.h>
+#include <linux/platform_device.h>
+#include <asm/prom.h>
+#include <asm/machdep.h>
+#include <asm/io.h>
+#include <asm/system.h>
+#include <asm/sections.h>
+#include <asm/smu.h>
+
+#include "windfarm.h"
+#include "windfarm_pid.h"
+
+#define VERSION "0.4"
+
+#undef DEBUG
+
+#ifdef DEBUG
+#define DBG(args...)   printk(args)
+#else
+#define DBG(args...)   do { } while(0)
+#endif
+
+/* define this to force CPU overtemp to 74 degree, useful for testing
+ * the overtemp code
+ */
+#undef HACKED_OVERTEMP
+
+static struct device *wf_smu_dev;
+
+/* Controls & sensors */
+static struct wf_sensor        *sensor_cpu_power;
+static struct wf_sensor        *sensor_cpu_temp;
+static struct wf_sensor        *sensor_hd_temp;
+static struct wf_sensor        *sensor_slots_power;
+static struct wf_control *fan_cpu_main;
+static struct wf_control *fan_cpu_second;
+static struct wf_control *fan_cpu_third;
+static struct wf_control *fan_hd;
+static struct wf_control *fan_slots;
+static struct wf_control *cpufreq_clamp;
+
+/* Set to kick the control loop into life */
+static int wf_smu_all_controls_ok, wf_smu_all_sensors_ok, wf_smu_started;
+
+/* Failure handling.. could be nicer */
+#define FAILURE_FAN            0x01
+#define FAILURE_SENSOR         0x02
+#define FAILURE_OVERTEMP       0x04
+
+static unsigned int wf_smu_failure_state;
+static int wf_smu_readjust, wf_smu_skipping;
+
+/*
+ * ****** CPU Fans Control Loop ******
+ *
+ */
+
+
+#define WF_SMU_CPU_FANS_INTERVAL       1
+#define WF_SMU_CPU_FANS_MAX_HISTORY    16
+
+/* State data used by the cpu fans control loop
+ */
+struct wf_smu_cpu_fans_state {
+       int                     ticks;
+       s32                     cpu_setpoint;
+       struct wf_cpu_pid_state pid;
+};
+
+static struct wf_smu_cpu_fans_state *wf_smu_cpu_fans;
+
+
+
+/*
+ * ****** Drive Fan Control Loop ******
+ *
+ */
+
+struct wf_smu_drive_fans_state {
+       int                     ticks;
+       s32                     setpoint;
+       struct wf_pid_state     pid;
+};
+
+static struct wf_smu_drive_fans_state *wf_smu_drive_fans;
+
+/*
+ * ****** Slots Fan Control Loop ******
+ *
+ */
+
+struct wf_smu_slots_fans_state {
+       int                     ticks;
+       s32                     setpoint;
+       struct wf_pid_state     pid;
+};
+
+static struct wf_smu_slots_fans_state *wf_smu_slots_fans;
+
+/*
+ * ***** Implementation *****
+ *
+ */
+
+
+static void wf_smu_create_cpu_fans(void)
+{
+       struct wf_cpu_pid_param pid_param;
+       struct smu_sdbp_header *hdr;
+       struct smu_sdbp_cpupiddata *piddata;
+       struct smu_sdbp_fvt *fvt;
+       s32 tmax, tdelta, maxpow, powadj;
+
+       /* First, locate the PID params in SMU SBD */
+       hdr = smu_get_sdb_partition(SMU_SDB_CPUPIDDATA_ID, NULL);
+       if (hdr == 0) {
+               printk(KERN_WARNING "windfarm: CPU PID fan config not found "
+                      "max fan speed\n");
+               goto fail;
+       }
+       piddata = (struct smu_sdbp_cpupiddata *)&hdr[1];
+
+       /* Get the FVT params for operating point 0 (the only supported one
+        * for now) in order to get tmax
+        */
+       hdr = smu_get_sdb_partition(SMU_SDB_FVT_ID, NULL);
+       if (hdr) {
+               fvt = (struct smu_sdbp_fvt *)&hdr[1];
+               tmax = ((s32)fvt->maxtemp) << 16;
+       } else
+               tmax = 0x5e0000; /* 94 degree default */
+
+       /* Alloc & initialize state */
+       wf_smu_cpu_fans = kmalloc(sizeof(struct wf_smu_cpu_fans_state),
+                                 GFP_KERNEL);
+       if (wf_smu_cpu_fans == NULL)
+               goto fail;
+               wf_smu_cpu_fans->ticks = 1;
+
+       /* Fill PID params */
+       pid_param.interval = WF_SMU_CPU_FANS_INTERVAL;
+       pid_param.history_len = piddata->history_len;
+       if (pid_param.history_len > WF_CPU_PID_MAX_HISTORY) {
+               printk(KERN_WARNING "windfarm: History size overflow on "
+                      "CPU control loop (%d)\n", piddata->history_len);
+               pid_param.history_len = WF_CPU_PID_MAX_HISTORY;
+       }
+       pid_param.gd = piddata->gd;
+       pid_param.gp = piddata->gp;
+       pid_param.gr = piddata->gr / pid_param.history_len;
+
+       tdelta = ((s32)piddata->target_temp_delta) << 16;
+       maxpow = ((s32)piddata->max_power) << 16;
+       powadj = ((s32)piddata->power_adj) << 16;
+
+       pid_param.tmax = tmax;
+       pid_param.ttarget = tmax - tdelta;
+       pid_param.pmaxadj = maxpow - powadj;
+
+       pid_param.min = fan_cpu_main->ops->get_min(fan_cpu_main);
+       pid_param.max = fan_cpu_main->ops->get_max(fan_cpu_main);
+
+       wf_cpu_pid_init(&wf_smu_cpu_fans->pid, &pid_param);
+
+       DBG("wf: CPU Fan control initialized.\n");
+       DBG("    ttarged=%d.%03d, tmax=%d.%03d, min=%d RPM, max=%d RPM\n",
+           FIX32TOPRINT(pid_param.ttarget), FIX32TOPRINT(pid_param.tmax),
+           pid_param.min, pid_param.max);
+
+       return;
+
+ fail:
+       printk(KERN_WARNING "windfarm: CPU fan config not found\n"
+              "for this machine model, max fan speed\n");
+
+       if (cpufreq_clamp)
+               wf_control_set_max(cpufreq_clamp);
+       if (fan_cpu_main)
+               wf_control_set_max(fan_cpu_main);
+}
+
+static void wf_smu_cpu_fans_tick(struct wf_smu_cpu_fans_state *st)
+{
+       s32 new_setpoint, temp, power;
+       int rc;
+
+       if (--st->ticks != 0) {
+               if (wf_smu_readjust)
+                       goto readjust;
+               return;
+       }
+       st->ticks = WF_SMU_CPU_FANS_INTERVAL;
+
+       rc = sensor_cpu_temp->ops->get_value(sensor_cpu_temp, &temp);
+       if (rc) {
+               printk(KERN_WARNING "windfarm: CPU temp sensor error %d\n",
+                      rc);
+               wf_smu_failure_state |= FAILURE_SENSOR;
+               return;
+       }
+
+       rc = sensor_cpu_power->ops->get_value(sensor_cpu_power, &power);
+       if (rc) {
+               printk(KERN_WARNING "windfarm: CPU power sensor error %d\n",
+                      rc);
+               wf_smu_failure_state |= FAILURE_SENSOR;
+               return;
+       }
+
+       DBG("wf_smu: CPU Fans tick ! CPU temp: %d.%03d, power: %d.%03d\n",
+           FIX32TOPRINT(temp), FIX32TOPRINT(power));
+
+#ifdef HACKED_OVERTEMP
+       if (temp > 0x4a0000)
+               wf_smu_failure_state |= FAILURE_OVERTEMP;
+#else
+       if (temp > st->pid.param.tmax)
+               wf_smu_failure_state |= FAILURE_OVERTEMP;
+#endif
+       new_setpoint = wf_cpu_pid_run(&st->pid, power, temp);
+
+       DBG("wf_smu: new_setpoint: %d RPM\n", (int)new_setpoint);
+
+       if (st->cpu_setpoint == new_setpoint)
+               return;
+       st->cpu_setpoint = new_setpoint;
+ readjust:
+       if (fan_cpu_main && wf_smu_failure_state == 0) {
+               rc = fan_cpu_main->ops->set_value(fan_cpu_main,
+                                                 st->cpu_setpoint);
+               if (rc) {
+                       printk(KERN_WARNING "windfarm: CPU main fan"
+                              " error %d\n", rc);
+                       wf_smu_failure_state |= FAILURE_FAN;
+               }
+       }
+       if (fan_cpu_second && wf_smu_failure_state == 0) {
+               rc = fan_cpu_second->ops->set_value(fan_cpu_second,
+                                                   st->cpu_setpoint);
+               if (rc) {
+                       printk(KERN_WARNING "windfarm: CPU second fan"
+                              " error %d\n", rc);
+                       wf_smu_failure_state |= FAILURE_FAN;
+               }
+       }
+       if (fan_cpu_third && wf_smu_failure_state == 0) {
+               rc = fan_cpu_main->ops->set_value(fan_cpu_third,
+                                                 st->cpu_setpoint);
+               if (rc) {
+                       printk(KERN_WARNING "windfarm: CPU third fan"
+                              " error %d\n", rc);
+                       wf_smu_failure_state |= FAILURE_FAN;
+               }
+       }
+}
+
+static void wf_smu_create_drive_fans(void)
+{
+       struct wf_pid_param param = {
+               .interval       = 5,
+               .history_len    = 2,
+               .gd             = 0x01e00000,
+               .gp             = 0x00500000,
+               .gr             = 0x00000000,
+               .itarget        = 0x00200000,
+       };
+
+       /* Alloc & initialize state */
+       wf_smu_drive_fans = kmalloc(sizeof(struct wf_smu_drive_fans_state),
+                                       GFP_KERNEL);
+       if (wf_smu_drive_fans == NULL) {
+               printk(KERN_WARNING "windfarm: Memory allocation error"
+                      " max fan speed\n");
+               goto fail;
+       }
+               wf_smu_drive_fans->ticks = 1;
+
+       /* Fill PID params */
+       param.additive = (fan_hd->type == WF_CONTROL_RPM_FAN);
+       param.min = fan_hd->ops->get_min(fan_hd);
+       param.max = fan_hd->ops->get_max(fan_hd);
+       wf_pid_init(&wf_smu_drive_fans->pid, &param);
+
+       DBG("wf: Drive Fan control initialized.\n");
+       DBG("    itarged=%d.%03d, min=%d RPM, max=%d RPM\n",
+           FIX32TOPRINT(param.itarget), param.min, param.max);
+       return;
+
+ fail:
+       if (fan_hd)
+               wf_control_set_max(fan_hd);
+}
+
+static void wf_smu_drive_fans_tick(struct wf_smu_drive_fans_state *st)
+{
+       s32 new_setpoint, temp;
+       int rc;
+
+       if (--st->ticks != 0) {
+               if (wf_smu_readjust)
+                       goto readjust;
+               return;
+       }
+       st->ticks = st->pid.param.interval;
+
+       rc = sensor_hd_temp->ops->get_value(sensor_hd_temp, &temp);
+       if (rc) {
+               printk(KERN_WARNING "windfarm: HD temp sensor error %d\n",
+                      rc);
+               wf_smu_failure_state |= FAILURE_SENSOR;
+               return;
+       }
+
+       DBG("wf_smu: Drive Fans tick ! HD temp: %d.%03d\n",
+           FIX32TOPRINT(temp));
+
+       if (temp > (st->pid.param.itarget + 0x50000))
+               wf_smu_failure_state |= FAILURE_OVERTEMP;
+
+       new_setpoint = wf_pid_run(&st->pid, temp);
+
+       DBG("wf_smu: new_setpoint: %d\n", (int)new_setpoint);
+
+       if (st->setpoint == new_setpoint)
+               return;
+       st->setpoint = new_setpoint;
+ readjust:
+       if (fan_hd && wf_smu_failure_state == 0) {
+               rc = fan_hd->ops->set_value(fan_hd, st->setpoint);
+               if (rc) {
+                       printk(KERN_WARNING "windfarm: HD fan error %d\n",
+                              rc);
+                       wf_smu_failure_state |= FAILURE_FAN;
+               }
+       }
+}
+
+static void wf_smu_create_slots_fans(void)
+{
+       struct wf_pid_param param = {
+               .interval       = 1,
+               .history_len    = 8,
+               .gd             = 0x00000000,
+               .gp             = 0x00000000,
+               .gr             = 0x00020000,
+               .itarget        = 0x00000000
+       };
+
+       /* Alloc & initialize state */
+       wf_smu_slots_fans = kmalloc(sizeof(struct wf_smu_slots_fans_state),
+                                       GFP_KERNEL);
+       if (wf_smu_slots_fans == NULL) {
+               printk(KERN_WARNING "windfarm: Memory allocation error"
+                      " max fan speed\n");
+               goto fail;
+       }
+               wf_smu_slots_fans->ticks = 1;
+
+       /* Fill PID params */
+       param.additive = (fan_slots->type == WF_CONTROL_RPM_FAN);
+       param.min = fan_slots->ops->get_min(fan_slots);
+       param.max = fan_slots->ops->get_max(fan_slots);
+       wf_pid_init(&wf_smu_slots_fans->pid, &param);
+
+       DBG("wf: Slots Fan control initialized.\n");
+       DBG("    itarged=%d.%03d, min=%d RPM, max=%d RPM\n",
+           FIX32TOPRINT(param.itarget), param.min, param.max);
+       return;
+
+ fail:
+       if (fan_slots)
+               wf_control_set_max(fan_slots);
+}
+
+static void wf_smu_slots_fans_tick(struct wf_smu_slots_fans_state *st)
+{
+       s32 new_setpoint, power;
+       int rc;
+
+       if (--st->ticks != 0) {
+               if (wf_smu_readjust)
+                       goto readjust;
+               return;
+       }
+       st->ticks = st->pid.param.interval;
+
+       rc = sensor_slots_power->ops->get_value(sensor_slots_power, &power);
+       if (rc) {
+               printk(KERN_WARNING "windfarm: Slots power sensor error %d\n",
+                      rc);
+               wf_smu_failure_state |= FAILURE_SENSOR;
+               return;
+       }
+
+       DBG("wf_smu: Slots Fans tick ! Slots power: %d.%03d\n",
+           FIX32TOPRINT(power));
+
+#if 0 /* Check what makes a good overtemp condition */
+       if (power > (st->pid.param.itarget + 0x50000))
+               wf_smu_failure_state |= FAILURE_OVERTEMP;
+#endif
+
+       new_setpoint = wf_pid_run(&st->pid, power);
+
+       DBG("wf_smu: new_setpoint: %d\n", (int)new_setpoint);
+
+       if (st->setpoint == new_setpoint)
+               return;
+       st->setpoint = new_setpoint;
+ readjust:
+       if (fan_slots && wf_smu_failure_state == 0) {
+               rc = fan_slots->ops->set_value(fan_slots, st->setpoint);
+               if (rc) {
+                       printk(KERN_WARNING "windfarm: Slots fan error %d\n",
+                              rc);
+                       wf_smu_failure_state |= FAILURE_FAN;
+               }
+       }
+}
+
+
+/*
+ * ****** Attributes ******
+ *
+ */
+
+#define BUILD_SHOW_FUNC_FIX(name, data)                                \
+static ssize_t show_##name(struct device *dev,                  \
+                          struct device_attribute *attr,       \
+                          char *buf)                           \
+{                                                              \
+       ssize_t r;                                              \
+       s32 val = 0;                                            \
+       data->ops->get_value(data, &val);                       \
+       r = sprintf(buf, "%d.%03d", FIX32TOPRINT(val));         \
+       return r;                                               \
+}                                                               \
+static DEVICE_ATTR(name,S_IRUGO,show_##name, NULL);
+
+
+#define BUILD_SHOW_FUNC_INT(name, data)                                \
+static ssize_t show_##name(struct device *dev,                  \
+                          struct device_attribute *attr,       \
+                          char *buf)                           \
+{                                                              \
+       s32 val = 0;                                            \
+       data->ops->get_value(data, &val);                       \
+       return sprintf(buf, "%d", val);                         \
+}                                                               \
+static DEVICE_ATTR(name,S_IRUGO,show_##name, NULL);
+
+BUILD_SHOW_FUNC_INT(cpu_fan, fan_cpu_main);
+BUILD_SHOW_FUNC_INT(hd_fan, fan_hd);
+BUILD_SHOW_FUNC_INT(slots_fan, fan_slots);
+
+BUILD_SHOW_FUNC_FIX(cpu_temp, sensor_cpu_temp);
+BUILD_SHOW_FUNC_FIX(cpu_power, sensor_cpu_power);
+BUILD_SHOW_FUNC_FIX(hd_temp, sensor_hd_temp);
+BUILD_SHOW_FUNC_FIX(slots_power, sensor_slots_power);
+
+/*
+ * ****** Setup / Init / Misc ... ******
+ *
+ */
+
+static void wf_smu_tick(void)
+{
+       unsigned int last_failure = wf_smu_failure_state;
+       unsigned int new_failure;
+
+       if (!wf_smu_started) {
+               DBG("wf: creating control loops !\n");
+               wf_smu_create_drive_fans();
+               wf_smu_create_slots_fans();
+               wf_smu_create_cpu_fans();
+               wf_smu_started = 1;
+       }
+
+       /* Skipping ticks */
+       if (wf_smu_skipping && --wf_smu_skipping)
+               return;
+
+       wf_smu_failure_state = 0;
+       if (wf_smu_drive_fans)
+               wf_smu_drive_fans_tick(wf_smu_drive_fans);
+       if (wf_smu_slots_fans)
+               wf_smu_slots_fans_tick(wf_smu_slots_fans);
+       if (wf_smu_cpu_fans)
+               wf_smu_cpu_fans_tick(wf_smu_cpu_fans);
+
+       wf_smu_readjust = 0;
+       new_failure = wf_smu_failure_state & ~last_failure;
+
+       /* If entering failure mode, clamp cpufreq and ramp all
+        * fans to full speed.
+        */
+       if (wf_smu_failure_state && !last_failure) {
+               if (cpufreq_clamp)
+                       wf_control_set_max(cpufreq_clamp);
+               if (fan_cpu_main)
+                       wf_control_set_max(fan_cpu_main);
+               if (fan_cpu_second)
+                       wf_control_set_max(fan_cpu_second);
+               if (fan_cpu_third)
+                       wf_control_set_max(fan_cpu_third);
+               if (fan_hd)
+                       wf_control_set_max(fan_hd);
+               if (fan_slots)
+                       wf_control_set_max(fan_slots);
+       }
+
+       /* If leaving failure mode, unclamp cpufreq and readjust
+        * all fans on next iteration
+        */
+       if (!wf_smu_failure_state && last_failure) {
+               if (cpufreq_clamp)
+                       wf_control_set_min(cpufreq_clamp);
+               wf_smu_readjust = 1;
+       }
+
+       /* Overtemp condition detected, notify and start skipping a couple
+        * ticks to let the temperature go down
+        */
+       if (new_failure & FAILURE_OVERTEMP) {
+               wf_set_overtemp();
+               wf_smu_skipping = 2;
+       }
+
+       /* We only clear the overtemp condition if overtemp is cleared
+        * _and_ no other failure is present. Since a sensor error will
+        * clear the overtemp condition (can't measure temperature) at
+        * the control loop levels, but we don't want to keep it clear
+        * here in this case
+        */
+       if (new_failure == 0 && last_failure & FAILURE_OVERTEMP)
+               wf_clear_overtemp();
+}
+
+
+static void wf_smu_new_control(struct wf_control *ct)
+{
+       if (wf_smu_all_controls_ok)
+               return;
+
+       if (fan_cpu_main == NULL && !strcmp(ct->name, "cpu-rear-fan-0")) {
+               if (wf_get_control(ct) == 0) {
+                       fan_cpu_main = ct;
+                       device_create_file(wf_smu_dev, &dev_attr_cpu_fan);
+               }
+       }
+
+       if (fan_cpu_second == NULL && !strcmp(ct->name, "cpu-rear-fan-1")) {
+               if (wf_get_control(ct) == 0)
+                       fan_cpu_second = ct;
+       }
+
+       if (fan_cpu_third == NULL && !strcmp(ct->name, "cpu-front-fan-0")) {
+               if (wf_get_control(ct) == 0)
+                       fan_cpu_third = ct;
+       }
+
+       if (cpufreq_clamp == NULL && !strcmp(ct->name, "cpufreq-clamp")) {
+               if (wf_get_control(ct) == 0)
+                       cpufreq_clamp = ct;
+       }
+
+       if (fan_hd == NULL && !strcmp(ct->name, "drive-bay-fan")) {
+               if (wf_get_control(ct) == 0) {
+                       fan_hd = ct;
+                       device_create_file(wf_smu_dev, &dev_attr_hd_fan);
+               }
+       }
+
+       if (fan_slots == NULL && !strcmp(ct->name, "slots-fan")) {
+               if (wf_get_control(ct) == 0) {
+                       fan_slots = ct;
+                       device_create_file(wf_smu_dev, &dev_attr_slots_fan);
+               }
+       }
+
+       if (fan_cpu_main && (fan_cpu_second || fan_cpu_third) && fan_hd &&
+           fan_slots && cpufreq_clamp)
+               wf_smu_all_controls_ok = 1;
+}
+
+static void wf_smu_new_sensor(struct wf_sensor *sr)
+{
+       if (wf_smu_all_sensors_ok)
+               return;
+
+       if (sensor_cpu_power == NULL && !strcmp(sr->name, "cpu-power")) {
+               if (wf_get_sensor(sr) == 0) {
+                       sensor_cpu_power = sr;
+                       device_create_file(wf_smu_dev, &dev_attr_cpu_power);
+               }
+       }
+
+       if (sensor_cpu_temp == NULL && !strcmp(sr->name, "cpu-temp")) {
+               if (wf_get_sensor(sr) == 0) {
+                       sensor_cpu_temp = sr;
+                       device_create_file(wf_smu_dev, &dev_attr_cpu_temp);
+               }
+       }
+
+       if (sensor_hd_temp == NULL && !strcmp(sr->name, "hd-temp")) {
+               if (wf_get_sensor(sr) == 0) {
+                       sensor_hd_temp = sr;
+                       device_create_file(wf_smu_dev, &dev_attr_hd_temp);
+               }
+       }
+
+       if (sensor_slots_power == NULL && !strcmp(sr->name, "slots-power")) {
+               if (wf_get_sensor(sr) == 0) {
+                       sensor_slots_power = sr;
+                       device_create_file(wf_smu_dev, &dev_attr_slots_power);
+               }
+       }
+
+       if (sensor_cpu_power && sensor_cpu_temp &&
+           sensor_hd_temp && sensor_slots_power)
+               wf_smu_all_sensors_ok = 1;
+}
+
+
+static int wf_smu_notify(struct notifier_block *self,
+                              unsigned long event, void *data)
+{
+       switch(event) {
+       case WF_EVENT_NEW_CONTROL:
+               DBG("wf: new control %s detected\n",
+                   ((struct wf_control *)data)->name);
+               wf_smu_new_control(data);
+               wf_smu_readjust = 1;
+               break;
+       case WF_EVENT_NEW_SENSOR:
+               DBG("wf: new sensor %s detected\n",
+                   ((struct wf_sensor *)data)->name);
+               wf_smu_new_sensor(data);
+               break;
+       case WF_EVENT_TICK:
+               if (wf_smu_all_controls_ok && wf_smu_all_sensors_ok)
+                       wf_smu_tick();
+       }
+
+       return 0;
+}
+
+static struct notifier_block wf_smu_events = {
+       .notifier_call  = wf_smu_notify,
+};
+
+static int wf_init_pm(void)
+{
+       printk(KERN_INFO "windfarm: Initializing for Desktop G5 model\n");
+
+       return 0;
+}
+
+static int wf_smu_probe(struct device *ddev)
+{
+       wf_smu_dev = ddev;
+
+       wf_register_client(&wf_smu_events);
+
+       return 0;
+}
+
+static int wf_smu_remove(struct device *ddev)
+{
+       wf_unregister_client(&wf_smu_events);
+
+       /* XXX We don't have yet a guarantee that our callback isn't
+        * in progress when returning from wf_unregister_client, so
+        * we add an arbitrary delay. I'll have to fix that in the core
+        */
+       msleep(1000);
+
+       /* Release all sensors */
+       /* One more crappy race: I don't think we have any guarantee here
+        * that the attribute callback won't race with the sensor beeing
+        * disposed of, and I'm not 100% certain what best way to deal
+        * with that except by adding locks all over... I'll do that
+        * eventually but heh, who ever rmmod this module anyway ?
+        */
+       if (sensor_cpu_power) {
+               device_remove_file(wf_smu_dev, &dev_attr_cpu_power);
+               wf_put_sensor(sensor_cpu_power);
+       }
+       if (sensor_cpu_temp) {
+               device_remove_file(wf_smu_dev, &dev_attr_cpu_temp);
+               wf_put_sensor(sensor_cpu_temp);
+       }
+       if (sensor_hd_temp) {
+               device_remove_file(wf_smu_dev, &dev_attr_hd_temp);
+               wf_put_sensor(sensor_hd_temp);
+       }
+       if (sensor_slots_power) {
+               device_remove_file(wf_smu_dev, &dev_attr_slots_power);
+               wf_put_sensor(sensor_slots_power);
+       }
+
+       /* Release all controls */
+       if (fan_cpu_main) {
+               device_remove_file(wf_smu_dev, &dev_attr_cpu_fan);
+               wf_put_control(fan_cpu_main);
+       }
+       if (fan_cpu_second)
+               wf_put_control(fan_cpu_second);
+       if (fan_cpu_third)
+               wf_put_control(fan_cpu_third);
+       if (fan_hd) {
+               device_remove_file(wf_smu_dev, &dev_attr_hd_fan);
+               wf_put_control(fan_hd);
+       }
+       if (fan_slots) {
+               device_remove_file(wf_smu_dev, &dev_attr_slots_fan);
+               wf_put_control(fan_slots);
+       }
+       if (cpufreq_clamp)
+               wf_put_control(cpufreq_clamp);
+
+       /* Destroy control loops state structures */
+       if (wf_smu_slots_fans)
+               kfree(wf_smu_cpu_fans);
+       if (wf_smu_drive_fans)
+               kfree(wf_smu_cpu_fans);
+       if (wf_smu_cpu_fans)
+               kfree(wf_smu_cpu_fans);
+
+       wf_smu_dev = NULL;
+
+       return 0;
+}
+
+static struct device_driver wf_smu_driver = {
+        .name = "windfarm",
+        .bus = &platform_bus_type,
+        .probe = wf_smu_probe,
+        .remove = wf_smu_remove,
+};
+
+
+static int __init wf_smu_init(void)
+{
+       int rc = -ENODEV;
+
+       if (machine_is_compatible("PowerMac9,1"))
+               rc = wf_init_pm();
+
+       if (rc == 0) {
+#ifdef MODULE
+               request_module("windfarm_smu_controls");
+               request_module("windfarm_smu_sensors");
+               request_module("windfarm_lm75_sensor");
+
+#endif /* MODULE */
+               driver_register(&wf_smu_driver);
+       }
+
+       return rc;
+}
+
+static void __exit wf_smu_exit(void)
+{
+
+       driver_unregister(&wf_smu_driver);
+}
+
+
+module_init(wf_smu_init);
+module_exit(wf_smu_exit);
+
+MODULE_AUTHOR("Benjamin Herrenschmidt <benh@kernel.crashing.org>");
+MODULE_DESCRIPTION("Thermal control logic for PowerMac9,1");
+MODULE_LICENSE("GPL");
+
diff --git a/drivers/macintosh/windfarm_smu_controls.c b/drivers/macintosh/windfarm_smu_controls.c
new file mode 100644 (file)
index 0000000..2c3158c
--- /dev/null
@@ -0,0 +1,282 @@
+/*
+ * Windfarm PowerMac thermal control. SMU based controls
+ *
+ * (c) Copyright 2005 Benjamin Herrenschmidt, IBM Corp.
+ *                    <benh@kernel.crashing.org>
+ *
+ * Released under the term of the GNU GPL v2.
+ */
+
+#include <linux/types.h>
+#include <linux/errno.h>
+#include <linux/kernel.h>
+#include <linux/delay.h>
+#include <linux/slab.h>
+#include <linux/init.h>
+#include <linux/wait.h>
+#include <asm/prom.h>
+#include <asm/machdep.h>
+#include <asm/io.h>
+#include <asm/system.h>
+#include <asm/sections.h>
+#include <asm/smu.h>
+
+#include "windfarm.h"
+
+#define VERSION "0.3"
+
+#undef DEBUG
+
+#ifdef DEBUG
+#define DBG(args...)   printk(args)
+#else
+#define DBG(args...)   do { } while(0)
+#endif
+
+/*
+ * SMU fans control object
+ */
+
+static LIST_HEAD(smu_fans);
+
+struct smu_fan_control {
+       struct list_head        link;
+       int                     fan_type;       /* 0 = rpm, 1 = pwm */
+       u32                     reg;            /* index in SMU */
+       s32                     value;          /* current value */
+       s32                     min, max;       /* min/max values */
+       struct wf_control       ctrl;
+};
+#define to_smu_fan(c) container_of(c, struct smu_fan_control, ctrl)
+
+static int smu_set_fan(int pwm, u8 id, u16 value)
+{
+       struct smu_cmd cmd;
+       u8 buffer[16];
+       DECLARE_COMPLETION(comp);
+       int rc;
+
+       /* Fill SMU command structure */
+       cmd.cmd = SMU_CMD_FAN_COMMAND;
+       cmd.data_len = 14;
+       cmd.reply_len = 16;
+       cmd.data_buf = cmd.reply_buf = buffer;
+       cmd.status = 0;
+       cmd.done = smu_done_complete;
+       cmd.misc = &comp;
+
+       /* Fill argument buffer */
+       memset(buffer, 0, 16);
+       buffer[0] = pwm ? 0x10 : 0x00;
+       buffer[1] = 0x01 << id;
+       *((u16 *)&buffer[2 + id * 2]) = value;
+
+       rc = smu_queue_cmd(&cmd);
+       if (rc)
+               return rc;
+       wait_for_completion(&comp);
+       return cmd.status;
+}
+
+static void smu_fan_release(struct wf_control *ct)
+{
+       struct smu_fan_control *fct = to_smu_fan(ct);
+
+       kfree(fct);
+}
+
+static int smu_fan_set(struct wf_control *ct, s32 value)
+{
+       struct smu_fan_control *fct = to_smu_fan(ct);
+
+       if (value < fct->min)
+               value = fct->min;
+       if (value > fct->max)
+               value = fct->max;
+       fct->value = value;
+
+       return smu_set_fan(fct->fan_type, fct->reg, value);
+}
+
+static int smu_fan_get(struct wf_control *ct, s32 *value)
+{
+       struct smu_fan_control *fct = to_smu_fan(ct);
+       *value = fct->value; /* todo: read from SMU */
+       return 0;
+}
+
+static s32 smu_fan_min(struct wf_control *ct)
+{
+       struct smu_fan_control *fct = to_smu_fan(ct);
+       return fct->min;
+}
+
+static s32 smu_fan_max(struct wf_control *ct)
+{
+       struct smu_fan_control *fct = to_smu_fan(ct);
+       return fct->max;
+}
+
+static struct wf_control_ops smu_fan_ops = {
+       .set_value      = smu_fan_set,
+       .get_value      = smu_fan_get,
+       .get_min        = smu_fan_min,
+       .get_max        = smu_fan_max,
+       .release        = smu_fan_release,
+       .owner          = THIS_MODULE,
+};
+
+static struct smu_fan_control *smu_fan_create(struct device_node *node,
+                                             int pwm_fan)
+{
+       struct smu_fan_control *fct;
+       s32 *v; u32 *reg;
+       char *l;
+
+       fct = kmalloc(sizeof(struct smu_fan_control), GFP_KERNEL);
+       if (fct == NULL)
+               return NULL;
+       fct->ctrl.ops = &smu_fan_ops;
+       l = (char *)get_property(node, "location", NULL);
+       if (l == NULL)
+               goto fail;
+
+       fct->fan_type = pwm_fan;
+       fct->ctrl.type = pwm_fan ? WF_CONTROL_PWM_FAN : WF_CONTROL_RPM_FAN;
+
+       /* We use the name & location here the same way we do for SMU sensors,
+        * see the comment in windfarm_smu_sensors.c. The locations are a bit
+        * less consistent here between the iMac and the desktop models, but
+        * that is good enough for our needs for now at least.
+        *
+        * One problem though is that Apple seem to be inconsistent with case
+        * and the kernel doesn't have strcasecmp =P
+        */
+
+       fct->ctrl.name = NULL;
+
+       /* Names used on desktop models */
+       if (!strcmp(l, "Rear Fan 0") || !strcmp(l, "Rear Fan") ||
+           !strcmp(l, "Rear fan 0") || !strcmp(l, "Rear fan"))
+               fct->ctrl.name = "cpu-rear-fan-0";
+       else if (!strcmp(l, "Rear Fan 1") || !strcmp(l, "Rear fan 1"))
+               fct->ctrl.name = "cpu-rear-fan-1";
+       else if (!strcmp(l, "Front Fan 0") || !strcmp(l, "Front Fan") ||
+                !strcmp(l, "Front fan 0") || !strcmp(l, "Front fan"))
+               fct->ctrl.name = "cpu-front-fan-0";
+       else if (!strcmp(l, "Front Fan 1") || !strcmp(l, "Front fan 1"))
+               fct->ctrl.name = "cpu-front-fan-1";
+       else if (!strcmp(l, "Slots Fan") || !strcmp(l, "Slots fan"))
+               fct->ctrl.name = "slots-fan";
+       else if (!strcmp(l, "Drive Bay") || !strcmp(l, "Drive bay"))
+               fct->ctrl.name = "drive-bay-fan";
+
+       /* Names used on iMac models */
+       if (!strcmp(l, "System Fan") || !strcmp(l, "System fan"))
+               fct->ctrl.name = "system-fan";
+       else if (!strcmp(l, "CPU Fan") || !strcmp(l, "CPU fan"))
+               fct->ctrl.name = "cpu-fan";
+       else if (!strcmp(l, "Hard Drive") || !strcmp(l, "Hard drive"))
+               fct->ctrl.name = "drive-bay-fan";
+
+       /* Unrecognized fan, bail out */
+       if (fct->ctrl.name == NULL)
+               goto fail;
+
+       /* Get min & max values*/
+       v = (s32 *)get_property(node, "min-value", NULL);
+       if (v == NULL)
+               goto fail;
+       fct->min = *v;
+       v = (s32 *)get_property(node, "max-value", NULL);
+       if (v == NULL)
+               goto fail;
+       fct->max = *v;
+
+       /* Get "reg" value */
+       reg = (u32 *)get_property(node, "reg", NULL);
+       if (reg == NULL)
+               goto fail;
+       fct->reg = *reg;
+
+       if (wf_register_control(&fct->ctrl))
+               goto fail;
+
+       return fct;
+ fail:
+       kfree(fct);
+       return NULL;
+}
+
+
+static int __init smu_controls_init(void)
+{
+       struct device_node *smu, *fans, *fan;
+
+       if (!smu_present())
+               return -ENODEV;
+
+       smu = of_find_node_by_type(NULL, "smu");
+       if (smu == NULL)
+               return -ENODEV;
+
+       /* Look for RPM fans */
+       for (fans = NULL; (fans = of_get_next_child(smu, fans)) != NULL;)
+               if (!strcmp(fans->name, "rpm-fans"))
+                       break;
+       for (fan = NULL;
+            fans && (fan = of_get_next_child(fans, fan)) != NULL;) {
+               struct smu_fan_control *fct;
+
+               fct = smu_fan_create(fan, 0);
+               if (fct == NULL) {
+                       printk(KERN_WARNING "windfarm: Failed to create SMU "
+                              "RPM fan %s\n", fan->name);
+                       continue;
+               }
+               list_add(&fct->link, &smu_fans);
+       }
+       of_node_put(fans);
+
+
+       /* Look for PWM fans */
+       for (fans = NULL; (fans = of_get_next_child(smu, fans)) != NULL;)
+               if (!strcmp(fans->name, "pwm-fans"))
+                       break;
+       for (fan = NULL;
+            fans && (fan = of_get_next_child(fans, fan)) != NULL;) {
+               struct smu_fan_control *fct;
+
+               fct = smu_fan_create(fan, 1);
+               if (fct == NULL) {
+                       printk(KERN_WARNING "windfarm: Failed to create SMU "
+                              "PWM fan %s\n", fan->name);
+                       continue;
+               }
+               list_add(&fct->link, &smu_fans);
+       }
+       of_node_put(fans);
+       of_node_put(smu);
+
+       return 0;
+}
+
+static void __exit smu_controls_exit(void)
+{
+       struct smu_fan_control *fct;
+
+       while (!list_empty(&smu_fans)) {
+               fct = list_entry(smu_fans.next, struct smu_fan_control, link);
+               list_del(&fct->link);
+               wf_unregister_control(&fct->ctrl);
+       }
+}
+
+
+module_init(smu_controls_init);
+module_exit(smu_controls_exit);
+
+MODULE_AUTHOR("Benjamin Herrenschmidt <benh@kernel.crashing.org>");
+MODULE_DESCRIPTION("SMU control objects for PowerMacs thermal control");
+MODULE_LICENSE("GPL");
+
diff --git a/drivers/macintosh/windfarm_smu_sensors.c b/drivers/macintosh/windfarm_smu_sensors.c
new file mode 100644 (file)
index 0000000..b558cc2
--- /dev/null
@@ -0,0 +1,479 @@
+/*
+ * Windfarm PowerMac thermal control. SMU based sensors
+ *
+ * (c) Copyright 2005 Benjamin Herrenschmidt, IBM Corp.
+ *                    <benh@kernel.crashing.org>
+ *
+ * Released under the term of the GNU GPL v2.
+ */
+
+#include <linux/types.h>
+#include <linux/errno.h>
+#include <linux/kernel.h>
+#include <linux/delay.h>
+#include <linux/slab.h>
+#include <linux/init.h>
+#include <linux/wait.h>
+#include <asm/prom.h>
+#include <asm/machdep.h>
+#include <asm/io.h>
+#include <asm/system.h>
+#include <asm/sections.h>
+#include <asm/smu.h>
+
+#include "windfarm.h"
+
+#define VERSION "0.2"
+
+#undef DEBUG
+
+#ifdef DEBUG
+#define DBG(args...)   printk(args)
+#else
+#define DBG(args...)   do { } while(0)
+#endif
+
+/*
+ * Various SMU "partitions" calibration objects for which we
+ * keep pointers here for use by bits & pieces of the driver
+ */
+static struct smu_sdbp_cpuvcp *cpuvcp;
+static int  cpuvcp_version;
+static struct smu_sdbp_cpudiode *cpudiode;
+static struct smu_sdbp_slotspow *slotspow;
+static u8 *debugswitches;
+
+/*
+ * SMU basic sensors objects
+ */
+
+static LIST_HEAD(smu_ads);
+
+struct smu_ad_sensor {
+       struct list_head        link;
+       u32                     reg;            /* index in SMU */
+       struct wf_sensor        sens;
+};
+#define to_smu_ads(c) container_of(c, struct smu_ad_sensor, sens)
+
+static void smu_ads_release(struct wf_sensor *sr)
+{
+       struct smu_ad_sensor *ads = to_smu_ads(sr);
+
+       kfree(ads);
+}
+
+static int smu_read_adc(u8 id, s32 *value)
+{
+       struct smu_simple_cmd   cmd;
+       DECLARE_COMPLETION(comp);
+       int rc;
+
+       rc = smu_queue_simple(&cmd, SMU_CMD_READ_ADC, 1,
+                             smu_done_complete, &comp, id);
+       if (rc)
+               return rc;
+       wait_for_completion(&comp);
+       if (cmd.cmd.status != 0)
+               return cmd.cmd.status;
+       if (cmd.cmd.reply_len != 2) {
+               printk(KERN_ERR "winfarm: read ADC 0x%x returned %d bytes !\n",
+                      id, cmd.cmd.reply_len);
+               return -EIO;
+       }
+       *value = *((u16 *)cmd.buffer);
+       return 0;
+}
+
+static int smu_cputemp_get(struct wf_sensor *sr, s32 *value)
+{
+       struct smu_ad_sensor *ads = to_smu_ads(sr);
+       int rc;
+       s32 val;
+       s64 scaled;
+
+       rc = smu_read_adc(ads->reg, &val);
+       if (rc) {
+               printk(KERN_ERR "windfarm: read CPU temp failed, err %d\n",
+                      rc);
+               return rc;
+       }
+
+       /* Ok, we have to scale & adjust, taking units into account */
+       scaled = (s64)(((u64)val) * (u64)cpudiode->m_value);
+       scaled >>= 3;
+       scaled += ((s64)cpudiode->b_value) << 9;
+       *value = (s32)(scaled << 1);
+
+       return 0;
+}
+
+static int smu_cpuamp_get(struct wf_sensor *sr, s32 *value)
+{
+       struct smu_ad_sensor *ads = to_smu_ads(sr);
+       s32 val, scaled;
+       int rc;
+
+       rc = smu_read_adc(ads->reg, &val);
+       if (rc) {
+               printk(KERN_ERR "windfarm: read CPU current failed, err %d\n",
+                      rc);
+               return rc;
+       }
+
+       /* Ok, we have to scale & adjust, taking units into account */
+       scaled = (s32)(val * (u32)cpuvcp->curr_scale);
+       scaled += (s32)cpuvcp->curr_offset;
+       *value = scaled << 4;
+
+       return 0;
+}
+
+static int smu_cpuvolt_get(struct wf_sensor *sr, s32 *value)
+{
+       struct smu_ad_sensor *ads = to_smu_ads(sr);
+       s32 val, scaled;
+       int rc;
+
+       rc = smu_read_adc(ads->reg, &val);
+       if (rc) {
+               printk(KERN_ERR "windfarm: read CPU voltage failed, err %d\n",
+                      rc);
+               return rc;
+       }
+
+       /* Ok, we have to scale & adjust, taking units into account */
+       scaled = (s32)(val * (u32)cpuvcp->volt_scale);
+       scaled += (s32)cpuvcp->volt_offset;
+       *value = scaled << 4;
+
+       return 0;
+}
+
+static int smu_slotspow_get(struct wf_sensor *sr, s32 *value)
+{
+       struct smu_ad_sensor *ads = to_smu_ads(sr);
+       s32 val, scaled;
+       int rc;
+
+       rc = smu_read_adc(ads->reg, &val);
+       if (rc) {
+               printk(KERN_ERR "windfarm: read slots power failed, err %d\n",
+                      rc);
+               return rc;
+       }
+
+       /* Ok, we have to scale & adjust, taking units into account */
+       scaled = (s32)(val * (u32)slotspow->pow_scale);
+       scaled += (s32)slotspow->pow_offset;
+       *value = scaled << 4;
+
+       return 0;
+}
+
+
+static struct wf_sensor_ops smu_cputemp_ops = {
+       .get_value      = smu_cputemp_get,
+       .release        = smu_ads_release,
+       .owner          = THIS_MODULE,
+};
+static struct wf_sensor_ops smu_cpuamp_ops = {
+       .get_value      = smu_cpuamp_get,
+       .release        = smu_ads_release,
+       .owner          = THIS_MODULE,
+};
+static struct wf_sensor_ops smu_cpuvolt_ops = {
+       .get_value      = smu_cpuvolt_get,
+       .release        = smu_ads_release,
+       .owner          = THIS_MODULE,
+};
+static struct wf_sensor_ops smu_slotspow_ops = {
+       .get_value      = smu_slotspow_get,
+       .release        = smu_ads_release,
+       .owner          = THIS_MODULE,
+};
+
+
+static struct smu_ad_sensor *smu_ads_create(struct device_node *node)
+{
+       struct smu_ad_sensor *ads;
+       char *c, *l;
+       u32 *v;
+
+       ads = kmalloc(sizeof(struct smu_ad_sensor), GFP_KERNEL);
+       if (ads == NULL)
+               return NULL;
+       c = (char *)get_property(node, "device_type", NULL);
+       l = (char *)get_property(node, "location", NULL);
+       if (c == NULL || l == NULL)
+               goto fail;
+
+       /* We currently pick the sensors based on the OF name and location
+        * properties, while Darwin uses the sensor-id's.
+        * The problem with the IDs is that they are model specific while it
+        * looks like apple has been doing a reasonably good job at keeping
+        * the names and locations consistents so I'll stick with the names
+        * and locations for now.
+        */
+       if (!strcmp(c, "temp-sensor") &&
+           !strcmp(l, "CPU T-Diode")) {
+               ads->sens.ops = &smu_cputemp_ops;
+               ads->sens.name = "cpu-temp";
+       } else if (!strcmp(c, "current-sensor") &&
+                  !strcmp(l, "CPU Current")) {
+               ads->sens.ops = &smu_cpuamp_ops;
+               ads->sens.name = "cpu-current";
+       } else if (!strcmp(c, "voltage-sensor") &&
+                  !strcmp(l, "CPU Voltage")) {
+               ads->sens.ops = &smu_cpuvolt_ops;
+               ads->sens.name = "cpu-voltage";
+       } else if (!strcmp(c, "power-sensor") &&
+                  !strcmp(l, "Slots Power")) {
+               ads->sens.ops = &smu_slotspow_ops;
+               ads->sens.name = "slots-power";
+               if (slotspow == NULL) {
+                       DBG("wf: slotspow partition (%02x) not found\n",
+                           SMU_SDB_SLOTSPOW_ID);
+                       goto fail;
+               }
+       } else
+               goto fail;
+
+       v = (u32 *)get_property(node, "reg", NULL);
+       if (v == NULL)
+               goto fail;
+       ads->reg = *v;
+
+       if (wf_register_sensor(&ads->sens))
+               goto fail;
+       return ads;
+ fail:
+       kfree(ads);
+       return NULL;
+}
+
+/*
+ * SMU Power combo sensor object
+ */
+
+struct smu_cpu_power_sensor {
+       struct list_head        link;
+       struct wf_sensor        *volts;
+       struct wf_sensor        *amps;
+       int                     fake_volts : 1;
+       int                     quadratic : 1;
+       struct wf_sensor        sens;
+};
+#define to_smu_cpu_power(c) container_of(c, struct smu_cpu_power_sensor, sens)
+
+static struct smu_cpu_power_sensor *smu_cpu_power;
+
+static void smu_cpu_power_release(struct wf_sensor *sr)
+{
+       struct smu_cpu_power_sensor *pow = to_smu_cpu_power(sr);
+
+       if (pow->volts)
+               wf_put_sensor(pow->volts);
+       if (pow->amps)
+               wf_put_sensor(pow->amps);
+       kfree(pow);
+}
+
+static int smu_cpu_power_get(struct wf_sensor *sr, s32 *value)
+{
+       struct smu_cpu_power_sensor *pow = to_smu_cpu_power(sr);
+       s32 volts, amps, power;
+       u64 tmps, tmpa, tmpb;
+       int rc;
+
+       rc = pow->amps->ops->get_value(pow->amps, &amps);
+       if (rc)
+               return rc;
+
+       if (pow->fake_volts) {
+               *value = amps * 12 - 0x30000;
+               return 0;
+       }
+
+       rc = pow->volts->ops->get_value(pow->volts, &volts);
+       if (rc)
+               return rc;
+
+       power = (s32)((((u64)volts) * ((u64)amps)) >> 16);
+       if (!pow->quadratic) {
+               *value = power;
+               return 0;
+       }
+       tmps = (((u64)power) * ((u64)power)) >> 16;
+       tmpa = ((u64)cpuvcp->power_quads[0]) * tmps;
+       tmpb = ((u64)cpuvcp->power_quads[1]) * ((u64)power);
+       *value = (tmpa >> 28) + (tmpb >> 28) + (cpuvcp->power_quads[2] >> 12);
+
+       return 0;
+}
+
+static struct wf_sensor_ops smu_cpu_power_ops = {
+       .get_value      = smu_cpu_power_get,
+       .release        = smu_cpu_power_release,
+       .owner          = THIS_MODULE,
+};
+
+
+static struct smu_cpu_power_sensor *
+smu_cpu_power_create(struct wf_sensor *volts, struct wf_sensor *amps)
+{
+       struct smu_cpu_power_sensor *pow;
+
+       pow = kmalloc(sizeof(struct smu_cpu_power_sensor), GFP_KERNEL);
+       if (pow == NULL)
+               return NULL;
+       pow->sens.ops = &smu_cpu_power_ops;
+       pow->sens.name = "cpu-power";
+
+       wf_get_sensor(volts);
+       pow->volts = volts;
+       wf_get_sensor(amps);
+       pow->amps = amps;
+
+       /* Some early machines need a faked voltage */
+       if (debugswitches && ((*debugswitches) & 0x80)) {
+               printk(KERN_INFO "windfarm: CPU Power sensor using faked"
+                      " voltage !\n");
+               pow->fake_volts = 1;
+       } else
+               pow->fake_volts = 0;
+
+       /* Try to use quadratic transforms on PowerMac8,1 and 9,1 for now,
+        * I yet have to figure out what's up with 8,2 and will have to
+        * adjust for later, unless we can 100% trust the SDB partition...
+        */
+       if ((machine_is_compatible("PowerMac8,1") ||
+            machine_is_compatible("PowerMac8,2") ||
+            machine_is_compatible("PowerMac9,1")) &&
+           cpuvcp_version >= 2) {
+               pow->quadratic = 1;
+               DBG("windfarm: CPU Power using quadratic transform\n");
+       } else
+               pow->quadratic = 0;
+
+       if (wf_register_sensor(&pow->sens))
+               goto fail;
+       return pow;
+ fail:
+       kfree(pow);
+       return NULL;
+}
+
+static int smu_fetch_param_partitions(void)
+{
+       struct smu_sdbp_header *hdr;
+
+       /* Get CPU voltage/current/power calibration data */
+       hdr = smu_get_sdb_partition(SMU_SDB_CPUVCP_ID, NULL);
+       if (hdr == NULL) {
+               DBG("wf: cpuvcp partition (%02x) not found\n",
+                   SMU_SDB_CPUVCP_ID);
+               return -ENODEV;
+       }
+       cpuvcp = (struct smu_sdbp_cpuvcp *)&hdr[1];
+       /* Keep version around */
+       cpuvcp_version = hdr->version;
+
+       /* Get CPU diode calibration data */
+       hdr = smu_get_sdb_partition(SMU_SDB_CPUDIODE_ID, NULL);
+       if (hdr == NULL) {
+               DBG("wf: cpudiode partition (%02x) not found\n",
+                   SMU_SDB_CPUDIODE_ID);
+               return -ENODEV;
+       }
+       cpudiode = (struct smu_sdbp_cpudiode *)&hdr[1];
+
+       /* Get slots power calibration data if any */
+       hdr = smu_get_sdb_partition(SMU_SDB_SLOTSPOW_ID, NULL);
+       if (hdr != NULL)
+               slotspow = (struct smu_sdbp_slotspow *)&hdr[1];
+
+       /* Get debug switches if any */
+       hdr = smu_get_sdb_partition(SMU_SDB_DEBUG_SWITCHES_ID, NULL);
+       if (hdr != NULL)
+               debugswitches = (u8 *)&hdr[1];
+
+       return 0;
+}
+
+static int __init smu_sensors_init(void)
+{
+       struct device_node *smu, *sensors, *s;
+       struct smu_ad_sensor *volt_sensor = NULL, *curr_sensor = NULL;
+       int rc;
+
+       if (!smu_present())
+               return -ENODEV;
+
+       /* Get parameters partitions */
+       rc = smu_fetch_param_partitions();
+       if (rc)
+               return rc;
+
+       smu = of_find_node_by_type(NULL, "smu");
+       if (smu == NULL)
+               return -ENODEV;
+
+       /* Look for sensors subdir */
+       for (sensors = NULL;
+            (sensors = of_get_next_child(smu, sensors)) != NULL;)
+               if (!strcmp(sensors->name, "sensors"))
+                       break;
+
+       of_node_put(smu);
+
+       /* Create basic sensors */
+       for (s = NULL;
+            sensors && (s = of_get_next_child(sensors, s)) != NULL;) {
+               struct smu_ad_sensor *ads;
+
+               ads = smu_ads_create(s);
+               if (ads == NULL)
+                       continue;
+               list_add(&ads->link, &smu_ads);
+               /* keep track of cpu voltage & current */
+               if (!strcmp(ads->sens.name, "cpu-voltage"))
+                       volt_sensor = ads;
+               else if (!strcmp(ads->sens.name, "cpu-current"))
+                       curr_sensor = ads;
+       }
+
+       of_node_put(sensors);
+
+       /* Create CPU power sensor if possible */
+       if (volt_sensor && curr_sensor)
+               smu_cpu_power = smu_cpu_power_create(&volt_sensor->sens,
+                                                    &curr_sensor->sens);
+
+       return 0;
+}
+
+static void __exit smu_sensors_exit(void)
+{
+       struct smu_ad_sensor *ads;
+
+       /* dispose of power sensor */
+       if (smu_cpu_power)
+               wf_unregister_sensor(&smu_cpu_power->sens);
+
+       /* dispose of basic sensors */
+       while (!list_empty(&smu_ads)) {
+               ads = list_entry(smu_ads.next, struct smu_ad_sensor, link);
+               list_del(&ads->link);
+               wf_unregister_sensor(&ads->sens);
+       }
+}
+
+
+module_init(smu_sensors_init);
+module_exit(smu_sensors_exit);
+
+MODULE_AUTHOR("Benjamin Herrenschmidt <benh@kernel.crashing.org>");
+MODULE_DESCRIPTION("SMU sensor objects for PowerMacs thermal control");
+MODULE_LICENSE("GPL");
+
index 01654fcabc52128ce866728b24ddaa73c1437a1f..51315302a85e43ab651a4edaba742784d5e04af2 100644 (file)
@@ -21,7 +21,6 @@
  */
 
 #include <linux/module.h>
-#include <linux/version.h>
 #include <linux/errno.h>
 #include <linux/slab.h>
 #include <linux/init.h>
@@ -272,7 +271,8 @@ static struct page *read_sb_page(mddev_t *mddev, long offset, unsigned long inde
                return ERR_PTR(-ENOMEM);
 
        ITERATE_RDEV(mddev, rdev, tmp) {
-               if (! rdev->in_sync || rdev->faulty)
+               if (! test_bit(In_sync, &rdev->flags)
+                   || test_bit(Faulty, &rdev->flags))
                        continue;
 
                target = (rdev->sb_offset << 1) + offset + index * (PAGE_SIZE/512);
@@ -292,7 +292,8 @@ static int write_sb_page(mddev_t *mddev, long offset, struct page *page, int wai
        struct list_head *tmp;
 
        ITERATE_RDEV(mddev, rdev, tmp)
-               if (rdev->in_sync && !rdev->faulty)
+               if (test_bit(In_sync, &rdev->flags)
+                   && !test_bit(Faulty, &rdev->flags))
                        md_super_write(mddev, rdev,
                                       (rdev->sb_offset<<1) + offset
                                       + page->index * (PAGE_SIZE/512),
@@ -300,7 +301,7 @@ static int write_sb_page(mddev_t *mddev, long offset, struct page *page, int wai
                                       page);
 
        if (wait)
-               wait_event(mddev->sb_wait, atomic_read(&mddev->pending_writes)==0);
+               md_super_wait(mddev);
        return 0;
 }
 
@@ -481,7 +482,8 @@ static int bitmap_read_sb(struct bitmap *bitmap)
        /* verify that the bitmap-specific fields are valid */
        if (sb->magic != cpu_to_le32(BITMAP_MAGIC))
                reason = "bad magic";
-       else if (sb->version != cpu_to_le32(BITMAP_MAJOR))
+       else if (le32_to_cpu(sb->version) < BITMAP_MAJOR_LO ||
+                le32_to_cpu(sb->version) > BITMAP_MAJOR_HI)
                reason = "unrecognized superblock version";
        else if (chunksize < 512 || chunksize > (1024 * 1024 * 4))
                reason = "bitmap chunksize out of range (512B - 4MB)";
@@ -526,6 +528,8 @@ success:
        bitmap->daemon_lastrun = jiffies;
        bitmap->max_write_behind = write_behind;
        bitmap->flags |= sb->state;
+       if (le32_to_cpu(sb->version) == BITMAP_MAJOR_HOSTENDIAN)
+               bitmap->flags |= BITMAP_HOSTENDIAN;
        bitmap->events_cleared = le64_to_cpu(sb->events_cleared);
        if (sb->state & BITMAP_STALE)
                bitmap->events_cleared = bitmap->mddev->events;
@@ -763,7 +767,10 @@ static void bitmap_file_set_bit(struct bitmap *bitmap, sector_t block)
 
        /* set the bit */
        kaddr = kmap_atomic(page, KM_USER0);
-       set_bit(bit, kaddr);
+       if (bitmap->flags & BITMAP_HOSTENDIAN)
+               set_bit(bit, kaddr);
+       else
+               ext2_set_bit(bit, kaddr);
        kunmap_atomic(kaddr, KM_USER0);
        PRINTK("set file bit %lu page %lu\n", bit, page->index);
 
@@ -821,8 +828,7 @@ int bitmap_unplug(struct bitmap *bitmap)
                                            wake_up_process(bitmap->writeback_daemon->tsk));
                        spin_unlock_irq(&bitmap->write_lock);
                } else
-                       wait_event(bitmap->mddev->sb_wait,
-                                  atomic_read(&bitmap->mddev->pending_writes)==0);
+                       md_super_wait(bitmap->mddev);
        }
        return 0;
 }
@@ -890,6 +896,7 @@ static int bitmap_init_from_disk(struct bitmap *bitmap, sector_t start)
        oldindex = ~0L;
 
        for (i = 0; i < chunks; i++) {
+               int b;
                index = file_page_index(i);
                bit = file_page_offset(i);
                if (index != oldindex) { /* this is a new page, read it in */
@@ -938,7 +945,11 @@ static int bitmap_init_from_disk(struct bitmap *bitmap, sector_t start)
 
                        bitmap->filemap[bitmap->file_pages++] = page;
                }
-               if (test_bit(bit, page_address(page))) {
+               if (bitmap->flags & BITMAP_HOSTENDIAN)
+                       b = test_bit(bit, page_address(page));
+               else
+                       b = ext2_test_bit(bit, page_address(page));
+               if (b) {
                        /* if the disk bit is set, set the memory bit */
                        bitmap_set_memory_bits(bitmap, i << CHUNK_BLOCK_SHIFT(bitmap),
                                               ((i+1) << (CHUNK_BLOCK_SHIFT(bitmap)) >= start)
@@ -1096,7 +1107,10 @@ int bitmap_daemon_work(struct bitmap *bitmap)
                                                  -1);
 
                                /* clear the bit */
-                               clear_bit(file_page_offset(j), page_address(page));
+                               if (bitmap->flags & BITMAP_HOSTENDIAN)
+                                       clear_bit(file_page_offset(j), page_address(page));
+                               else
+                                       ext2_clear_bit(file_page_offset(j), page_address(page));
                        }
                }
                spin_unlock_irqrestore(&bitmap->lock, flags);
index 9ecf51ee596fb296f64a75f8372828e0d2701012..adf960d8a7c98d1430c2e51b7e0250674b98abff 100644 (file)
@@ -131,6 +131,8 @@ static ctl_table raid_root_table[] = {
 
 static struct block_device_operations md_fops;
 
+static int start_readonly;
+
 /*
  * Enables to iterate over all existing md arrays
  * all_mddevs_lock protects this list.
@@ -181,7 +183,7 @@ static void mddev_put(mddev_t *mddev)
        if (!mddev->raid_disks && list_empty(&mddev->disks)) {
                list_del(&mddev->all_mddevs);
                blk_put_queue(mddev->queue);
-               kfree(mddev);
+               kobject_unregister(&mddev->kobj);
        }
        spin_unlock(&all_mddevs_lock);
 }
@@ -330,18 +332,46 @@ static void free_disk_sb(mdk_rdev_t * rdev)
 static int super_written(struct bio *bio, unsigned int bytes_done, int error)
 {
        mdk_rdev_t *rdev = bio->bi_private;
+       mddev_t *mddev = rdev->mddev;
        if (bio->bi_size)
                return 1;
 
        if (error || !test_bit(BIO_UPTODATE, &bio->bi_flags))
-               md_error(rdev->mddev, rdev);
+               md_error(mddev, rdev);
 
-       if (atomic_dec_and_test(&rdev->mddev->pending_writes))
-               wake_up(&rdev->mddev->sb_wait);
+       if (atomic_dec_and_test(&mddev->pending_writes))
+               wake_up(&mddev->sb_wait);
        bio_put(bio);
        return 0;
 }
 
+static int super_written_barrier(struct bio *bio, unsigned int bytes_done, int error)
+{
+       struct bio *bio2 = bio->bi_private;
+       mdk_rdev_t *rdev = bio2->bi_private;
+       mddev_t *mddev = rdev->mddev;
+       if (bio->bi_size)
+               return 1;
+
+       if (!test_bit(BIO_UPTODATE, &bio->bi_flags) &&
+           error == -EOPNOTSUPP) {
+               unsigned long flags;
+               /* barriers don't appear to be supported :-( */
+               set_bit(BarriersNotsupp, &rdev->flags);
+               mddev->barriers_work = 0;
+               spin_lock_irqsave(&mddev->write_lock, flags);
+               bio2->bi_next = mddev->biolist;
+               mddev->biolist = bio2;
+               spin_unlock_irqrestore(&mddev->write_lock, flags);
+               wake_up(&mddev->sb_wait);
+               bio_put(bio);
+               return 0;
+       }
+       bio_put(bio2);
+       bio->bi_private = rdev;
+       return super_written(bio, bytes_done, error);
+}
+
 void md_super_write(mddev_t *mddev, mdk_rdev_t *rdev,
                   sector_t sector, int size, struct page *page)
 {
@@ -350,16 +380,54 @@ void md_super_write(mddev_t *mddev, mdk_rdev_t *rdev,
         * and decrement it on completion, waking up sb_wait
         * if zero is reached.
         * If an error occurred, call md_error
+        *
+        * As we might need to resubmit the request if BIO_RW_BARRIER
+        * causes ENOTSUPP, we allocate a spare bio...
         */
        struct bio *bio = bio_alloc(GFP_NOIO, 1);
+       int rw = (1<<BIO_RW) | (1<<BIO_RW_SYNC);
 
        bio->bi_bdev = rdev->bdev;
        bio->bi_sector = sector;
        bio_add_page(bio, page, size, 0);
        bio->bi_private = rdev;
        bio->bi_end_io = super_written;
+       bio->bi_rw = rw;
+
        atomic_inc(&mddev->pending_writes);
-       submit_bio((1<<BIO_RW)|(1<<BIO_RW_SYNC), bio);
+       if (!test_bit(BarriersNotsupp, &rdev->flags)) {
+               struct bio *rbio;
+               rw |= (1<<BIO_RW_BARRIER);
+               rbio = bio_clone(bio, GFP_NOIO);
+               rbio->bi_private = bio;
+               rbio->bi_end_io = super_written_barrier;
+               submit_bio(rw, rbio);
+       } else
+               submit_bio(rw, bio);
+}
+
+void md_super_wait(mddev_t *mddev)
+{
+       /* wait for all superblock writes that were scheduled to complete.
+        * if any had to be retried (due to BARRIER problems), retry them
+        */
+       DEFINE_WAIT(wq);
+       for(;;) {
+               prepare_to_wait(&mddev->sb_wait, &wq, TASK_UNINTERRUPTIBLE);
+               if (atomic_read(&mddev->pending_writes)==0)
+                       break;
+               while (mddev->biolist) {
+                       struct bio *bio;
+                       spin_lock_irq(&mddev->write_lock);
+                       bio = mddev->biolist;
+                       mddev->biolist = bio->bi_next ;
+                       bio->bi_next = NULL;
+                       spin_unlock_irq(&mddev->write_lock);
+                       submit_bio(bio->bi_rw, bio);
+               }
+               schedule();
+       }
+       finish_wait(&mddev->sb_wait, &wq);
 }
 
 static int bi_complete(struct bio *bio, unsigned int bytes_done, int error)
@@ -610,7 +678,7 @@ static int super_90_validate(mddev_t *mddev, mdk_rdev_t *rdev)
        mdp_super_t *sb = (mdp_super_t *)page_address(rdev->sb_page);
 
        rdev->raid_disk = -1;
-       rdev->in_sync = 0;
+       rdev->flags = 0;
        if (mddev->raid_disks == 0) {
                mddev->major_version = 0;
                mddev->minor_version = sb->minor_version;
@@ -671,21 +739,19 @@ static int super_90_validate(mddev_t *mddev, mdk_rdev_t *rdev)
                return 0;
 
        if (mddev->level != LEVEL_MULTIPATH) {
-               rdev->faulty = 0;
-               rdev->flags = 0;
                desc = sb->disks + rdev->desc_nr;
 
                if (desc->state & (1<<MD_DISK_FAULTY))
-                       rdev->faulty = 1;
+                       set_bit(Faulty, &rdev->flags);
                else if (desc->state & (1<<MD_DISK_SYNC) &&
                         desc->raid_disk < mddev->raid_disks) {
-                       rdev->in_sync = 1;
+                       set_bit(In_sync, &rdev->flags);
                        rdev->raid_disk = desc->raid_disk;
                }
                if (desc->state & (1<<MD_DISK_WRITEMOSTLY))
                        set_bit(WriteMostly, &rdev->flags);
        } else /* MULTIPATH are always insync */
-               rdev->in_sync = 1;
+               set_bit(In_sync, &rdev->flags);
        return 0;
 }
 
@@ -699,6 +765,7 @@ static void super_90_sync(mddev_t *mddev, mdk_rdev_t *rdev)
        mdk_rdev_t *rdev2;
        int next_spare = mddev->raid_disks;
 
+
        /* make rdev->sb match mddev data..
         *
         * 1/ zero out disks
@@ -758,23 +825,27 @@ static void super_90_sync(mddev_t *mddev, mdk_rdev_t *rdev)
        sb->disks[0].state = (1<<MD_DISK_REMOVED);
        ITERATE_RDEV(mddev,rdev2,tmp) {
                mdp_disk_t *d;
-               if (rdev2->raid_disk >= 0 && rdev2->in_sync && !rdev2->faulty)
-                       rdev2->desc_nr = rdev2->raid_disk;
+               int desc_nr;
+               if (rdev2->raid_disk >= 0 && test_bit(In_sync, &rdev2->flags)
+                   && !test_bit(Faulty, &rdev2->flags))
+                       desc_nr = rdev2->raid_disk;
                else
-                       rdev2->desc_nr = next_spare++;
+                       desc_nr = next_spare++;
+               rdev2->desc_nr = desc_nr;
                d = &sb->disks[rdev2->desc_nr];
                nr_disks++;
                d->number = rdev2->desc_nr;
                d->major = MAJOR(rdev2->bdev->bd_dev);
                d->minor = MINOR(rdev2->bdev->bd_dev);
-               if (rdev2->raid_disk >= 0 && rdev->in_sync && !rdev2->faulty)
+               if (rdev2->raid_disk >= 0 && test_bit(In_sync, &rdev2->flags)
+                   && !test_bit(Faulty, &rdev2->flags))
                        d->raid_disk = rdev2->raid_disk;
                else
                        d->raid_disk = rdev2->desc_nr; /* compatibility */
-               if (rdev2->faulty) {
+               if (test_bit(Faulty, &rdev2->flags)) {
                        d->state = (1<<MD_DISK_FAULTY);
                        failed++;
-               } else if (rdev2->in_sync) {
+               } else if (test_bit(In_sync, &rdev2->flags)) {
                        d->state = (1<<MD_DISK_ACTIVE);
                        d->state |= (1<<MD_DISK_SYNC);
                        active++;
@@ -787,7 +858,6 @@ static void super_90_sync(mddev_t *mddev, mdk_rdev_t *rdev)
                if (test_bit(WriteMostly, &rdev2->flags))
                        d->state |= (1<<MD_DISK_WRITEMOSTLY);
        }
-       
        /* now set the "removed" and "faulty" bits on any missing devices */
        for (i=0 ; i < mddev->raid_disks ; i++) {
                mdp_disk_t *d = &sb->disks[i];
@@ -944,7 +1014,7 @@ static int super_1_validate(mddev_t *mddev, mdk_rdev_t *rdev)
        struct mdp_superblock_1 *sb = (struct mdp_superblock_1*)page_address(rdev->sb_page);
 
        rdev->raid_disk = -1;
-       rdev->in_sync = 0;
+       rdev->flags = 0;
        if (mddev->raid_disks == 0) {
                mddev->major_version = 1;
                mddev->patch_version = 0;
@@ -996,22 +1066,19 @@ static int super_1_validate(mddev_t *mddev, mdk_rdev_t *rdev)
                role = le16_to_cpu(sb->dev_roles[rdev->desc_nr]);
                switch(role) {
                case 0xffff: /* spare */
-                       rdev->faulty = 0;
                        break;
                case 0xfffe: /* faulty */
-                       rdev->faulty = 1;
+                       set_bit(Faulty, &rdev->flags);
                        break;
                default:
-                       rdev->in_sync = 1;
-                       rdev->faulty = 0;
+                       set_bit(In_sync, &rdev->flags);
                        rdev->raid_disk = role;
                        break;
                }
-               rdev->flags = 0;
                if (sb->devflags & WriteMostly1)
                        set_bit(WriteMostly, &rdev->flags);
        } else /* MULTIPATH are always insync */
-               rdev->in_sync = 1;
+               set_bit(In_sync, &rdev->flags);
 
        return 0;
 }
@@ -1055,9 +1122,9 @@ static void super_1_sync(mddev_t *mddev, mdk_rdev_t *rdev)
        
        ITERATE_RDEV(mddev,rdev2,tmp) {
                i = rdev2->desc_nr;
-               if (rdev2->faulty)
+               if (test_bit(Faulty, &rdev2->flags))
                        sb->dev_roles[i] = cpu_to_le16(0xfffe);
-               else if (rdev2->in_sync)
+               else if (test_bit(In_sync, &rdev2->flags))
                        sb->dev_roles[i] = cpu_to_le16(rdev2->raid_disk);
                else
                        sb->dev_roles[i] = cpu_to_le16(0xffff);
@@ -1115,6 +1182,7 @@ static int bind_rdev_to_array(mdk_rdev_t * rdev, mddev_t * mddev)
 {
        mdk_rdev_t *same_pdev;
        char b[BDEVNAME_SIZE], b2[BDEVNAME_SIZE];
+       struct kobject *ko;
 
        if (rdev->mddev) {
                MD_BUG();
@@ -1143,10 +1211,22 @@ static int bind_rdev_to_array(mdk_rdev_t * rdev, mddev_t * mddev)
                if (find_rdev_nr(mddev, rdev->desc_nr))
                        return -EBUSY;
        }
+       bdevname(rdev->bdev,b);
+       if (kobject_set_name(&rdev->kobj, "dev-%s", b) < 0)
+               return -ENOMEM;
                        
        list_add(&rdev->same_set, &mddev->disks);
        rdev->mddev = mddev;
-       printk(KERN_INFO "md: bind<%s>\n", bdevname(rdev->bdev,b));
+       printk(KERN_INFO "md: bind<%s>\n", b);
+
+       rdev->kobj.parent = &mddev->kobj;
+       kobject_add(&rdev->kobj);
+
+       if (rdev->bdev->bd_part)
+               ko = &rdev->bdev->bd_part->kobj;
+       else
+               ko = &rdev->bdev->bd_disk->kobj;
+       sysfs_create_link(&rdev->kobj, ko, "block");
        return 0;
 }
 
@@ -1160,6 +1240,8 @@ static void unbind_rdev_from_array(mdk_rdev_t * rdev)
        list_del_init(&rdev->same_set);
        printk(KERN_INFO "md: unbind<%s>\n", bdevname(rdev->bdev,b));
        rdev->mddev = NULL;
+       sysfs_remove_link(&rdev->kobj, "block");
+       kobject_del(&rdev->kobj);
 }
 
 /*
@@ -1215,7 +1297,7 @@ static void export_rdev(mdk_rdev_t * rdev)
        md_autodetect_dev(rdev->bdev->bd_dev);
 #endif
        unlock_rdev(rdev);
-       kfree(rdev);
+       kobject_put(&rdev->kobj);
 }
 
 static void kick_rdev_from_array(mdk_rdev_t * rdev)
@@ -1287,7 +1369,8 @@ static void print_rdev(mdk_rdev_t *rdev)
        char b[BDEVNAME_SIZE];
        printk(KERN_INFO "md: rdev %s, SZ:%08llu F:%d S:%d DN:%u\n",
                bdevname(rdev->bdev,b), (unsigned long long)rdev->size,
-               rdev->faulty, rdev->in_sync, rdev->desc_nr);
+               test_bit(Faulty, &rdev->flags), test_bit(In_sync, &rdev->flags),
+               rdev->desc_nr);
        if (rdev->sb_loaded) {
                printk(KERN_INFO "md: rdev superblock:\n");
                print_sb((mdp_super_t*)page_address(rdev->sb_page));
@@ -1344,7 +1427,7 @@ static void md_update_sb(mddev_t * mddev)
        int sync_req;
 
 repeat:
-       spin_lock(&mddev->write_lock);
+       spin_lock_irq(&mddev->write_lock);
        sync_req = mddev->in_sync;
        mddev->utime = get_seconds();
        mddev->events ++;
@@ -1367,11 +1450,11 @@ repeat:
         */
        if (!mddev->persistent) {
                mddev->sb_dirty = 0;
-               spin_unlock(&mddev->write_lock);
+               spin_unlock_irq(&mddev->write_lock);
                wake_up(&mddev->sb_wait);
                return;
        }
-       spin_unlock(&mddev->write_lock);
+       spin_unlock_irq(&mddev->write_lock);
 
        dprintk(KERN_INFO 
                "md: updating %s RAID superblock on device (in sync %d)\n",
@@ -1381,11 +1464,11 @@ repeat:
        ITERATE_RDEV(mddev,rdev,tmp) {
                char b[BDEVNAME_SIZE];
                dprintk(KERN_INFO "md: ");
-               if (rdev->faulty)
+               if (test_bit(Faulty, &rdev->flags))
                        dprintk("(skipping faulty ");
 
                dprintk("%s ", bdevname(rdev->bdev,b));
-               if (!rdev->faulty) {
+               if (!test_bit(Faulty, &rdev->flags)) {
                        md_super_write(mddev,rdev,
                                       rdev->sb_offset<<1, rdev->sb_size,
                                       rdev->sb_page);
@@ -1399,21 +1482,106 @@ repeat:
                        /* only need to write one superblock... */
                        break;
        }
-       wait_event(mddev->sb_wait, atomic_read(&mddev->pending_writes)==0);
+       md_super_wait(mddev);
        /* if there was a failure, sb_dirty was set to 1, and we re-write super */
 
-       spin_lock(&mddev->write_lock);
+       spin_lock_irq(&mddev->write_lock);
        if (mddev->in_sync != sync_req|| mddev->sb_dirty == 1) {
                /* have to write it out again */
-               spin_unlock(&mddev->write_lock);
+               spin_unlock_irq(&mddev->write_lock);
                goto repeat;
        }
        mddev->sb_dirty = 0;
-       spin_unlock(&mddev->write_lock);
+       spin_unlock_irq(&mddev->write_lock);
        wake_up(&mddev->sb_wait);
 
 }
 
+struct rdev_sysfs_entry {
+       struct attribute attr;
+       ssize_t (*show)(mdk_rdev_t *, char *);
+       ssize_t (*store)(mdk_rdev_t *, const char *, size_t);
+};
+
+static ssize_t
+state_show(mdk_rdev_t *rdev, char *page)
+{
+       char *sep = "";
+       int len=0;
+
+       if (test_bit(Faulty, &rdev->flags)) {
+               len+= sprintf(page+len, "%sfaulty",sep);
+               sep = ",";
+       }
+       if (test_bit(In_sync, &rdev->flags)) {
+               len += sprintf(page+len, "%sin_sync",sep);
+               sep = ",";
+       }
+       if (!test_bit(Faulty, &rdev->flags) &&
+           !test_bit(In_sync, &rdev->flags)) {
+               len += sprintf(page+len, "%sspare", sep);
+               sep = ",";
+       }
+       return len+sprintf(page+len, "\n");
+}
+
+static struct rdev_sysfs_entry
+rdev_state = __ATTR_RO(state);
+
+static ssize_t
+super_show(mdk_rdev_t *rdev, char *page)
+{
+       if (rdev->sb_loaded && rdev->sb_size) {
+               memcpy(page, page_address(rdev->sb_page), rdev->sb_size);
+               return rdev->sb_size;
+       } else
+               return 0;
+}
+static struct rdev_sysfs_entry rdev_super = __ATTR_RO(super);
+
+static struct attribute *rdev_default_attrs[] = {
+       &rdev_state.attr,
+       &rdev_super.attr,
+       NULL,
+};
+static ssize_t
+rdev_attr_show(struct kobject *kobj, struct attribute *attr, char *page)
+{
+       struct rdev_sysfs_entry *entry = container_of(attr, struct rdev_sysfs_entry, attr);
+       mdk_rdev_t *rdev = container_of(kobj, mdk_rdev_t, kobj);
+
+       if (!entry->show)
+               return -EIO;
+       return entry->show(rdev, page);
+}
+
+static ssize_t
+rdev_attr_store(struct kobject *kobj, struct attribute *attr,
+             const char *page, size_t length)
+{
+       struct rdev_sysfs_entry *entry = container_of(attr, struct rdev_sysfs_entry, attr);
+       mdk_rdev_t *rdev = container_of(kobj, mdk_rdev_t, kobj);
+
+       if (!entry->store)
+               return -EIO;
+       return entry->store(rdev, page, length);
+}
+
+static void rdev_free(struct kobject *ko)
+{
+       mdk_rdev_t *rdev = container_of(ko, mdk_rdev_t, kobj);
+       kfree(rdev);
+}
+static struct sysfs_ops rdev_sysfs_ops = {
+       .show           = rdev_attr_show,
+       .store          = rdev_attr_store,
+};
+static struct kobj_type rdev_ktype = {
+       .release        = rdev_free,
+       .sysfs_ops      = &rdev_sysfs_ops,
+       .default_attrs  = rdev_default_attrs,
+};
+
 /*
  * Import a device. If 'super_format' >= 0, then sanity check the superblock
  *
@@ -1445,11 +1613,15 @@ static mdk_rdev_t *md_import_device(dev_t newdev, int super_format, int super_mi
        if (err)
                goto abort_free;
 
+       rdev->kobj.parent = NULL;
+       rdev->kobj.ktype = &rdev_ktype;
+       kobject_init(&rdev->kobj);
+
        rdev->desc_nr = -1;
-       rdev->faulty = 0;
-       rdev->in_sync = 0;
+       rdev->flags = 0;
        rdev->data_offset = 0;
        atomic_set(&rdev->nr_pending, 0);
+       atomic_set(&rdev->read_errors, 0);
 
        size = rdev->bdev->bd_inode->i_size >> BLOCK_SIZE_BITS;
        if (!size) {
@@ -1537,7 +1709,7 @@ static void analyze_sbs(mddev_t * mddev)
                if (mddev->level == LEVEL_MULTIPATH) {
                        rdev->desc_nr = i++;
                        rdev->raid_disk = rdev->desc_nr;
-                       rdev->in_sync = 1;
+                       set_bit(In_sync, &rdev->flags);
                }
        }
 
@@ -1551,6 +1723,162 @@ static void analyze_sbs(mddev_t * mddev)
 
 }
 
+static ssize_t
+level_show(mddev_t *mddev, char *page)
+{
+       mdk_personality_t *p = mddev->pers;
+       if (p == NULL && mddev->raid_disks == 0)
+               return 0;
+       if (mddev->level >= 0)
+               return sprintf(page, "RAID-%d\n", mddev->level);
+       else
+               return sprintf(page, "%s\n", p->name);
+}
+
+static struct md_sysfs_entry md_level = __ATTR_RO(level);
+
+static ssize_t
+raid_disks_show(mddev_t *mddev, char *page)
+{
+       if (mddev->raid_disks == 0)
+               return 0;
+       return sprintf(page, "%d\n", mddev->raid_disks);
+}
+
+static struct md_sysfs_entry md_raid_disks = __ATTR_RO(raid_disks);
+
+static ssize_t
+action_show(mddev_t *mddev, char *page)
+{
+       char *type = "idle";
+       if (test_bit(MD_RECOVERY_RUNNING, &mddev->recovery) ||
+           test_bit(MD_RECOVERY_NEEDED, &mddev->recovery)) {
+               if (test_bit(MD_RECOVERY_SYNC, &mddev->recovery)) {
+                       if (!test_bit(MD_RECOVERY_REQUESTED, &mddev->recovery))
+                               type = "resync";
+                       else if (test_bit(MD_RECOVERY_CHECK, &mddev->recovery))
+                               type = "check";
+                       else
+                               type = "repair";
+               } else
+                       type = "recover";
+       }
+       return sprintf(page, "%s\n", type);
+}
+
+static ssize_t
+action_store(mddev_t *mddev, const char *page, size_t len)
+{
+       if (!mddev->pers || !mddev->pers->sync_request)
+               return -EINVAL;
+
+       if (strcmp(page, "idle")==0 || strcmp(page, "idle\n")==0) {
+               if (mddev->sync_thread) {
+                       set_bit(MD_RECOVERY_INTR, &mddev->recovery);
+                       md_unregister_thread(mddev->sync_thread);
+                       mddev->sync_thread = NULL;
+                       mddev->recovery = 0;
+               }
+               return len;
+       }
+
+       if (test_bit(MD_RECOVERY_RUNNING, &mddev->recovery) ||
+           test_bit(MD_RECOVERY_NEEDED, &mddev->recovery))
+               return -EBUSY;
+       if (strcmp(page, "resync")==0 || strcmp(page, "resync\n")==0 ||
+           strcmp(page, "recover")==0 || strcmp(page, "recover\n")==0)
+               set_bit(MD_RECOVERY_NEEDED, &mddev->recovery);
+       else {
+               if (strcmp(page, "check")==0 || strcmp(page, "check\n")==0)
+                       set_bit(MD_RECOVERY_CHECK, &mddev->recovery);
+               else if (strcmp(page, "repair")!=0 && strcmp(page, "repair\n")!=0)
+                       return -EINVAL;
+               set_bit(MD_RECOVERY_REQUESTED, &mddev->recovery);
+               set_bit(MD_RECOVERY_SYNC, &mddev->recovery);
+               set_bit(MD_RECOVERY_NEEDED, &mddev->recovery);
+       }
+       md_wakeup_thread(mddev->thread);
+       return len;
+}
+
+static ssize_t
+mismatch_cnt_show(mddev_t *mddev, char *page)
+{
+       return sprintf(page, "%llu\n",
+                      (unsigned long long) mddev->resync_mismatches);
+}
+
+static struct md_sysfs_entry
+md_scan_mode = __ATTR(sync_action, S_IRUGO|S_IWUSR, action_show, action_store);
+
+
+static struct md_sysfs_entry
+md_mismatches = __ATTR_RO(mismatch_cnt);
+
+static struct attribute *md_default_attrs[] = {
+       &md_level.attr,
+       &md_raid_disks.attr,
+       NULL,
+};
+
+static struct attribute *md_redundancy_attrs[] = {
+       &md_scan_mode.attr,
+       &md_mismatches.attr,
+       NULL,
+};
+static struct attribute_group md_redundancy_group = {
+       .name = NULL,
+       .attrs = md_redundancy_attrs,
+};
+
+
+static ssize_t
+md_attr_show(struct kobject *kobj, struct attribute *attr, char *page)
+{
+       struct md_sysfs_entry *entry = container_of(attr, struct md_sysfs_entry, attr);
+       mddev_t *mddev = container_of(kobj, struct mddev_s, kobj);
+       ssize_t rv;
+
+       if (!entry->show)
+               return -EIO;
+       mddev_lock(mddev);
+       rv = entry->show(mddev, page);
+       mddev_unlock(mddev);
+       return rv;
+}
+
+static ssize_t
+md_attr_store(struct kobject *kobj, struct attribute *attr,
+             const char *page, size_t length)
+{
+       struct md_sysfs_entry *entry = container_of(attr, struct md_sysfs_entry, attr);
+       mddev_t *mddev = container_of(kobj, struct mddev_s, kobj);
+       ssize_t rv;
+
+       if (!entry->store)
+               return -EIO;
+       mddev_lock(mddev);
+       rv = entry->store(mddev, page, length);
+       mddev_unlock(mddev);
+       return rv;
+}
+
+static void md_free(struct kobject *ko)
+{
+       mddev_t *mddev = container_of(ko, mddev_t, kobj);
+       kfree(mddev);
+}
+
+static struct sysfs_ops md_sysfs_ops = {
+       .show   = md_attr_show,
+       .store  = md_attr_store,
+};
+static struct kobj_type md_ktype = {
+       .release        = md_free,
+       .sysfs_ops      = &md_sysfs_ops,
+       .default_attrs  = md_default_attrs,
+};
+
 int mdp_major = 0;
 
 static struct kobject *md_probe(dev_t dev, int *part, void *data)
@@ -1592,6 +1920,11 @@ static struct kobject *md_probe(dev_t dev, int *part, void *data)
        add_disk(disk);
        mddev->gendisk = disk;
        up(&disks_sem);
+       mddev->kobj.parent = &disk->kobj;
+       mddev->kobj.k_name = NULL;
+       snprintf(mddev->kobj.name, KOBJ_NAME_LEN, "%s", "md");
+       mddev->kobj.ktype = &md_ktype;
+       kobject_register(&mddev->kobj);
        return NULL;
 }
 
@@ -1663,7 +1996,7 @@ static int do_md_run(mddev_t * mddev)
 
                /* devices must have minimum size of one chunk */
                ITERATE_RDEV(mddev,rdev,tmp) {
-                       if (rdev->faulty)
+                       if (test_bit(Faulty, &rdev->flags))
                                continue;
                        if (rdev->size < chunk_size / 1024) {
                                printk(KERN_WARNING
@@ -1691,7 +2024,7 @@ static int do_md_run(mddev_t * mddev)
         * Also find largest hardsector size
         */
        ITERATE_RDEV(mddev,rdev,tmp) {
-               if (rdev->faulty)
+               if (test_bit(Faulty, &rdev->flags))
                        continue;
                sync_blockdev(rdev->bdev);
                invalidate_bdev(rdev->bdev, 0);
@@ -1715,6 +2048,10 @@ static int do_md_run(mddev_t * mddev)
 
        mddev->recovery = 0;
        mddev->resync_max_sectors = mddev->size << 1; /* may be over-ridden by personality */
+       mddev->barriers_work = 1;
+
+       if (start_readonly)
+               mddev->ro = 2; /* read-only, but switch on first write */
 
        /* before we start the array running, initialise the bitmap */
        err = bitmap_create(mddev);
@@ -1730,12 +2067,24 @@ static int do_md_run(mddev_t * mddev)
                bitmap_destroy(mddev);
                return err;
        }
+       if (mddev->pers->sync_request)
+               sysfs_create_group(&mddev->kobj, &md_redundancy_group);
+       else if (mddev->ro == 2) /* auto-readonly not meaningful */
+               mddev->ro = 0;
+
        atomic_set(&mddev->writes_pending,0);
        mddev->safemode = 0;
        mddev->safemode_timer.function = md_safemode_timeout;
        mddev->safemode_timer.data = (unsigned long) mddev;
        mddev->safemode_delay = (20 * HZ)/1000 +1; /* 20 msec delay */
        mddev->in_sync = 1;
+
+       ITERATE_RDEV(mddev,rdev,tmp)
+               if (rdev->raid_disk >= 0) {
+                       char nm[20];
+                       sprintf(nm, "rd%d", rdev->raid_disk);
+                       sysfs_create_link(&mddev->kobj, &rdev->kobj, nm);
+               }
        
        set_bit(MD_RECOVERY_NEEDED, &mddev->recovery);
        md_wakeup_thread(mddev->thread);
@@ -1821,16 +2170,19 @@ static int do_md_stop(mddev_t * mddev, int ro)
 
                if (ro) {
                        err  = -ENXIO;
-                       if (mddev->ro)
+                       if (mddev->ro==1)
                                goto out;
                        mddev->ro = 1;
                } else {
                        bitmap_flush(mddev);
-                       wait_event(mddev->sb_wait, atomic_read(&mddev->pending_writes)==0);
+                       md_super_wait(mddev);
                        if (mddev->ro)
                                set_disk_ro(disk, 0);
                        blk_queue_make_request(mddev->queue, md_fail_request);
                        mddev->pers->stop(mddev);
+                       if (mddev->pers->sync_request)
+                               sysfs_remove_group(&mddev->kobj, &md_redundancy_group);
+
                        module_put(mddev->pers->owner);
                        mddev->pers = NULL;
                        if (mddev->ro)
@@ -1857,9 +2209,18 @@ static int do_md_stop(mddev_t * mddev, int ro)
         * Free resources if final stop
         */
        if (!ro) {
+               mdk_rdev_t *rdev;
+               struct list_head *tmp;
                struct gendisk *disk;
                printk(KERN_INFO "md: %s stopped.\n", mdname(mddev));
 
+               ITERATE_RDEV(mddev,rdev,tmp)
+                       if (rdev->raid_disk >= 0) {
+                               char nm[20];
+                               sprintf(nm, "rd%d", rdev->raid_disk);
+                               sysfs_remove_link(&mddev->kobj, nm);
+                       }
+
                export_array(mddev);
 
                mddev->array_size = 0;
@@ -2012,7 +2373,7 @@ static int autostart_array(dev_t startdev)
                return err;
        }
 
-       if (start_rdev->faulty) {
+       if (test_bit(Faulty, &start_rdev->flags)) {
                printk(KERN_WARNING 
                        "md: can not autostart based on faulty %s!\n",
                        bdevname(start_rdev->bdev,b));
@@ -2071,11 +2432,11 @@ static int get_array_info(mddev_t * mddev, void __user * arg)
        nr=working=active=failed=spare=0;
        ITERATE_RDEV(mddev,rdev,tmp) {
                nr++;
-               if (rdev->faulty)
+               if (test_bit(Faulty, &rdev->flags))
                        failed++;
                else {
                        working++;
-                       if (rdev->in_sync)
+                       if (test_bit(In_sync, &rdev->flags))
                                active++;       
                        else
                                spare++;
@@ -2166,9 +2527,9 @@ static int get_disk_info(mddev_t * mddev, void __user * arg)
                info.minor = MINOR(rdev->bdev->bd_dev);
                info.raid_disk = rdev->raid_disk;
                info.state = 0;
-               if (rdev->faulty)
+               if (test_bit(Faulty, &rdev->flags))
                        info.state |= (1<<MD_DISK_FAULTY);
-               else if (rdev->in_sync) {
+               else if (test_bit(In_sync, &rdev->flags)) {
                        info.state |= (1<<MD_DISK_ACTIVE);
                        info.state |= (1<<MD_DISK_SYNC);
                }
@@ -2261,7 +2622,7 @@ static int add_new_disk(mddev_t * mddev, mdu_disk_info_t *info)
                                validate_super(mddev, rdev);
                rdev->saved_raid_disk = rdev->raid_disk;
 
-               rdev->in_sync = 0; /* just to be sure */
+               clear_bit(In_sync, &rdev->flags); /* just to be sure */
                if (info->state & (1<<MD_DISK_WRITEMOSTLY))
                        set_bit(WriteMostly, &rdev->flags);
 
@@ -2299,11 +2660,11 @@ static int add_new_disk(mddev_t * mddev, mdu_disk_info_t *info)
                else
                        rdev->raid_disk = -1;
 
-               rdev->faulty = 0;
+               rdev->flags = 0;
+
                if (rdev->raid_disk < mddev->raid_disks)
-                       rdev->in_sync = (info->state & (1<<MD_DISK_SYNC));
-               else
-                       rdev->in_sync = 0;
+                       if (info->state & (1<<MD_DISK_SYNC))
+                               set_bit(In_sync, &rdev->flags);
 
                if (info->state & (1<<MD_DISK_WRITEMOSTLY))
                        set_bit(WriteMostly, &rdev->flags);
@@ -2402,14 +2763,14 @@ static int hot_add_disk(mddev_t * mddev, dev_t dev)
                goto abort_export;
        }
 
-       if (rdev->faulty) {
+       if (test_bit(Faulty, &rdev->flags)) {
                printk(KERN_WARNING 
                        "md: can not hot-add faulty %s disk to %s!\n",
                        bdevname(rdev->bdev,b), mdname(mddev));
                err = -EINVAL;
                goto abort_export;
        }
-       rdev->in_sync = 0;
+       clear_bit(In_sync, &rdev->flags);
        rdev->desc_nr = -1;
        bind_rdev_to_array(rdev, mddev);
 
@@ -2929,12 +3290,22 @@ static int md_ioctl(struct inode *inode, struct file *file,
 
        /*
         * The remaining ioctls are changing the state of the
-        * superblock, so we do not allow read-only arrays
-        * here:
+        * superblock, so we do not allow them on read-only arrays.
+        * However non-MD ioctls (e.g. get-size) will still come through
+        * here and hit the 'default' below, so only disallow
+        * 'md' ioctls, and switch to rw mode if started auto-readonly.
         */
-       if (mddev->ro) {
-               err = -EROFS;
-               goto abort_unlock;
+       if (_IOC_TYPE(cmd) == MD_MAJOR &&
+           mddev->ro && mddev->pers) {
+               if (mddev->ro == 2) {
+                       mddev->ro = 0;
+               set_bit(MD_RECOVERY_NEEDED, &mddev->recovery);
+               md_wakeup_thread(mddev->thread);
+
+               } else {
+                       err = -EROFS;
+                       goto abort_unlock;
+               }
        }
 
        switch (cmd)
@@ -3064,21 +3435,17 @@ static int md_thread(void * arg)
         */
 
        allow_signal(SIGKILL);
-       complete(thread->event);
        while (!kthread_should_stop()) {
-               void (*run)(mddev_t *);
 
-               wait_event_interruptible_timeout(thread->wqueue,
-                                                test_bit(THREAD_WAKEUP, &thread->flags)
-                                                || kthread_should_stop(),
-                                                thread->timeout);
+               wait_event_timeout(thread->wqueue,
+                                  test_bit(THREAD_WAKEUP, &thread->flags)
+                                  || kthread_should_stop(),
+                                  thread->timeout);
                try_to_freeze();
 
                clear_bit(THREAD_WAKEUP, &thread->flags);
 
-               run = thread->run;
-               if (run)
-                       run(thread->mddev);
+               thread->run(thread->mddev);
        }
 
        return 0;
@@ -3097,7 +3464,6 @@ mdk_thread_t *md_register_thread(void (*run) (mddev_t *), mddev_t *mddev,
                                 const char *name)
 {
        mdk_thread_t *thread;
-       struct completion event;
 
        thread = kmalloc(sizeof(mdk_thread_t), GFP_KERNEL);
        if (!thread)
@@ -3106,18 +3472,14 @@ mdk_thread_t *md_register_thread(void (*run) (mddev_t *), mddev_t *mddev,
        memset(thread, 0, sizeof(mdk_thread_t));
        init_waitqueue_head(&thread->wqueue);
 
-       init_completion(&event);
-       thread->event = &event;
        thread->run = run;
        thread->mddev = mddev;
-       thread->name = name;
        thread->timeout = MAX_SCHEDULE_TIMEOUT;
        thread->tsk = kthread_run(md_thread, thread, name, mdname(thread->mddev));
        if (IS_ERR(thread->tsk)) {
                kfree(thread);
                return NULL;
        }
-       wait_for_completion(&event);
        return thread;
 }
 
@@ -3136,7 +3498,7 @@ void md_error(mddev_t *mddev, mdk_rdev_t *rdev)
                return;
        }
 
-       if (!rdev || rdev->faulty)
+       if (!rdev || test_bit(Faulty, &rdev->flags))
                return;
 /*
        dprintk("md_error dev:%s, rdev:(%d:%d), (caller: %p,%p,%p,%p).\n",
@@ -3322,8 +3684,10 @@ static int md_seq_show(struct seq_file *seq, void *v)
                seq_printf(seq, "%s : %sactive", mdname(mddev),
                                                mddev->pers ? "" : "in");
                if (mddev->pers) {
-                       if (mddev->ro)
+                       if (mddev->ro==1)
                                seq_printf(seq, " (read-only)");
+                       if (mddev->ro==2)
+                               seq_printf(seq, "(auto-read-only)");
                        seq_printf(seq, " %s", mddev->pers->name);
                }
 
@@ -3334,7 +3698,7 @@ static int md_seq_show(struct seq_file *seq, void *v)
                                bdevname(rdev->bdev,b), rdev->desc_nr);
                        if (test_bit(WriteMostly, &rdev->flags))
                                seq_printf(seq, "(W)");
-                       if (rdev->faulty) {
+                       if (test_bit(Faulty, &rdev->flags)) {
                                seq_printf(seq, "(F)");
                                continue;
                        } else if (rdev->raid_disk < 0)
@@ -3363,11 +3727,15 @@ static int md_seq_show(struct seq_file *seq, void *v)
                if (mddev->pers) {
                        mddev->pers->status (seq, mddev);
                        seq_printf(seq, "\n      ");
-                       if (mddev->curr_resync > 2) {
-                               status_resync (seq, mddev);
-                               seq_printf(seq, "\n      ");
-                       } else if (mddev->curr_resync == 1 || mddev->curr_resync == 2)
-                               seq_printf(seq, "       resync=DELAYED\n      ");
+                       if (mddev->pers->sync_request) {
+                               if (mddev->curr_resync > 2) {
+                                       status_resync (seq, mddev);
+                                       seq_printf(seq, "\n      ");
+                               } else if (mddev->curr_resync == 1 || mddev->curr_resync == 2)
+                                       seq_printf(seq, "\tresync=DELAYED\n      ");
+                               else if (mddev->recovery_cp < MaxSector)
+                                       seq_printf(seq, "\tresync=PENDING\n      ");
+                       }
                } else
                        seq_printf(seq, "\n       ");
 
@@ -3504,15 +3872,22 @@ void md_write_start(mddev_t *mddev, struct bio *bi)
        if (bio_data_dir(bi) != WRITE)
                return;
 
+       BUG_ON(mddev->ro == 1);
+       if (mddev->ro == 2) {
+               /* need to switch to read/write */
+               mddev->ro = 0;
+               set_bit(MD_RECOVERY_NEEDED, &mddev->recovery);
+               md_wakeup_thread(mddev->thread);
+       }
        atomic_inc(&mddev->writes_pending);
        if (mddev->in_sync) {
-               spin_lock(&mddev->write_lock);
+               spin_lock_irq(&mddev->write_lock);
                if (mddev->in_sync) {
                        mddev->in_sync = 0;
                        mddev->sb_dirty = 1;
                        md_wakeup_thread(mddev->thread);
                }
-               spin_unlock(&mddev->write_lock);
+               spin_unlock_irq(&mddev->write_lock);
        }
        wait_event(mddev->sb_wait, mddev->sb_dirty==0);
 }
@@ -3568,9 +3943,7 @@ static void md_do_sync(mddev_t *mddev)
                mddev->curr_resync = 2;
 
        try_again:
-               if (signal_pending(current) ||
-                   kthread_should_stop()) {
-                       flush_signals(current);
+               if (kthread_should_stop()) {
                        set_bit(MD_RECOVERY_INTR, &mddev->recovery);
                        goto skip;
                }
@@ -3590,9 +3963,8 @@ static void md_do_sync(mddev_t *mddev)
                                         * time 'round when curr_resync == 2
                                         */
                                        continue;
-                               prepare_to_wait(&resync_wait, &wq, TASK_INTERRUPTIBLE);
-                               if (!signal_pending(current) &&
-                                   !kthread_should_stop() &&
+                               prepare_to_wait(&resync_wait, &wq, TASK_UNINTERRUPTIBLE);
+                               if (!kthread_should_stop() &&
                                    mddev2->curr_resync >= mddev->curr_resync) {
                                        printk(KERN_INFO "md: delaying resync of %s"
                                               " until %s has finished resync (they"
@@ -3608,12 +3980,13 @@ static void md_do_sync(mddev_t *mddev)
                }
        } while (mddev->curr_resync < 2);
 
-       if (test_bit(MD_RECOVERY_SYNC, &mddev->recovery))
+       if (test_bit(MD_RECOVERY_SYNC, &mddev->recovery)) {
                /* resync follows the size requested by the personality,
                 * which defaults to physical size, but can be virtual size
                 */
                max_sectors = mddev->resync_max_sectors;
-       else
+               mddev->resync_mismatches = 0;
+       } else
                /* recovery follows the physical size of devices */
                max_sectors = mddev->size << 1;
 
@@ -3626,7 +3999,8 @@ static void md_do_sync(mddev_t *mddev)
 
        is_mddev_idle(mddev); /* this also initializes IO event counters */
        /* we don't use the checkpoint if there's a bitmap */
-       if (test_bit(MD_RECOVERY_SYNC, &mddev->recovery) && !mddev->bitmap)
+       if (test_bit(MD_RECOVERY_SYNC, &mddev->recovery) && !mddev->bitmap
+           && ! test_bit(MD_RECOVERY_REQUESTED, &mddev->recovery))
                j = mddev->recovery_cp;
        else
                j = 0;
@@ -3699,13 +4073,12 @@ static void md_do_sync(mddev_t *mddev)
                }
 
 
-               if (signal_pending(current) || kthread_should_stop()) {
+               if (kthread_should_stop()) {
                        /*
                         * got a signal, exit.
                         */
                        printk(KERN_INFO 
                                "md: md_do_sync() got signal ... exiting\n");
-                       flush_signals(current);
                        set_bit(MD_RECOVERY_INTR, &mddev->recovery);
                        goto out;
                }
@@ -3727,7 +4100,7 @@ static void md_do_sync(mddev_t *mddev)
                if (currspeed > sysctl_speed_limit_min) {
                        if ((currspeed > sysctl_speed_limit_max) ||
                                        !is_mddev_idle(mddev)) {
-                               msleep_interruptible(250);
+                               msleep(250);
                                goto repeat;
                        }
                }
@@ -3820,7 +4193,7 @@ void md_check_recovery(mddev_t *mddev)
        if (mddev_trylock(mddev)==0) {
                int spares =0;
 
-               spin_lock(&mddev->write_lock);
+               spin_lock_irq(&mddev->write_lock);
                if (mddev->safemode && !atomic_read(&mddev->writes_pending) &&
                    !mddev->in_sync && mddev->recovery_cp == MaxSector) {
                        mddev->in_sync = 1;
@@ -3828,7 +4201,7 @@ void md_check_recovery(mddev_t *mddev)
                }
                if (mddev->safemode == 1)
                        mddev->safemode = 0;
-               spin_unlock(&mddev->write_lock);
+               spin_unlock_irq(&mddev->write_lock);
 
                if (mddev->sb_dirty)
                        md_update_sb(mddev);
@@ -3864,9 +4237,13 @@ void md_check_recovery(mddev_t *mddev)
                        set_bit(MD_RECOVERY_NEEDED, &mddev->recovery);
                        goto unlock;
                }
-               if (mddev->recovery)
-                       /* probably just the RECOVERY_NEEDED flag */
-                       mddev->recovery = 0;
+               /* Clear some bits that don't mean anything, but
+                * might be left set
+                */
+               clear_bit(MD_RECOVERY_NEEDED, &mddev->recovery);
+               clear_bit(MD_RECOVERY_ERR, &mddev->recovery);
+               clear_bit(MD_RECOVERY_INTR, &mddev->recovery);
+               clear_bit(MD_RECOVERY_DONE, &mddev->recovery);
 
                /* no recovery is running.
                 * remove any failed drives, then
@@ -3876,31 +4253,41 @@ void md_check_recovery(mddev_t *mddev)
                 */
                ITERATE_RDEV(mddev,rdev,rtmp)
                        if (rdev->raid_disk >= 0 &&
-                           (rdev->faulty || ! rdev->in_sync) &&
+                           (test_bit(Faulty, &rdev->flags) || ! test_bit(In_sync, &rdev->flags)) &&
                            atomic_read(&rdev->nr_pending)==0) {
-                               if (mddev->pers->hot_remove_disk(mddev, rdev->raid_disk)==0)
+                               if (mddev->pers->hot_remove_disk(mddev, rdev->raid_disk)==0) {
+                                       char nm[20];
+                                       sprintf(nm,"rd%d", rdev->raid_disk);
+                                       sysfs_remove_link(&mddev->kobj, nm);
                                        rdev->raid_disk = -1;
+                               }
                        }
 
                if (mddev->degraded) {
                        ITERATE_RDEV(mddev,rdev,rtmp)
                                if (rdev->raid_disk < 0
-                                   && !rdev->faulty) {
-                                       if (mddev->pers->hot_add_disk(mddev,rdev))
+                                   && !test_bit(Faulty, &rdev->flags)) {
+                                       if (mddev->pers->hot_add_disk(mddev,rdev)) {
+                                               char nm[20];
+                                               sprintf(nm, "rd%d", rdev->raid_disk);
+                                               sysfs_create_link(&mddev->kobj, &rdev->kobj, nm);
                                                spares++;
-                                       else
+                                       else
                                                break;
                                }
                }
 
-               if (!spares && (mddev->recovery_cp == MaxSector )) {
-                       /* nothing we can do ... */
+               if (spares) {
+                       clear_bit(MD_RECOVERY_SYNC, &mddev->recovery);
+                       clear_bit(MD_RECOVERY_CHECK, &mddev->recovery);
+               } else if (mddev->recovery_cp < MaxSector) {
+                       set_bit(MD_RECOVERY_SYNC, &mddev->recovery);
+               } else if (!test_bit(MD_RECOVERY_SYNC, &mddev->recovery))
+                       /* nothing to be done ... */
                        goto unlock;
-               }
+
                if (mddev->pers->sync_request) {
                        set_bit(MD_RECOVERY_RUNNING, &mddev->recovery);
-                       if (!spares)
-                               set_bit(MD_RECOVERY_SYNC, &mddev->recovery);
                        if (spares && mddev->bitmap && ! mddev->bitmap->file) {
                                /* We are adding a device or devices to an array
                                 * which has the bitmap stored on all devices.
@@ -3975,7 +4362,7 @@ static int __init md_init(void)
                        " MD_SB_DISKS=%d\n",
                        MD_MAJOR_VERSION, MD_MINOR_VERSION,
                        MD_PATCHLEVEL_VERSION, MAX_MD_DEVS, MD_SB_DISKS);
-       printk(KERN_INFO "md: bitmap version %d.%d\n", BITMAP_MAJOR,
+       printk(KERN_INFO "md: bitmap version %d.%d\n", BITMAP_MAJOR_HI,
                        BITMAP_MINOR);
 
        if (register_blkdev(MAJOR_NR, "md"))
@@ -4039,7 +4426,7 @@ static void autostart_arrays(int part)
                if (IS_ERR(rdev))
                        continue;
 
-               if (rdev->faulty) {
+               if (test_bit(Faulty, &rdev->flags)) {
                        MD_BUG();
                        continue;
                }
@@ -4086,6 +4473,23 @@ static __exit void md_exit(void)
 module_init(md_init)
 module_exit(md_exit)
 
+static int get_ro(char *buffer, struct kernel_param *kp)
+{
+       return sprintf(buffer, "%d", start_readonly);
+}
+static int set_ro(const char *val, struct kernel_param *kp)
+{
+       char *e;
+       int num = simple_strtoul(val, &e, 10);
+       if (*val && (*e == '\0' || *e == '\n')) {
+               start_readonly = num;
+               return 0;;
+       }
+       return -EINVAL;
+}
+
+module_param_call(start_ro, set_ro, get_ro, NULL, 0600);
+
 EXPORT_SYMBOL(register_md_personality);
 EXPORT_SYMBOL(unregister_md_personality);
 EXPORT_SYMBOL(md_error);
index c06f4474192b712438a2538b47607c51f246b7b8..145cdc5ad008090e67cabe449e10d8cac5395ff1 100644 (file)
@@ -63,8 +63,8 @@ static int multipath_map (multipath_conf_t *conf)
 
        rcu_read_lock();
        for (i = 0; i < disks; i++) {
-               mdk_rdev_t *rdev = conf->multipaths[i].rdev;
-               if (rdev && rdev->in_sync) {
+               mdk_rdev_t *rdev = rcu_dereference(conf->multipaths[i].rdev);
+               if (rdev && test_bit(In_sync, &rdev->flags)) {
                        atomic_inc(&rdev->nr_pending);
                        rcu_read_unlock();
                        return i;
@@ -139,8 +139,9 @@ static void unplug_slaves(mddev_t *mddev)
 
        rcu_read_lock();
        for (i=0; i<mddev->raid_disks; i++) {
-               mdk_rdev_t *rdev = conf->multipaths[i].rdev;
-               if (rdev && !rdev->faulty && atomic_read(&rdev->nr_pending)) {
+               mdk_rdev_t *rdev = rcu_dereference(conf->multipaths[i].rdev);
+               if (rdev && !test_bit(Faulty, &rdev->flags)
+                   && atomic_read(&rdev->nr_pending)) {
                        request_queue_t *r_queue = bdev_get_queue(rdev->bdev);
 
                        atomic_inc(&rdev->nr_pending);
@@ -211,7 +212,7 @@ static void multipath_status (struct seq_file *seq, mddev_t *mddev)
        for (i = 0; i < conf->raid_disks; i++)
                seq_printf (seq, "%s",
                               conf->multipaths[i].rdev && 
-                              conf->multipaths[i].rdev->in_sync ? "U" : "_");
+                              test_bit(In_sync, &conf->multipaths[i].rdev->flags) ? "U" : "_");
        seq_printf (seq, "]");
 }
 
@@ -224,8 +225,8 @@ static int multipath_issue_flush(request_queue_t *q, struct gendisk *disk,
 
        rcu_read_lock();
        for (i=0; i<mddev->raid_disks && ret == 0; i++) {
-               mdk_rdev_t *rdev = conf->multipaths[i].rdev;
-               if (rdev && !rdev->faulty) {
+               mdk_rdev_t *rdev = rcu_dereference(conf->multipaths[i].rdev);
+               if (rdev && !test_bit(Faulty, &rdev->flags)) {
                        struct block_device *bdev = rdev->bdev;
                        request_queue_t *r_queue = bdev_get_queue(bdev);
 
@@ -265,10 +266,10 @@ static void multipath_error (mddev_t *mddev, mdk_rdev_t *rdev)
                /*
                 * Mark disk as unusable
                 */
-               if (!rdev->faulty) {
+               if (!test_bit(Faulty, &rdev->flags)) {
                        char b[BDEVNAME_SIZE];
-                       rdev->in_sync = 0;
-                       rdev->faulty = 1;
+                       clear_bit(In_sync, &rdev->flags);
+                       set_bit(Faulty, &rdev->flags);
                        mddev->sb_dirty = 1;
                        conf->working_disks--;
                        printk(KERN_ALERT "multipath: IO failure on %s,"
@@ -298,7 +299,7 @@ static void print_multipath_conf (multipath_conf_t *conf)
                tmp = conf->multipaths + i;
                if (tmp->rdev)
                        printk(" disk%d, o:%d, dev:%s\n",
-                               i,!tmp->rdev->faulty,
+                               i,!test_bit(Faulty, &tmp->rdev->flags),
                               bdevname(tmp->rdev->bdev,b));
        }
 }
@@ -330,8 +331,8 @@ static int multipath_add_disk(mddev_t *mddev, mdk_rdev_t *rdev)
 
                        conf->working_disks++;
                        rdev->raid_disk = path;
-                       rdev->in_sync = 1;
-                       p->rdev = rdev;
+                       set_bit(In_sync, &rdev->flags);
+                       rcu_assign_pointer(p->rdev, rdev);
                        found = 1;
                }
 
@@ -350,7 +351,7 @@ static int multipath_remove_disk(mddev_t *mddev, int number)
 
        rdev = p->rdev;
        if (rdev) {
-               if (rdev->in_sync ||
+               if (test_bit(In_sync, &rdev->flags) ||
                    atomic_read(&rdev->nr_pending)) {
                        printk(KERN_ERR "hot-remove-disk, slot %d is identified"                                " but is still operational!\n", number);
                        err = -EBUSY;
@@ -482,7 +483,7 @@ static int multipath_run (mddev_t *mddev)
                    mddev->queue->max_sectors > (PAGE_SIZE>>9))
                        blk_queue_max_sectors(mddev->queue, PAGE_SIZE>>9);
 
-               if (!rdev->faulty) 
+               if (!test_bit(Faulty, &rdev->flags))
                        conf->working_disks++;
        }
 
index e16f473bcf46b2bf1888eed7472c6474e4dc641e..2da9d3ba902dd1337ff2d724e46838f9d604f148 100644 (file)
@@ -301,7 +301,7 @@ static int raid1_end_write_request(struct bio *bio, unsigned int bytes_done, int
 {
        int uptodate = test_bit(BIO_UPTODATE, &bio->bi_flags);
        r1bio_t * r1_bio = (r1bio_t *)(bio->bi_private);
-       int mirror, behind;
+       int mirror, behind = test_bit(R1BIO_BehindIO, &r1_bio->state);
        conf_t *conf = mddev_to_conf(r1_bio->mddev);
 
        if (bio->bi_size)
@@ -311,47 +311,54 @@ static int raid1_end_write_request(struct bio *bio, unsigned int bytes_done, int
                if (r1_bio->bios[mirror] == bio)
                        break;
 
-       /*
-        * this branch is our 'one mirror IO has finished' event handler:
-        */
-       if (!uptodate) {
-               md_error(r1_bio->mddev, conf->mirrors[mirror].rdev);
-               /* an I/O failed, we can't clear the bitmap */
-               set_bit(R1BIO_Degraded, &r1_bio->state);
-       } else
+       if (error == -ENOTSUPP && test_bit(R1BIO_Barrier, &r1_bio->state)) {
+               set_bit(BarriersNotsupp, &conf->mirrors[mirror].rdev->flags);
+               set_bit(R1BIO_BarrierRetry, &r1_bio->state);
+               r1_bio->mddev->barriers_work = 0;
+       } else {
                /*
-                * Set R1BIO_Uptodate in our master bio, so that
-                * we will return a good error code for to the higher
-                * levels even if IO on some other mirrored buffer fails.
-                *
-                * The 'master' represents the composite IO operation to
-                * user-side. So if something waits for IO, then it will
-                * wait for the 'master' bio.
+                * this branch is our 'one mirror IO has finished' event handler:
                 */
-               set_bit(R1BIO_Uptodate, &r1_bio->state);
-
-       update_head_pos(mirror, r1_bio);
-
-       behind = test_bit(R1BIO_BehindIO, &r1_bio->state);
-       if (behind) {
-               if (test_bit(WriteMostly, &conf->mirrors[mirror].rdev->flags))
-                       atomic_dec(&r1_bio->behind_remaining);
-
-               /* In behind mode, we ACK the master bio once the I/O has safely
-                * reached all non-writemostly disks. Setting the Returned bit
-                * ensures that this gets done only once -- we don't ever want to
-                * return -EIO here, instead we'll wait */
-
-               if (atomic_read(&r1_bio->behind_remaining) >= (atomic_read(&r1_bio->remaining)-1) &&
-                   test_bit(R1BIO_Uptodate, &r1_bio->state)) {
-                       /* Maybe we can return now */
-                       if (!test_and_set_bit(R1BIO_Returned, &r1_bio->state)) {
-                               struct bio *mbio = r1_bio->master_bio;
-                               PRINTK(KERN_DEBUG "raid1: behind end write sectors %llu-%llu\n",
-                                      (unsigned long long) mbio->bi_sector,
-                                      (unsigned long long) mbio->bi_sector +
-                                      (mbio->bi_size >> 9) - 1);
-                               bio_endio(mbio, mbio->bi_size, 0);
+               r1_bio->bios[mirror] = NULL;
+               bio_put(bio);
+               if (!uptodate) {
+                       md_error(r1_bio->mddev, conf->mirrors[mirror].rdev);
+                       /* an I/O failed, we can't clear the bitmap */
+                       set_bit(R1BIO_Degraded, &r1_bio->state);
+               } else
+                       /*
+                        * Set R1BIO_Uptodate in our master bio, so that
+                        * we will return a good error code for to the higher
+                        * levels even if IO on some other mirrored buffer fails.
+                        *
+                        * The 'master' represents the composite IO operation to
+                        * user-side. So if something waits for IO, then it will
+                        * wait for the 'master' bio.
+                        */
+                       set_bit(R1BIO_Uptodate, &r1_bio->state);
+
+               update_head_pos(mirror, r1_bio);
+
+               if (behind) {
+                       if (test_bit(WriteMostly, &conf->mirrors[mirror].rdev->flags))
+                               atomic_dec(&r1_bio->behind_remaining);
+
+                       /* In behind mode, we ACK the master bio once the I/O has safely
+                        * reached all non-writemostly disks. Setting the Returned bit
+                        * ensures that this gets done only once -- we don't ever want to
+                        * return -EIO here, instead we'll wait */
+
+                       if (atomic_read(&r1_bio->behind_remaining) >= (atomic_read(&r1_bio->remaining)-1) &&
+                           test_bit(R1BIO_Uptodate, &r1_bio->state)) {
+                               /* Maybe we can return now */
+                               if (!test_and_set_bit(R1BIO_Returned, &r1_bio->state)) {
+                                       struct bio *mbio = r1_bio->master_bio;
+                                       PRINTK(KERN_DEBUG "raid1: behind end write sectors %llu-%llu\n",
+                                              (unsigned long long) mbio->bi_sector,
+                                              (unsigned long long) mbio->bi_sector +
+                                              (mbio->bi_size >> 9) - 1);
+                                       bio_endio(mbio, mbio->bi_size, 0);
+                               }
                        }
                }
        }
@@ -361,8 +368,16 @@ static int raid1_end_write_request(struct bio *bio, unsigned int bytes_done, int
         * already.
         */
        if (atomic_dec_and_test(&r1_bio->remaining)) {
+               if (test_bit(R1BIO_BarrierRetry, &r1_bio->state)) {
+                       reschedule_retry(r1_bio);
+                       /* Don't dec_pending yet, we want to hold
+                        * the reference over the retry
+                        */
+                       return 0;
+               }
                if (test_bit(R1BIO_BehindIO, &r1_bio->state)) {
                        /* free extra copy of the data pages */
+/* FIXME bio has been freed!!! */
                        int i = bio->bi_vcnt;
                        while (i--)
                                __free_page(bio->bi_io_vec[i].bv_page);
@@ -416,12 +431,12 @@ static int read_balance(conf_t *conf, r1bio_t *r1_bio)
                /* Choose the first operation device, for consistancy */
                new_disk = 0;
 
-               for (rdev = conf->mirrors[new_disk].rdev;
-                    !rdev || !rdev->in_sync
+               for (rdev = rcu_dereference(conf->mirrors[new_disk].rdev);
+                    !rdev || !test_bit(In_sync, &rdev->flags)
                             || test_bit(WriteMostly, &rdev->flags);
-                    rdev = conf->mirrors[++new_disk].rdev) {
+                    rdev = rcu_dereference(conf->mirrors[++new_disk].rdev)) {
 
-                       if (rdev && rdev->in_sync)
+                       if (rdev && test_bit(In_sync, &rdev->flags))
                                wonly_disk = new_disk;
 
                        if (new_disk == conf->raid_disks - 1) {
@@ -434,12 +449,12 @@ static int read_balance(conf_t *conf, r1bio_t *r1_bio)
 
 
        /* make sure the disk is operational */
-       for (rdev = conf->mirrors[new_disk].rdev;
-            !rdev || !rdev->in_sync ||
+       for (rdev = rcu_dereference(conf->mirrors[new_disk].rdev);
+            !rdev || !test_bit(In_sync, &rdev->flags) ||
                     test_bit(WriteMostly, &rdev->flags);
-            rdev = conf->mirrors[new_disk].rdev) {
+            rdev = rcu_dereference(conf->mirrors[new_disk].rdev)) {
 
-               if (rdev && rdev->in_sync)
+               if (rdev && test_bit(In_sync, &rdev->flags))
                        wonly_disk = new_disk;
 
                if (new_disk <= 0)
@@ -474,10 +489,10 @@ static int read_balance(conf_t *conf, r1bio_t *r1_bio)
                        disk = conf->raid_disks;
                disk--;
 
-               rdev = conf->mirrors[disk].rdev;
+               rdev = rcu_dereference(conf->mirrors[disk].rdev);
 
                if (!rdev ||
-                   !rdev->in_sync ||
+                   !test_bit(In_sync, &rdev->flags) ||
                    test_bit(WriteMostly, &rdev->flags))
                        continue;
 
@@ -496,11 +511,11 @@ static int read_balance(conf_t *conf, r1bio_t *r1_bio)
 
 
        if (new_disk >= 0) {
-               rdev = conf->mirrors[new_disk].rdev;
+               rdev = rcu_dereference(conf->mirrors[new_disk].rdev);
                if (!rdev)
                        goto retry;
                atomic_inc(&rdev->nr_pending);
-               if (!rdev->in_sync) {
+               if (!test_bit(In_sync, &rdev->flags)) {
                        /* cannot risk returning a device that failed
                         * before we inc'ed nr_pending
                         */
@@ -522,8 +537,8 @@ static void unplug_slaves(mddev_t *mddev)
 
        rcu_read_lock();
        for (i=0; i<mddev->raid_disks; i++) {
-               mdk_rdev_t *rdev = conf->mirrors[i].rdev;
-               if (rdev && !rdev->faulty && atomic_read(&rdev->nr_pending)) {
+               mdk_rdev_t *rdev = rcu_dereference(conf->mirrors[i].rdev);
+               if (rdev && !test_bit(Faulty, &rdev->flags) && atomic_read(&rdev->nr_pending)) {
                        request_queue_t *r_queue = bdev_get_queue(rdev->bdev);
 
                        atomic_inc(&rdev->nr_pending);
@@ -556,8 +571,8 @@ static int raid1_issue_flush(request_queue_t *q, struct gendisk *disk,
 
        rcu_read_lock();
        for (i=0; i<mddev->raid_disks && ret == 0; i++) {
-               mdk_rdev_t *rdev = conf->mirrors[i].rdev;
-               if (rdev && !rdev->faulty) {
+               mdk_rdev_t *rdev = rcu_dereference(conf->mirrors[i].rdev);
+               if (rdev && !test_bit(Faulty, &rdev->flags)) {
                        struct block_device *bdev = rdev->bdev;
                        request_queue_t *r_queue = bdev_get_queue(bdev);
 
@@ -648,8 +663,9 @@ static int make_request(request_queue_t *q, struct bio * bio)
        struct bio_list bl;
        struct page **behind_pages = NULL;
        const int rw = bio_data_dir(bio);
+       int do_barriers;
 
-       if (unlikely(bio_barrier(bio))) {
+       if (unlikely(!mddev->barriers_work && bio_barrier(bio))) {
                bio_endio(bio, bio->bi_size, -EOPNOTSUPP);
                return 0;
        }
@@ -728,10 +744,10 @@ static int make_request(request_queue_t *q, struct bio * bio)
 #endif
        rcu_read_lock();
        for (i = 0;  i < disks; i++) {
-               if ((rdev=conf->mirrors[i].rdev) != NULL &&
-                   !rdev->faulty) {
+               if ((rdev=rcu_dereference(conf->mirrors[i].rdev)) != NULL &&
+                   !test_bit(Faulty, &rdev->flags)) {
                        atomic_inc(&rdev->nr_pending);
-                       if (rdev->faulty) {
+                       if (test_bit(Faulty, &rdev->flags)) {
                                atomic_dec(&rdev->nr_pending);
                                r1_bio->bios[i] = NULL;
                        } else
@@ -759,6 +775,10 @@ static int make_request(request_queue_t *q, struct bio * bio)
        atomic_set(&r1_bio->remaining, 0);
        atomic_set(&r1_bio->behind_remaining, 0);
 
+       do_barriers = bio->bi_rw & BIO_RW_BARRIER;
+       if (do_barriers)
+               set_bit(R1BIO_Barrier, &r1_bio->state);
+
        bio_list_init(&bl);
        for (i = 0; i < disks; i++) {
                struct bio *mbio;
@@ -771,7 +791,7 @@ static int make_request(request_queue_t *q, struct bio * bio)
                mbio->bi_sector = r1_bio->sector + conf->mirrors[i].rdev->data_offset;
                mbio->bi_bdev = conf->mirrors[i].rdev->bdev;
                mbio->bi_end_io = raid1_end_write_request;
-               mbio->bi_rw = WRITE;
+               mbio->bi_rw = WRITE | do_barriers;
                mbio->bi_private = r1_bio;
 
                if (behind_pages) {
@@ -824,7 +844,7 @@ static void status(struct seq_file *seq, mddev_t *mddev)
        for (i = 0; i < conf->raid_disks; i++)
                seq_printf(seq, "%s",
                              conf->mirrors[i].rdev &&
-                             conf->mirrors[i].rdev->in_sync ? "U" : "_");
+                             test_bit(In_sync, &conf->mirrors[i].rdev->flags) ? "U" : "_");
        seq_printf(seq, "]");
 }
 
@@ -840,14 +860,14 @@ static void error(mddev_t *mddev, mdk_rdev_t *rdev)
         * next level up know.
         * else mark the drive as failed
         */
-       if (rdev->in_sync
+       if (test_bit(In_sync, &rdev->flags)
            && conf->working_disks == 1)
                /*
                 * Don't fail the drive, act as though we were just a
                 * normal single drive
                 */
                return;
-       if (rdev->in_sync) {
+       if (test_bit(In_sync, &rdev->flags)) {
                mddev->degraded++;
                conf->working_disks--;
                /*
@@ -855,8 +875,8 @@ static void error(mddev_t *mddev, mdk_rdev_t *rdev)
                 */
                set_bit(MD_RECOVERY_ERR, &mddev->recovery);
        }
-       rdev->in_sync = 0;
-       rdev->faulty = 1;
+       clear_bit(In_sync, &rdev->flags);
+       set_bit(Faulty, &rdev->flags);
        mddev->sb_dirty = 1;
        printk(KERN_ALERT "raid1: Disk failure on %s, disabling device. \n"
                "       Operation continuing on %d devices\n",
@@ -881,7 +901,7 @@ static void print_conf(conf_t *conf)
                tmp = conf->mirrors + i;
                if (tmp->rdev)
                        printk(" disk %d, wo:%d, o:%d, dev:%s\n",
-                               i, !tmp->rdev->in_sync, !tmp->rdev->faulty,
+                               i, !test_bit(In_sync, &tmp->rdev->flags), !test_bit(Faulty, &tmp->rdev->flags),
                                bdevname(tmp->rdev->bdev,b));
        }
 }
@@ -913,11 +933,11 @@ static int raid1_spare_active(mddev_t *mddev)
        for (i = 0; i < conf->raid_disks; i++) {
                tmp = conf->mirrors + i;
                if (tmp->rdev 
-                   && !tmp->rdev->faulty
-                   && !tmp->rdev->in_sync) {
+                   && !test_bit(Faulty, &tmp->rdev->flags)
+                   && !test_bit(In_sync, &tmp->rdev->flags)) {
                        conf->working_disks++;
                        mddev->degraded--;
-                       tmp->rdev->in_sync = 1;
+                       set_bit(In_sync, &tmp->rdev->flags);
                }
        }
 
@@ -954,7 +974,7 @@ static int raid1_add_disk(mddev_t *mddev, mdk_rdev_t *rdev)
                        found = 1;
                        if (rdev->saved_raid_disk != mirror)
                                conf->fullsync = 1;
-                       p->rdev = rdev;
+                       rcu_assign_pointer(p->rdev, rdev);
                        break;
                }
 
@@ -972,7 +992,7 @@ static int raid1_remove_disk(mddev_t *mddev, int number)
        print_conf(conf);
        rdev = p->rdev;
        if (rdev) {
-               if (rdev->in_sync ||
+               if (test_bit(In_sync, &rdev->flags) ||
                    atomic_read(&rdev->nr_pending)) {
                        err = -EBUSY;
                        goto abort;
@@ -1153,6 +1173,36 @@ static void raid1d(mddev_t *mddev)
                if (test_bit(R1BIO_IsSync, &r1_bio->state)) {
                        sync_request_write(mddev, r1_bio);
                        unplug = 1;
+               } else if (test_bit(R1BIO_BarrierRetry, &r1_bio->state)) {
+                       /* some requests in the r1bio were BIO_RW_BARRIER
+                        * requests which failed with -ENOTSUPP.  Hohumm..
+                        * Better resubmit without the barrier.
+                        * We know which devices to resubmit for, because
+                        * all others have had their bios[] entry cleared.
+                        */
+                       int i;
+                       clear_bit(R1BIO_BarrierRetry, &r1_bio->state);
+                       clear_bit(R1BIO_Barrier, &r1_bio->state);
+                       for (i=0; i < conf->raid_disks; i++)
+                               if (r1_bio->bios[i]) {
+                                       struct bio_vec *bvec;
+                                       int j;
+
+                                       bio = bio_clone(r1_bio->master_bio, GFP_NOIO);
+                                       /* copy pages from the failed bio, as
+                                        * this might be a write-behind device */
+                                       __bio_for_each_segment(bvec, bio, j, 0)
+                                               bvec->bv_page = bio_iovec_idx(r1_bio->bios[i], j)->bv_page;
+                                       bio_put(r1_bio->bios[i]);
+                                       bio->bi_sector = r1_bio->sector +
+                                               conf->mirrors[i].rdev->data_offset;
+                                       bio->bi_bdev = conf->mirrors[i].rdev->bdev;
+                                       bio->bi_end_io = raid1_end_write_request;
+                                       bio->bi_rw = WRITE;
+                                       bio->bi_private = r1_bio;
+                                       r1_bio->bios[i] = bio;
+                                       generic_make_request(bio);
+                               }
                } else {
                        int disk;
                        bio = r1_bio->bios[r1_bio->read_disk];
@@ -1260,7 +1310,7 @@ static sector_t sync_request(mddev_t *mddev, sector_t sector_nr, int *skipped, i
         * This call the bitmap_start_sync doesn't actually record anything
         */
        if (!bitmap_start_sync(mddev->bitmap, sector_nr, &sync_blocks, 1) &&
-           !conf->fullsync) {
+           !conf->fullsync && !test_bit(MD_RECOVERY_REQUESTED, &mddev->recovery)) {
                /* We can skip this block, and probably several more */
                *skipped = 1;
                return sync_blocks;
@@ -1282,11 +1332,11 @@ static sector_t sync_request(mddev_t *mddev, sector_t sector_nr, int *skipped, i
        /* make sure disk is operational */
        wonly = disk;
        while (conf->mirrors[disk].rdev == NULL ||
-              !conf->mirrors[disk].rdev->in_sync ||
+              !test_bit(In_sync, &conf->mirrors[disk].rdev->flags) ||
               test_bit(WriteMostly, &conf->mirrors[disk].rdev->flags)
                ) {
                if (conf->mirrors[disk].rdev  &&
-                   conf->mirrors[disk].rdev->in_sync)
+                   test_bit(In_sync, &conf->mirrors[disk].rdev->flags))
                        wonly = disk;
                if (disk <= 0)
                        disk = conf->raid_disks;
@@ -1333,11 +1383,12 @@ static sector_t sync_request(mddev_t *mddev, sector_t sector_nr, int *skipped, i
                        bio->bi_rw = READ;
                        bio->bi_end_io = end_sync_read;
                } else if (conf->mirrors[i].rdev == NULL ||
-                          conf->mirrors[i].rdev->faulty) {
+                          test_bit(Faulty, &conf->mirrors[i].rdev->flags)) {
                        still_degraded = 1;
                        continue;
-               } else if (!conf->mirrors[i].rdev->in_sync ||
-                          sector_nr + RESYNC_SECTORS > mddev->recovery_cp) {
+               } else if (!test_bit(In_sync, &conf->mirrors[i].rdev->flags) ||
+                          sector_nr + RESYNC_SECTORS > mddev->recovery_cp   ||
+                          test_bit(MD_RECOVERY_REQUESTED, &mddev->recovery)) {
                        bio->bi_rw = WRITE;
                        bio->bi_end_io = end_sync_write;
                        write_targets ++;
@@ -1371,8 +1422,9 @@ static sector_t sync_request(mddev_t *mddev, sector_t sector_nr, int *skipped, i
                        break;
                if (sync_blocks == 0) {
                        if (!bitmap_start_sync(mddev->bitmap, sector_nr,
-                                       &sync_blocks, still_degraded) &&
-                                       !conf->fullsync)
+                                              &sync_blocks, still_degraded) &&
+                           !conf->fullsync &&
+                           !test_bit(MD_RECOVERY_REQUESTED, &mddev->recovery))
                                break;
                        if (sync_blocks < (PAGE_SIZE>>9))
                                BUG();
@@ -1478,7 +1530,7 @@ static int run(mddev_t *mddev)
                        blk_queue_max_sectors(mddev->queue, PAGE_SIZE>>9);
 
                disk->head_position = 0;
-               if (!rdev->faulty && rdev->in_sync)
+               if (!test_bit(Faulty, &rdev->flags) && test_bit(In_sync, &rdev->flags))
                        conf->working_disks++;
        }
        conf->raid_disks = mddev->raid_disks;
@@ -1518,7 +1570,7 @@ static int run(mddev_t *mddev)
         */
        for (j = 0; j < conf->raid_disks &&
                     (!conf->mirrors[j].rdev ||
-                     !conf->mirrors[j].rdev->in_sync) ; j++)
+                     !test_bit(In_sync, &conf->mirrors[j].rdev->flags)) ; j++)
                /* nothing */;
        conf->last_used = j;
 
index bbe40e9cf9236cd843a7a17a28f92019d20b2a2c..867f06ae33d944e8ef7178d28fc3fa8905d963b3 100644 (file)
@@ -496,6 +496,7 @@ static int read_balance(conf_t *conf, r10bio_t *r10_bio)
        int disk, slot, nslot;
        const int sectors = r10_bio->sectors;
        sector_t new_distance, current_distance;
+       mdk_rdev_t *rdev;
 
        raid10_find_phys(conf, r10_bio);
        rcu_read_lock();
@@ -510,8 +511,8 @@ static int read_balance(conf_t *conf, r10bio_t *r10_bio)
                slot = 0;
                disk = r10_bio->devs[slot].devnum;
 
-               while (!conf->mirrors[disk].rdev ||
-                      !conf->mirrors[disk].rdev->in_sync) {
+               while ((rdev = rcu_dereference(conf->mirrors[disk].rdev)) == NULL ||
+                      !test_bit(In_sync, &rdev->flags)) {
                        slot++;
                        if (slot == conf->copies) {
                                slot = 0;
@@ -527,8 +528,8 @@ static int read_balance(conf_t *conf, r10bio_t *r10_bio)
        /* make sure the disk is operational */
        slot = 0;
        disk = r10_bio->devs[slot].devnum;
-       while (!conf->mirrors[disk].rdev ||
-              !conf->mirrors[disk].rdev->in_sync) {
+       while ((rdev=rcu_dereference(conf->mirrors[disk].rdev)) == NULL ||
+              !test_bit(In_sync, &rdev->flags)) {
                slot ++;
                if (slot == conf->copies) {
                        disk = -1;
@@ -547,11 +548,11 @@ static int read_balance(conf_t *conf, r10bio_t *r10_bio)
                int ndisk = r10_bio->devs[nslot].devnum;
 
 
-               if (!conf->mirrors[ndisk].rdev ||
-                   !conf->mirrors[ndisk].rdev->in_sync)
+               if ((rdev=rcu_dereference(conf->mirrors[ndisk].rdev)) == NULL ||
+                   !test_bit(In_sync, &rdev->flags))
                        continue;
 
-               if (!atomic_read(&conf->mirrors[ndisk].rdev->nr_pending)) {
+               if (!atomic_read(&rdev->nr_pending)) {
                        disk = ndisk;
                        slot = nslot;
                        break;
@@ -569,7 +570,7 @@ rb_out:
        r10_bio->read_slot = slot;
 /*     conf->next_seq_sect = this_sector + sectors;*/
 
-       if (disk >= 0 && conf->mirrors[disk].rdev)
+       if (disk >= 0 && (rdev=rcu_dereference(conf->mirrors[disk].rdev))!= NULL)
                atomic_inc(&conf->mirrors[disk].rdev->nr_pending);
        rcu_read_unlock();
 
@@ -583,8 +584,8 @@ static void unplug_slaves(mddev_t *mddev)
 
        rcu_read_lock();
        for (i=0; i<mddev->raid_disks; i++) {
-               mdk_rdev_t *rdev = conf->mirrors[i].rdev;
-               if (rdev && !rdev->faulty && atomic_read(&rdev->nr_pending)) {
+               mdk_rdev_t *rdev = rcu_dereference(conf->mirrors[i].rdev);
+               if (rdev && !test_bit(Faulty, &rdev->flags) && atomic_read(&rdev->nr_pending)) {
                        request_queue_t *r_queue = bdev_get_queue(rdev->bdev);
 
                        atomic_inc(&rdev->nr_pending);
@@ -614,8 +615,8 @@ static int raid10_issue_flush(request_queue_t *q, struct gendisk *disk,
 
        rcu_read_lock();
        for (i=0; i<mddev->raid_disks && ret == 0; i++) {
-               mdk_rdev_t *rdev = conf->mirrors[i].rdev;
-               if (rdev && !rdev->faulty) {
+               mdk_rdev_t *rdev = rcu_dereference(conf->mirrors[i].rdev);
+               if (rdev && !test_bit(Faulty, &rdev->flags)) {
                        struct block_device *bdev = rdev->bdev;
                        request_queue_t *r_queue = bdev_get_queue(bdev);
 
@@ -768,9 +769,10 @@ static int make_request(request_queue_t *q, struct bio * bio)
        rcu_read_lock();
        for (i = 0;  i < conf->copies; i++) {
                int d = r10_bio->devs[i].devnum;
-               if (conf->mirrors[d].rdev &&
-                   !conf->mirrors[d].rdev->faulty) {
-                       atomic_inc(&conf->mirrors[d].rdev->nr_pending);
+               mdk_rdev_t *rdev = rcu_dereference(conf->mirrors[d].rdev);
+               if (rdev &&
+                   !test_bit(Faulty, &rdev->flags)) {
+                       atomic_inc(&rdev->nr_pending);
                        r10_bio->devs[i].bio = bio;
                } else
                        r10_bio->devs[i].bio = NULL;
@@ -824,7 +826,7 @@ static void status(struct seq_file *seq, mddev_t *mddev)
        for (i = 0; i < conf->raid_disks; i++)
                seq_printf(seq, "%s",
                              conf->mirrors[i].rdev &&
-                             conf->mirrors[i].rdev->in_sync ? "U" : "_");
+                             test_bit(In_sync, &conf->mirrors[i].rdev->flags) ? "U" : "_");
        seq_printf(seq, "]");
 }
 
@@ -839,7 +841,7 @@ static void error(mddev_t *mddev, mdk_rdev_t *rdev)
         * next level up know.
         * else mark the drive as failed
         */
-       if (rdev->in_sync
+       if (test_bit(In_sync, &rdev->flags)
            && conf->working_disks == 1)
                /*
                 * Don't fail the drive, just return an IO error.
@@ -849,7 +851,7 @@ static void error(mddev_t *mddev, mdk_rdev_t *rdev)
                 * really dead" tests...
                 */
                return;
-       if (rdev->in_sync) {
+       if (test_bit(In_sync, &rdev->flags)) {
                mddev->degraded++;
                conf->working_disks--;
                /*
@@ -857,8 +859,8 @@ static void error(mddev_t *mddev, mdk_rdev_t *rdev)
                 */
                set_bit(MD_RECOVERY_ERR, &mddev->recovery);
        }
-       rdev->in_sync = 0;
-       rdev->faulty = 1;
+       clear_bit(In_sync, &rdev->flags);
+       set_bit(Faulty, &rdev->flags);
        mddev->sb_dirty = 1;
        printk(KERN_ALERT "raid10: Disk failure on %s, disabling device. \n"
                "       Operation continuing on %d devices\n",
@@ -883,7 +885,8 @@ static void print_conf(conf_t *conf)
                tmp = conf->mirrors + i;
                if (tmp->rdev)
                        printk(" disk %d, wo:%d, o:%d, dev:%s\n",
-                               i, !tmp->rdev->in_sync, !tmp->rdev->faulty,
+                               i, !test_bit(In_sync, &tmp->rdev->flags),
+                               !test_bit(Faulty, &tmp->rdev->flags),
                                bdevname(tmp->rdev->bdev,b));
        }
 }
@@ -936,11 +939,11 @@ static int raid10_spare_active(mddev_t *mddev)
        for (i = 0; i < conf->raid_disks; i++) {
                tmp = conf->mirrors + i;
                if (tmp->rdev
-                   && !tmp->rdev->faulty
-                   && !tmp->rdev->in_sync) {
+                   && !test_bit(Faulty, &tmp->rdev->flags)
+                   && !test_bit(In_sync, &tmp->rdev->flags)) {
                        conf->working_disks++;
                        mddev->degraded--;
-                       tmp->rdev->in_sync = 1;
+                       set_bit(In_sync, &tmp->rdev->flags);
                }
        }
 
@@ -980,7 +983,7 @@ static int raid10_add_disk(mddev_t *mddev, mdk_rdev_t *rdev)
                        p->head_position = 0;
                        rdev->raid_disk = mirror;
                        found = 1;
-                       p->rdev = rdev;
+                       rcu_assign_pointer(p->rdev, rdev);
                        break;
                }
 
@@ -998,7 +1001,7 @@ static int raid10_remove_disk(mddev_t *mddev, int number)
        print_conf(conf);
        rdev = p->rdev;
        if (rdev) {
-               if (rdev->in_sync ||
+               if (test_bit(In_sync, &rdev->flags) ||
                    atomic_read(&rdev->nr_pending)) {
                        err = -EBUSY;
                        goto abort;
@@ -1414,7 +1417,7 @@ static sector_t sync_request(mddev_t *mddev, sector_t sector_nr, int *skipped, i
 
                for (i=0 ; i<conf->raid_disks; i++)
                        if (conf->mirrors[i].rdev &&
-                           !conf->mirrors[i].rdev->in_sync) {
+                           !test_bit(In_sync, &conf->mirrors[i].rdev->flags)) {
                                /* want to reconstruct this device */
                                r10bio_t *rb2 = r10_bio;
 
@@ -1435,7 +1438,7 @@ static sector_t sync_request(mddev_t *mddev, sector_t sector_nr, int *skipped, i
                                for (j=0; j<conf->copies;j++) {
                                        int d = r10_bio->devs[j].devnum;
                                        if (conf->mirrors[d].rdev &&
-                                           conf->mirrors[d].rdev->in_sync) {
+                                           test_bit(In_sync, &conf->mirrors[d].rdev->flags)) {
                                                /* This is where we read from */
                                                bio = r10_bio->devs[0].bio;
                                                bio->bi_next = biolist;
@@ -1511,7 +1514,7 @@ static sector_t sync_request(mddev_t *mddev, sector_t sector_nr, int *skipped, i
                        bio = r10_bio->devs[i].bio;
                        bio->bi_end_io = NULL;
                        if (conf->mirrors[d].rdev == NULL ||
-                           conf->mirrors[d].rdev->faulty)
+                           test_bit(Faulty, &conf->mirrors[d].rdev->flags))
                                continue;
                        atomic_inc(&conf->mirrors[d].rdev->nr_pending);
                        atomic_inc(&r10_bio->remaining);
@@ -1697,7 +1700,7 @@ static int run(mddev_t *mddev)
                        mddev->queue->max_sectors = (PAGE_SIZE>>9);
 
                disk->head_position = 0;
-               if (!rdev->faulty && rdev->in_sync)
+               if (!test_bit(Faulty, &rdev->flags) && test_bit(In_sync, &rdev->flags))
                        conf->working_disks++;
        }
        conf->raid_disks = mddev->raid_disks;
index 1223e98ecd70f538419790c48bfe19f664561480..e2a40283e323b46335beedb18face0aad67eae00 100644 (file)
@@ -293,9 +293,31 @@ static struct stripe_head *get_active_stripe(raid5_conf_t *conf, sector_t sector
        return sh;
 }
 
-static int grow_stripes(raid5_conf_t *conf, int num)
+static int grow_one_stripe(raid5_conf_t *conf)
 {
        struct stripe_head *sh;
+       sh = kmem_cache_alloc(conf->slab_cache, GFP_KERNEL);
+       if (!sh)
+               return 0;
+       memset(sh, 0, sizeof(*sh) + (conf->raid_disks-1)*sizeof(struct r5dev));
+       sh->raid_conf = conf;
+       spin_lock_init(&sh->lock);
+
+       if (grow_buffers(sh, conf->raid_disks)) {
+               shrink_buffers(sh, conf->raid_disks);
+               kmem_cache_free(conf->slab_cache, sh);
+               return 0;
+       }
+       /* we just created an active stripe so... */
+       atomic_set(&sh->count, 1);
+       atomic_inc(&conf->active_stripes);
+       INIT_LIST_HEAD(&sh->lru);
+       release_stripe(sh);
+       return 1;
+}
+
+static int grow_stripes(raid5_conf_t *conf, int num)
+{
        kmem_cache_t *sc;
        int devs = conf->raid_disks;
 
@@ -308,48 +330,39 @@ static int grow_stripes(raid5_conf_t *conf, int num)
                return 1;
        conf->slab_cache = sc;
        while (num--) {
-               sh = kmem_cache_alloc(sc, GFP_KERNEL);
-               if (!sh)
-                       return 1;
-               memset(sh, 0, sizeof(*sh) + (devs-1)*sizeof(struct r5dev));
-               sh->raid_conf = conf;
-               spin_lock_init(&sh->lock);
-
-               if (grow_buffers(sh, conf->raid_disks)) {
-                       shrink_buffers(sh, conf->raid_disks);
-                       kmem_cache_free(sc, sh);
+               if (!grow_one_stripe(conf))
                        return 1;
-               }
-               /* we just created an active stripe so... */
-               atomic_set(&sh->count, 1);
-               atomic_inc(&conf->active_stripes);
-               INIT_LIST_HEAD(&sh->lru);
-               release_stripe(sh);
        }
        return 0;
 }
 
-static void shrink_stripes(raid5_conf_t *conf)
+static int drop_one_stripe(raid5_conf_t *conf)
 {
        struct stripe_head *sh;
 
-       while (1) {
-               spin_lock_irq(&conf->device_lock);
-               sh = get_free_stripe(conf);
-               spin_unlock_irq(&conf->device_lock);
-               if (!sh)
-                       break;
-               if (atomic_read(&sh->count))
-                       BUG();
-               shrink_buffers(sh, conf->raid_disks);
-               kmem_cache_free(conf->slab_cache, sh);
-               atomic_dec(&conf->active_stripes);
-       }
+       spin_lock_irq(&conf->device_lock);
+       sh = get_free_stripe(conf);
+       spin_unlock_irq(&conf->device_lock);
+       if (!sh)
+               return 0;
+       if (atomic_read(&sh->count))
+               BUG();
+       shrink_buffers(sh, conf->raid_disks);
+       kmem_cache_free(conf->slab_cache, sh);
+       atomic_dec(&conf->active_stripes);
+       return 1;
+}
+
+static void shrink_stripes(raid5_conf_t *conf)
+{
+       while (drop_one_stripe(conf))
+               ;
+
        kmem_cache_destroy(conf->slab_cache);
        conf->slab_cache = NULL;
 }
 
-static int raid5_end_read_request (struct bio * bi, unsigned int bytes_done,
+static int raid5_end_read_request(struct bio * bi, unsigned int bytes_done,
                                   int error)
 {
        struct stripe_head *sh = bi->bi_private;
@@ -401,10 +414,35 @@ static int raid5_end_read_request (struct bio * bi, unsigned int bytes_done,
                }
 #else
                set_bit(R5_UPTODATE, &sh->dev[i].flags);
-#endif         
+#endif
+               if (test_bit(R5_ReadError, &sh->dev[i].flags)) {
+                       printk("R5: read error corrected!!\n");
+                       clear_bit(R5_ReadError, &sh->dev[i].flags);
+                       clear_bit(R5_ReWrite, &sh->dev[i].flags);
+               }
+               if (atomic_read(&conf->disks[i].rdev->read_errors))
+                       atomic_set(&conf->disks[i].rdev->read_errors, 0);
        } else {
-               md_error(conf->mddev, conf->disks[i].rdev);
+               int retry = 0;
                clear_bit(R5_UPTODATE, &sh->dev[i].flags);
+               atomic_inc(&conf->disks[i].rdev->read_errors);
+               if (conf->mddev->degraded)
+                       printk("R5: read error not correctable.\n");
+               else if (test_bit(R5_ReWrite, &sh->dev[i].flags))
+                       /* Oh, no!!! */
+                       printk("R5: read error NOT corrected!!\n");
+               else if (atomic_read(&conf->disks[i].rdev->read_errors)
+                        > conf->max_nr_stripes)
+                       printk("raid5: Too many read errors, failing device.\n");
+               else
+                       retry = 1;
+               if (retry)
+                       set_bit(R5_ReadError, &sh->dev[i].flags);
+               else {
+                       clear_bit(R5_ReadError, &sh->dev[i].flags);
+                       clear_bit(R5_ReWrite, &sh->dev[i].flags);
+                       md_error(conf->mddev, conf->disks[i].rdev);
+               }
        }
        rdev_dec_pending(conf->disks[i].rdev, conf->mddev);
 #if 0
@@ -487,19 +525,19 @@ static void error(mddev_t *mddev, mdk_rdev_t *rdev)
        raid5_conf_t *conf = (raid5_conf_t *) mddev->private;
        PRINTK("raid5: error called\n");
 
-       if (!rdev->faulty) {
+       if (!test_bit(Faulty, &rdev->flags)) {
                mddev->sb_dirty = 1;
-               if (rdev->in_sync) {
+               if (test_bit(In_sync, &rdev->flags)) {
                        conf->working_disks--;
                        mddev->degraded++;
                        conf->failed_disks++;
-                       rdev->in_sync = 0;
+                       clear_bit(In_sync, &rdev->flags);
                        /*
                         * if recovery was running, make sure it aborts.
                         */
                        set_bit(MD_RECOVERY_ERR, &mddev->recovery);
                }
-               rdev->faulty = 1;
+               set_bit(Faulty, &rdev->flags);
                printk (KERN_ALERT
                        "raid5: Disk failure on %s, disabling device."
                        " Operation continuing on %d devices\n",
@@ -965,7 +1003,13 @@ static void handle_stripe(struct stripe_head *sh)
                }
                if (dev->written) written++;
                rdev = conf->disks[i].rdev; /* FIXME, should I be looking rdev */
-               if (!rdev || !rdev->in_sync) {
+               if (!rdev || !test_bit(In_sync, &rdev->flags)) {
+                       /* The ReadError flag wil just be confusing now */
+                       clear_bit(R5_ReadError, &dev->flags);
+                       clear_bit(R5_ReWrite, &dev->flags);
+               }
+               if (!rdev || !test_bit(In_sync, &rdev->flags)
+                   || test_bit(R5_ReadError, &dev->flags)) {
                        failed++;
                        failed_num = i;
                } else
@@ -980,6 +1024,14 @@ static void handle_stripe(struct stripe_head *sh)
        if (failed > 1 && to_read+to_write+written) {
                for (i=disks; i--; ) {
                        int bitmap_end = 0;
+
+                       if (test_bit(R5_ReadError, &sh->dev[i].flags)) {
+                               mdk_rdev_t *rdev = conf->disks[i].rdev;
+                               if (rdev && test_bit(In_sync, &rdev->flags))
+                                       /* multiple read failures in one stripe */
+                                       md_error(conf->mddev, rdev);
+                       }
+
                        spin_lock_irq(&conf->device_lock);
                        /* fail all writes first */
                        bi = sh->dev[i].towrite;
@@ -1015,7 +1067,8 @@ static void handle_stripe(struct stripe_head *sh)
                        }
 
                        /* fail any reads if this device is non-operational */
-                       if (!test_bit(R5_Insync, &sh->dev[i].flags)) {
+                       if (!test_bit(R5_Insync, &sh->dev[i].flags) ||
+                           test_bit(R5_ReadError, &sh->dev[i].flags)) {
                                bi = sh->dev[i].toread;
                                sh->dev[i].toread = NULL;
                                if (test_and_clear_bit(R5_Overlap, &sh->dev[i].flags))
@@ -1247,6 +1300,11 @@ static void handle_stripe(struct stripe_head *sh)
                            !memcmp(pagea, pagea+4, STRIPE_SIZE-4)) {
                                /* parity is correct (on disc, not in buffer any more) */
                                set_bit(STRIPE_INSYNC, &sh->state);
+                       } else {
+                               conf->mddev->resync_mismatches += STRIPE_SECTORS;
+                               if (test_bit(MD_RECOVERY_CHECK, &conf->mddev->recovery))
+                                       /* don't try to repair!! */
+                                       set_bit(STRIPE_INSYNC, &sh->state);
                        }
                }
                if (!test_bit(STRIPE_INSYNC, &sh->state)) {
@@ -1274,7 +1332,27 @@ static void handle_stripe(struct stripe_head *sh)
                md_done_sync(conf->mddev, STRIPE_SECTORS,1);
                clear_bit(STRIPE_SYNCING, &sh->state);
        }
-       
+
+       /* If the failed drive is just a ReadError, then we might need to progress
+        * the repair/check process
+        */
+       if (failed == 1 && ! conf->mddev->ro &&
+           test_bit(R5_ReadError, &sh->dev[failed_num].flags)
+           && !test_bit(R5_LOCKED, &sh->dev[failed_num].flags)
+           && test_bit(R5_UPTODATE, &sh->dev[failed_num].flags)
+               ) {
+               dev = &sh->dev[failed_num];
+               if (!test_bit(R5_ReWrite, &dev->flags)) {
+                       set_bit(R5_Wantwrite, &dev->flags);
+                       set_bit(R5_ReWrite, &dev->flags);
+                       set_bit(R5_LOCKED, &dev->flags);
+               } else {
+                       /* let's read it back */
+                       set_bit(R5_Wantread, &dev->flags);
+                       set_bit(R5_LOCKED, &dev->flags);
+               }
+       }
+
        spin_unlock(&sh->lock);
 
        while ((bi=return_bi)) {
@@ -1305,8 +1383,8 @@ static void handle_stripe(struct stripe_head *sh)
                        bi->bi_end_io = raid5_end_read_request;
  
                rcu_read_lock();
-               rdev = conf->disks[i].rdev;
-               if (rdev && rdev->faulty)
+               rdev = rcu_dereference(conf->disks[i].rdev);
+               if (rdev && test_bit(Faulty, &rdev->flags))
                        rdev = NULL;
                if (rdev)
                        atomic_inc(&rdev->nr_pending);
@@ -1379,8 +1457,8 @@ static void unplug_slaves(mddev_t *mddev)
 
        rcu_read_lock();
        for (i=0; i<mddev->raid_disks; i++) {
-               mdk_rdev_t *rdev = conf->disks[i].rdev;
-               if (rdev && !rdev->faulty && atomic_read(&rdev->nr_pending)) {
+               mdk_rdev_t *rdev = rcu_dereference(conf->disks[i].rdev);
+               if (rdev && !test_bit(Faulty, &rdev->flags) && atomic_read(&rdev->nr_pending)) {
                        request_queue_t *r_queue = bdev_get_queue(rdev->bdev);
 
                        atomic_inc(&rdev->nr_pending);
@@ -1424,8 +1502,8 @@ static int raid5_issue_flush(request_queue_t *q, struct gendisk *disk,
 
        rcu_read_lock();
        for (i=0; i<mddev->raid_disks && ret == 0; i++) {
-               mdk_rdev_t *rdev = conf->disks[i].rdev;
-               if (rdev && !rdev->faulty) {
+               mdk_rdev_t *rdev = rcu_dereference(conf->disks[i].rdev);
+               if (rdev && !test_bit(Faulty, &rdev->flags)) {
                        struct block_device *bdev = rdev->bdev;
                        request_queue_t *r_queue = bdev_get_queue(bdev);
 
@@ -1567,6 +1645,7 @@ static sector_t sync_request(mddev_t *mddev, sector_t sector_nr, int *skipped, i
                return rv;
        }
        if (!bitmap_start_sync(mddev->bitmap, sector_nr, &sync_blocks, 1) &&
+           !test_bit(MD_RECOVERY_REQUESTED, &mddev->recovery) &&
            !conf->fullsync && sync_blocks >= STRIPE_SECTORS) {
                /* we can skip this block, and probably more */
                sync_blocks /= STRIPE_SECTORS;
@@ -1663,6 +1742,74 @@ static void raid5d (mddev_t *mddev)
        PRINTK("--- raid5d inactive\n");
 }
 
+static ssize_t
+raid5_show_stripe_cache_size(mddev_t *mddev, char *page)
+{
+       raid5_conf_t *conf = mddev_to_conf(mddev);
+       if (conf)
+               return sprintf(page, "%d\n", conf->max_nr_stripes);
+       else
+               return 0;
+}
+
+static ssize_t
+raid5_store_stripe_cache_size(mddev_t *mddev, const char *page, size_t len)
+{
+       raid5_conf_t *conf = mddev_to_conf(mddev);
+       char *end;
+       int new;
+       if (len >= PAGE_SIZE)
+               return -EINVAL;
+       if (!conf)
+               return -ENODEV;
+
+       new = simple_strtoul(page, &end, 10);
+       if (!*page || (*end && *end != '\n') )
+               return -EINVAL;
+       if (new <= 16 || new > 32768)
+               return -EINVAL;
+       while (new < conf->max_nr_stripes) {
+               if (drop_one_stripe(conf))
+                       conf->max_nr_stripes--;
+               else
+                       break;
+       }
+       while (new > conf->max_nr_stripes) {
+               if (grow_one_stripe(conf))
+                       conf->max_nr_stripes++;
+               else break;
+       }
+       return len;
+}
+
+static struct md_sysfs_entry
+raid5_stripecache_size = __ATTR(stripe_cache_size, S_IRUGO | S_IWUSR,
+                               raid5_show_stripe_cache_size,
+                               raid5_store_stripe_cache_size);
+
+static ssize_t
+stripe_cache_active_show(mddev_t *mddev, char *page)
+{
+       raid5_conf_t *conf = mddev_to_conf(mddev);
+       if (conf)
+               return sprintf(page, "%d\n", atomic_read(&conf->active_stripes));
+       else
+               return 0;
+}
+
+static struct md_sysfs_entry
+raid5_stripecache_active = __ATTR_RO(stripe_cache_active);
+
+static struct attribute *raid5_attrs[] =  {
+       &raid5_stripecache_size.attr,
+       &raid5_stripecache_active.attr,
+       NULL,
+};
+static struct attribute_group raid5_attrs_group = {
+       .name = NULL,
+       .attrs = raid5_attrs,
+};
+
 static int run(mddev_t *mddev)
 {
        raid5_conf_t *conf;
@@ -1709,7 +1856,7 @@ static int run(mddev_t *mddev)
 
                disk->rdev = rdev;
 
-               if (rdev->in_sync) {
+               if (test_bit(In_sync, &rdev->flags)) {
                        char b[BDEVNAME_SIZE];
                        printk(KERN_INFO "raid5: device %s operational as raid"
                                " disk %d\n", bdevname(rdev->bdev,b),
@@ -1804,6 +1951,7 @@ memory = conf->max_nr_stripes * (sizeof(struct stripe_head) +
        }
 
        /* Ok, everything is just fine now */
+       sysfs_create_group(&mddev->kobj, &raid5_attrs_group);
 
        if (mddev->bitmap)
                mddev->thread->timeout = mddev->bitmap->daemon_sleep * HZ;
@@ -1828,7 +1976,7 @@ abort:
 
 
 
-static int stop (mddev_t *mddev)
+static int stop(mddev_t *mddev)
 {
        raid5_conf_t *conf = (raid5_conf_t *) mddev->private;
 
@@ -1837,6 +1985,7 @@ static int stop (mddev_t *mddev)
        shrink_stripes(conf);
        free_pages((unsigned long) conf->stripe_hashtbl, HASH_PAGES_ORDER);
        blk_sync_queue(mddev->queue); /* the unplug fn references 'conf'*/
+       sysfs_remove_group(&mddev->kobj, &raid5_attrs_group);
        kfree(conf);
        mddev->private = NULL;
        return 0;
@@ -1887,7 +2036,7 @@ static void status (struct seq_file *seq, mddev_t *mddev)
        for (i = 0; i < conf->raid_disks; i++)
                seq_printf (seq, "%s",
                               conf->disks[i].rdev &&
-                              conf->disks[i].rdev->in_sync ? "U" : "_");
+                              test_bit(In_sync, &conf->disks[i].rdev->flags) ? "U" : "_");
        seq_printf (seq, "]");
 #if RAID5_DEBUG
 #define D(x) \
@@ -1914,7 +2063,7 @@ static void print_raid5_conf (raid5_conf_t *conf)
                tmp = conf->disks + i;
                if (tmp->rdev)
                printk(" disk %d, o:%d, dev:%s\n",
-                       i, !tmp->rdev->faulty,
+                       i, !test_bit(Faulty, &tmp->rdev->flags),
                        bdevname(tmp->rdev->bdev,b));
        }
 }
@@ -1928,12 +2077,12 @@ static int raid5_spare_active(mddev_t *mddev)
        for (i = 0; i < conf->raid_disks; i++) {
                tmp = conf->disks + i;
                if (tmp->rdev
-                   && !tmp->rdev->faulty
-                   && !tmp->rdev->in_sync) {
+                   && !test_bit(Faulty, &tmp->rdev->flags)
+                   && !test_bit(In_sync, &tmp->rdev->flags)) {
                        mddev->degraded--;
                        conf->failed_disks--;
                        conf->working_disks++;
-                       tmp->rdev->in_sync = 1;
+                       set_bit(In_sync, &tmp->rdev->flags);
                }
        }
        print_raid5_conf(conf);
@@ -1950,7 +2099,7 @@ static int raid5_remove_disk(mddev_t *mddev, int number)
        print_raid5_conf(conf);
        rdev = p->rdev;
        if (rdev) {
-               if (rdev->in_sync ||
+               if (test_bit(In_sync, &rdev->flags) ||
                    atomic_read(&rdev->nr_pending)) {
                        err = -EBUSY;
                        goto abort;
@@ -1985,12 +2134,12 @@ static int raid5_add_disk(mddev_t *mddev, mdk_rdev_t *rdev)
         */
        for (disk=0; disk < mddev->raid_disks; disk++)
                if ((p=conf->disks + disk)->rdev == NULL) {
-                       rdev->in_sync = 0;
+                       clear_bit(In_sync, &rdev->flags);
                        rdev->raid_disk = disk;
                        found = 1;
                        if (rdev->saved_raid_disk != disk)
                                conf->fullsync = 1;
-                       p->rdev = rdev;
+                       rcu_assign_pointer(p->rdev, rdev);
                        break;
                }
        print_raid5_conf(conf);
index 7757869477019ea5a87a186b6b46ced5fcb1fcd7..eae5a35629c59101372d31518ecba9daa4e77814 100644 (file)
@@ -507,19 +507,19 @@ static void error(mddev_t *mddev, mdk_rdev_t *rdev)
        raid6_conf_t *conf = (raid6_conf_t *) mddev->private;
        PRINTK("raid6: error called\n");
 
-       if (!rdev->faulty) {
+       if (!test_bit(Faulty, &rdev->flags)) {
                mddev->sb_dirty = 1;
-               if (rdev->in_sync) {
+               if (test_bit(In_sync, &rdev->flags)) {
                        conf->working_disks--;
                        mddev->degraded++;
                        conf->failed_disks++;
-                       rdev->in_sync = 0;
+                       clear_bit(In_sync, &rdev->flags);
                        /*
                         * if recovery was running, make sure it aborts.
                         */
                        set_bit(MD_RECOVERY_ERR, &mddev->recovery);
                }
-               rdev->faulty = 1;
+               set_bit(Faulty, &rdev->flags);
                printk (KERN_ALERT
                        "raid6: Disk failure on %s, disabling device."
                        " Operation continuing on %d devices\n",
@@ -1071,7 +1071,7 @@ static void handle_stripe(struct stripe_head *sh)
                }
                if (dev->written) written++;
                rdev = conf->disks[i].rdev; /* FIXME, should I be looking rdev */
-               if (!rdev || !rdev->in_sync) {
+               if (!rdev || !test_bit(In_sync, &rdev->flags)) {
                        if ( failed < 2 )
                                failed_num[failed] = i;
                        failed++;
@@ -1464,8 +1464,8 @@ static void handle_stripe(struct stripe_head *sh)
                        bi->bi_end_io = raid6_end_read_request;
 
                rcu_read_lock();
-               rdev = conf->disks[i].rdev;
-               if (rdev && rdev->faulty)
+               rdev = rcu_dereference(conf->disks[i].rdev);
+               if (rdev && test_bit(Faulty, &rdev->flags))
                        rdev = NULL;
                if (rdev)
                        atomic_inc(&rdev->nr_pending);
@@ -1538,8 +1538,8 @@ static void unplug_slaves(mddev_t *mddev)
 
        rcu_read_lock();
        for (i=0; i<mddev->raid_disks; i++) {
-               mdk_rdev_t *rdev = conf->disks[i].rdev;
-               if (rdev && !rdev->faulty && atomic_read(&rdev->nr_pending)) {
+               mdk_rdev_t *rdev = rcu_dereference(conf->disks[i].rdev);
+               if (rdev && !test_bit(Faulty, &rdev->flags) && atomic_read(&rdev->nr_pending)) {
                        request_queue_t *r_queue = bdev_get_queue(rdev->bdev);
 
                        atomic_inc(&rdev->nr_pending);
@@ -1583,8 +1583,8 @@ static int raid6_issue_flush(request_queue_t *q, struct gendisk *disk,
 
        rcu_read_lock();
        for (i=0; i<mddev->raid_disks && ret == 0; i++) {
-               mdk_rdev_t *rdev = conf->disks[i].rdev;
-               if (rdev && !rdev->faulty) {
+               mdk_rdev_t *rdev = rcu_dereference(conf->disks[i].rdev);
+               if (rdev && !test_bit(Faulty, &rdev->flags)) {
                        struct block_device *bdev = rdev->bdev;
                        request_queue_t *r_queue = bdev_get_queue(bdev);
 
@@ -1868,7 +1868,7 @@ static int run(mddev_t *mddev)
 
                disk->rdev = rdev;
 
-               if (rdev->in_sync) {
+               if (test_bit(In_sync, &rdev->flags)) {
                        char b[BDEVNAME_SIZE];
                        printk(KERN_INFO "raid6: device %s operational as raid"
                               " disk %d\n", bdevname(rdev->bdev,b),
@@ -2052,7 +2052,7 @@ static void status (struct seq_file *seq, mddev_t *mddev)
        for (i = 0; i < conf->raid_disks; i++)
                seq_printf (seq, "%s",
                            conf->disks[i].rdev &&
-                           conf->disks[i].rdev->in_sync ? "U" : "_");
+                           test_bit(In_sync, &conf->disks[i].rdev->flags) ? "U" : "_");
        seq_printf (seq, "]");
 #if RAID6_DUMPSTATE
        seq_printf (seq, "\n");
@@ -2078,7 +2078,7 @@ static void print_raid6_conf (raid6_conf_t *conf)
                tmp = conf->disks + i;
                if (tmp->rdev)
                printk(" disk %d, o:%d, dev:%s\n",
-                       i, !tmp->rdev->faulty,
+                       i, !test_bit(Faulty, &tmp->rdev->flags),
                        bdevname(tmp->rdev->bdev,b));
        }
 }
@@ -2092,12 +2092,12 @@ static int raid6_spare_active(mddev_t *mddev)
        for (i = 0; i < conf->raid_disks; i++) {
                tmp = conf->disks + i;
                if (tmp->rdev
-                   && !tmp->rdev->faulty
-                   && !tmp->rdev->in_sync) {
+                   && !test_bit(Faulty, &tmp->rdev->flags)
+                   && !test_bit(In_sync, &tmp->rdev->flags)) {
                        mddev->degraded--;
                        conf->failed_disks--;
                        conf->working_disks++;
-                       tmp->rdev->in_sync = 1;
+                       set_bit(In_sync, &tmp->rdev->flags);
                }
        }
        print_raid6_conf(conf);
@@ -2114,7 +2114,7 @@ static int raid6_remove_disk(mddev_t *mddev, int number)
        print_raid6_conf(conf);
        rdev = p->rdev;
        if (rdev) {
-               if (rdev->in_sync ||
+               if (test_bit(In_sync, &rdev->flags) ||
                    atomic_read(&rdev->nr_pending)) {
                        err = -EBUSY;
                        goto abort;
@@ -2149,12 +2149,12 @@ static int raid6_add_disk(mddev_t *mddev, mdk_rdev_t *rdev)
         */
        for (disk=0; disk < mddev->raid_disks; disk++)
                if ((p=conf->disks + disk)->rdev == NULL) {
-                       rdev->in_sync = 0;
+                       clear_bit(In_sync, &rdev->flags);
                        rdev->raid_disk = disk;
                        found = 1;
                        if (rdev->saved_raid_disk != disk)
                                conf->fullsync = 1;
-                       p->rdev = rdev;
+                       rcu_assign_pointer(p->rdev, rdev);
                        break;
                }
        print_raid6_conf(conf);
index 31fccb4f05d6ad8ade936d8b4aec9edaf82bf019..4b71fd6f7aed15b5ecf0382fcd8e622c2176d3c7 100644 (file)
@@ -116,7 +116,7 @@ IR_KEYTAB_TYPE ir_codes_winfast[IR_KEYTAB_SIZE] = {
        [ 46 ] = KEY_BLUE,
        [ 24 ] = KEY_KPPLUS,            /* fine tune + */
        [ 25 ] = KEY_KPMINUS,           /* fine tune - */
-        [ 33 ] = KEY_KPDOT,
+       [ 33 ] = KEY_KPDOT,
        [ 19 ] = KEY_KPENTER,
        [ 34 ] = KEY_BACK,
        [ 35 ] = KEY_PLAYPAUSE,
@@ -239,7 +239,7 @@ static void ir_input_key_event(struct input_dev *dev, struct ir_input_state *ir)
        dprintk(1,"%s: key event code=%d down=%d\n",
                dev->name,ir->keycode,ir->keypressed);
        input_report_key(dev,ir->keycode,ir->keypressed);
-        input_sync(dev);
+       input_sync(dev);
 }
 
 /* -------------------------------------------------------------------------- */
index 47e28b0ee951bcee5debf4a0b8f1c56879acd6c3..a35330315f6597f4019026ca11649f0584bec1c3 100644 (file)
@@ -13,6 +13,8 @@
 #include "bcm3510.h"
 #include "stv0297.h"
 #include "mt312.h"
+#include "lgdt330x.h"
+#include "dvb-pll.h"
 
 /* lnb control */
 
@@ -234,7 +236,6 @@ static struct stv0299_config samsung_tbmu24112_config = {
        .inittab = samsung_tbmu24112_inittab,
        .mclk = 88000000UL,
        .invert = 0,
-       .enhanced_tuning = 0,
        .skip_reinit = 0,
        .lock_output = STV0229_LOCKOUTPUT_LK,
        .volt13_op0_op1 = STV0299_VOLT13_OP1,
@@ -296,6 +297,52 @@ static int flexcop_fe_request_firmware(struct dvb_frontend* fe, const struct fir
        return request_firmware(fw, name, fc->dev);
 }
 
+static int lgdt3303_pll_set(struct dvb_frontend* fe,
+                            struct dvb_frontend_parameters* params)
+{
+       struct flexcop_device *fc = fe->dvb->priv;
+       u8 buf[4];
+       struct i2c_msg msg =
+               { .addr = 0x61, .flags = 0, .buf = buf, .len = 4 };
+       int err;
+
+       dvb_pll_configure(&dvb_pll_tdvs_tua6034,buf, params->frequency, 0);
+       dprintk(1, "%s: tuner at 0x%02x bytes: 0x%02x 0x%02x 0x%02x 0x%02x\n",
+                       __FUNCTION__, msg.addr, buf[0],buf[1],buf[2],buf[3]);
+       if ((err = i2c_transfer(&fc->i2c_adap, &msg, 1)) != 1) {
+               printk(KERN_WARNING "lgdt3303: %s error "
+                          "(addr %02x <- %02x, err = %i)\n",
+                          __FUNCTION__, buf[0], buf[1], err);
+               if (err < 0)
+                       return err;
+               else
+                       return -EREMOTEIO;
+       }
+
+       buf[0] = 0x86 | 0x18;
+       buf[1] = 0x50;
+       msg.len = 2;
+       if ((err = i2c_transfer(&fc->i2c_adap, &msg, 1)) != 1) {
+               printk(KERN_WARNING "lgdt3303: %s error "
+                          "(addr %02x <- %02x, err = %i)\n",
+                          __FUNCTION__, buf[0], buf[1], err);
+               if (err < 0)
+                       return err;
+               else
+                       return -EREMOTEIO;
+       }
+
+        return 0;
+}
+
+static struct lgdt330x_config air2pc_atsc_hd5000_config = {
+       .demod_address       = 0x59,
+       .demod_chip          = LGDT3303,
+       .serial_mpeg         = 0x04,
+       .pll_set             = lgdt3303_pll_set,
+       .clock_polarity_flip = 1,
+};
+
 static struct nxt2002_config samsung_tbmv_config = {
        .demod_address    = 0x0a,
        .request_firmware = flexcop_fe_request_firmware,
@@ -458,6 +505,11 @@ int flexcop_frontend_init(struct flexcop_device *fc)
                fc->dev_type          = FC_AIR_ATSC2;
                info("found the nxt2002 at i2c address: 0x%02x",samsung_tbmv_config.demod_address);
        } else
+       /* try the air atsc 3nd generation (lgdt3303) */
+       if ((fc->fe = lgdt330x_attach(&air2pc_atsc_hd5000_config, &fc->i2c_adap)) != NULL) {
+               fc->dev_type          = FC_AIR_ATSC3;
+               info("found the lgdt3303 at i2c address: 0x%02x",air2pc_atsc_hd5000_config.demod_address);
+       } else
        /* try the air atsc 1nd generation (bcm3510)/panasonic ct10s */
        if ((fc->fe = bcm3510_attach(&air2pc_atsc_first_gen_config, &fc->i2c_adap)) != NULL) {
                fc->dev_type          = FC_AIR_ATSC1;
index 3a08d38b318a94b8007840cf004df498ac8f7af2..62282d8dbfa82e80048c4838df05dfa44124a7dd 100644 (file)
@@ -51,6 +51,7 @@ const char *flexcop_device_names[] = {
        "Sky2PC/SkyStar 2 DVB-S",
        "Sky2PC/SkyStar 2 DVB-S (old version)",
        "Cable2PC/CableStar 2 DVB-C",
+       "Air2PC/AirStar 2 ATSC 3rd generation (HD5000)",
 };
 
 const char *flexcop_bus_names[] = {
index 4ae1eb5bfe98002a7826ac4f5ad0676a6e190474..23cc6431e2b819fc70ae92ea51b93af856ebd64c 100644 (file)
@@ -26,6 +26,7 @@ typedef enum {
        FC_SKY,
        FC_SKY_OLD,
        FC_CABLE,
+       FC_AIR_ATSC3,
 } flexcop_device_type_t;
 
 typedef enum {
index 12873d435406cb67023f8d43ac8c65859919cec0..123ed96f6faa54d4851c6e3c3171735dc9a01bd7 100644 (file)
@@ -193,6 +193,7 @@ static void flexcop_reset(struct flexcop_device *fc)
        v204 = fc->read_ibi_reg(fc,misc_204);
        v204.misc_204.Per_reset_sig = 0;
        fc->write_ibi_reg(fc,misc_204,v204);
+       msleep(1);
        v204.misc_204.Per_reset_sig = 1;
        fc->write_ibi_reg(fc,misc_204,v204);
 }
index 1e85d16491b02acb426d9f6a48f5439fc38c603c..2337b41714e062d4b1531ce037ec775091c561f2 100644 (file)
@@ -6,10 +6,12 @@ config DVB_BT8XX
        select DVB_NXT6000
        select DVB_CX24110
        select DVB_OR51211
+       select DVB_LGDT330X
        help
          Support for PCI cards based on the Bt8xx PCI bridge. Examples are
          the Nebula cards, the Pinnacle PCTV cards, the Twinhan DST cards,
-         the pcHDTV HD2000 cards, and certain AVerMedia cards.
+         the pcHDTV HD2000 cards, the DViCO FusionHDTV Lite cards, and
+         some AVerMedia cards.
 
          Since these cards have no MPEG decoder onboard, they transmit
          only compressed MPEG data over the PCI bus, so you need
index b3c9d7327ac1d4228a2eecc810bf6e98df75d172..8977c7a313df5aadb4bf66ab0722b6f0e1a69aa8 100644 (file)
@@ -690,8 +690,8 @@ struct dst_types dst_tlist[] = {
                .device_id = "DTT-CI",
                .offset = 1,
                .dst_type = DST_TYPE_IS_TERR,
-               .type_flags = DST_TYPE_HAS_TS204 | DST_TYPE_HAS_FW_2,
-               .dst_feature = 0
+               .type_flags = DST_TYPE_HAS_TS204 | DST_TYPE_HAS_NEWTUNE | DST_TYPE_HAS_FW_2 | DST_TYPE_HAS_MULTI_FE,
+               .dst_feature = DST_TYPE_HAS_CA
        },
 
        {
@@ -796,6 +796,56 @@ static int dst_get_vendor(struct dst_state *state)
        return 0;
 }
 
+static int dst_get_tuner_info(struct dst_state *state)
+{
+       u8 get_tuner_1[] = { 0x00, 0x13, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
+       u8 get_tuner_2[] = { 0x00, 0x0b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
+
+       get_tuner_1[7] = dst_check_sum(get_tuner_1, 7);
+       get_tuner_2[7] = dst_check_sum(get_tuner_2, 7);
+       if (state->type_flags & DST_TYPE_HAS_MULTI_FE) {
+               if (dst_command(state, get_tuner_2, 8) < 0) {
+                       dprintk(verbose, DST_INFO, 1, "Unsupported Command");
+                       return -1;
+               }
+       } else {
+               if (dst_command(state, get_tuner_1, 8) < 0) {
+                       dprintk(verbose, DST_INFO, 1, "Unsupported Command");
+                       return -1;
+               }
+       }
+       memset(&state->board_info, '\0', 8);
+       memcpy(&state->board_info, &state->rxbuffer, 8);
+       if (state->type_flags & DST_TYPE_HAS_MULTI_FE) {
+               if (state->board_info[1] == 0x0b) {
+                       if (state->type_flags & DST_TYPE_HAS_TS204)
+                               state->type_flags &= ~DST_TYPE_HAS_TS204;
+                       state->type_flags |= DST_TYPE_HAS_NEWTUNE;
+                       dprintk(verbose, DST_INFO, 1, "DST type has TS=188");
+               } else {
+                       if (state->type_flags & DST_TYPE_HAS_NEWTUNE)
+                               state->type_flags &= ~DST_TYPE_HAS_NEWTUNE;
+                       state->type_flags |= DST_TYPE_HAS_TS204;
+                       dprintk(verbose, DST_INFO, 1, "DST type has TS=204");
+               }
+       } else {
+               if (state->board_info[0] == 0xbc) {
+                       if (state->type_flags & DST_TYPE_HAS_TS204)
+                               state->type_flags &= ~DST_TYPE_HAS_TS204;
+                       state->type_flags |= DST_TYPE_HAS_NEWTUNE;
+                       dprintk(verbose, DST_INFO, 1, "DST type has TS=188, Daughterboard=[%d]", state->board_info[1]);
+
+               } else if (state->board_info[0] == 0xcc) {
+                       if (state->type_flags & DST_TYPE_HAS_NEWTUNE)
+                               state->type_flags &= ~DST_TYPE_HAS_NEWTUNE;
+                       state->type_flags |= DST_TYPE_HAS_TS204;
+                       dprintk(verbose, DST_INFO, 1, "DST type has TS=204 Daughterboard=[%d]", state->board_info[1]);
+               }
+       }
+
+       return 0;
+}
+
 static int dst_get_device_id(struct dst_state *state)
 {
        u8 reply;
@@ -855,15 +905,12 @@ static int dst_get_device_id(struct dst_state *state)
        state->dst_type = use_dst_type;
        dst_type_flags_print(state->type_flags);
 
-       if (state->type_flags & DST_TYPE_HAS_TS204) {
-               dst_packsize(state, 204);
-       }
-
        return 0;
 }
 
 static int dst_probe(struct dst_state *state)
 {
+       sema_init(&state->dst_mutex, 1);
        if ((rdc_8820_reset(state)) < 0) {
                dprintk(verbose, DST_ERROR, 1, "RDC 8820 RESET Failed.");
                return -1;
@@ -886,6 +933,13 @@ static int dst_probe(struct dst_state *state)
                dprintk(verbose, DST_INFO, 1, "MAC: Unsupported command");
                return 0;
        }
+       if ((state->type_flags & DST_TYPE_HAS_MULTI_FE) || (state->type_flags & DST_TYPE_HAS_FW_BUILD)) {
+               if (dst_get_tuner_info(state) < 0)
+                       dprintk(verbose, DST_INFO, 1, "Tuner: Unsupported command");
+       }
+       if (state->type_flags & DST_TYPE_HAS_TS204) {
+               dst_packsize(state, 204);
+       }
        if (state->type_flags & DST_TYPE_HAS_FW_BUILD) {
                if (dst_fw_ver(state) < 0) {
                        dprintk(verbose, DST_INFO, 1, "FW: Unsupported command");
@@ -907,21 +961,23 @@ static int dst_probe(struct dst_state *state)
 int dst_command(struct dst_state *state, u8 *data, u8 len)
 {
        u8 reply;
+
+       down(&state->dst_mutex);
        if ((dst_comm_init(state)) < 0) {
                dprintk(verbose, DST_NOTICE, 1, "DST Communication Initialization Failed.");
-               return -1;
+               goto error;
        }
        if (write_dst(state, data, len)) {
                dprintk(verbose, DST_INFO, 1, "Tring to recover.. ");
                if ((dst_error_recovery(state)) < 0) {
                        dprintk(verbose, DST_ERROR, 1, "Recovery Failed.");
-                       return -1;
+                       goto error;
                }
-               return -1;
+               goto error;
        }
        if ((dst_pio_disable(state)) < 0) {
                dprintk(verbose, DST_ERROR, 1, "PIO Disable Failed.");
-               return -1;
+               goto error;
        }
        if (state->type_flags & DST_TYPE_HAS_FW_1)
                udelay(3000);
@@ -929,36 +985,41 @@ int dst_command(struct dst_state *state, u8 *data, u8 len)
                dprintk(verbose, DST_DEBUG, 1, "Trying to recover.. ");
                if ((dst_error_recovery(state)) < 0) {
                        dprintk(verbose, DST_INFO, 1, "Recovery Failed.");
-                       return -1;
+                       goto error;
                }
-               return -1;
+               goto error;
        }
        if (reply != ACK) {
                dprintk(verbose, DST_INFO, 1, "write not acknowledged 0x%02x ", reply);
-               return -1;
+               goto error;
        }
        if (len >= 2 && data[0] == 0 && (data[1] == 1 || data[1] == 3))
-               return 0;
+               goto error;
        if (state->type_flags & DST_TYPE_HAS_FW_1)
                udelay(3000);
        else
                udelay(2000);
        if (!dst_wait_dst_ready(state, NO_DELAY))
-               return -1;
+               goto error;
        if (read_dst(state, state->rxbuffer, FIXED_COMM)) {
                dprintk(verbose, DST_DEBUG, 1, "Trying to recover.. ");
                if ((dst_error_recovery(state)) < 0) {
                        dprintk(verbose, DST_INFO, 1, "Recovery failed.");
-                       return -1;
+                       goto error;
                }
-               return -1;
+               goto error;
        }
        if (state->rxbuffer[7] != dst_check_sum(state->rxbuffer, 7)) {
                dprintk(verbose, DST_INFO, 1, "checksum failure");
-               return -1;
+               goto error;
        }
-
+       up(&state->dst_mutex);
        return 0;
+
+error:
+       up(&state->dst_mutex);
+       return -EIO;
+
 }
 EXPORT_SYMBOL(dst_command);
 
@@ -1016,7 +1077,7 @@ static int dst_get_tuna(struct dst_state *state)
                return 0;
        state->diseq_flags &= ~(HAS_LOCK);
        if (!dst_wait_dst_ready(state, NO_DELAY))
-               return 0;
+               return -EIO;
        if (state->type_flags & DST_TYPE_HAS_NEWTUNE)
                /* how to get variable length reply ???? */
                retval = read_dst(state, state->rx_tuna, 10);
@@ -1024,22 +1085,27 @@ static int dst_get_tuna(struct dst_state *state)
                retval = read_dst(state, &state->rx_tuna[2], FIXED_COMM);
        if (retval < 0) {
                dprintk(verbose, DST_DEBUG, 1, "read not successful");
-               return 0;
+               return retval;
        }
        if (state->type_flags & DST_TYPE_HAS_NEWTUNE) {
                if (state->rx_tuna[9] != dst_check_sum(&state->rx_tuna[0], 9)) {
                        dprintk(verbose, DST_INFO, 1, "checksum failure ? ");
-                       return 0;
+                       return -EIO;
                }
        } else {
                if (state->rx_tuna[9] != dst_check_sum(&state->rx_tuna[2], 7)) {
                        dprintk(verbose, DST_INFO, 1, "checksum failure? ");
-                       return 0;
+                       return -EIO;
                }
        }
        if (state->rx_tuna[2] == 0 && state->rx_tuna[3] == 0)
                return 0;
-       state->decode_freq = ((state->rx_tuna[2] & 0x7f) << 8) + state->rx_tuna[3];
+       if (state->dst_type == DST_TYPE_IS_SAT) {
+               state->decode_freq = ((state->rx_tuna[2] & 0x7f) << 8) + state->rx_tuna[3];
+       } else {
+               state->decode_freq = ((state->rx_tuna[2] & 0x7f) << 16) + (state->rx_tuna[3] << 8) + state->rx_tuna[4];
+       }
+       state->decode_freq = state->decode_freq * 1000;
        state->decode_lock = 1;
        state->diseq_flags |= HAS_LOCK;
 
@@ -1062,10 +1128,10 @@ static int dst_write_tuna(struct dvb_frontend *fe)
                        dst_set_voltage(fe, SEC_VOLTAGE_13);
        }
        state->diseq_flags &= ~(HAS_LOCK | ATTEMPT_TUNE);
-
+       down(&state->dst_mutex);
        if ((dst_comm_init(state)) < 0) {
                dprintk(verbose, DST_DEBUG, 1, "DST Communication initialization failed.");
-               return -1;
+               goto error;
        }
        if (state->type_flags & DST_TYPE_HAS_NEWTUNE) {
                state->tx_tuna[9] = dst_check_sum(&state->tx_tuna[0], 9);
@@ -1077,23 +1143,29 @@ static int dst_write_tuna(struct dvb_frontend *fe)
        if (retval < 0) {
                dst_pio_disable(state);
                dprintk(verbose, DST_DEBUG, 1, "write not successful");
-               return retval;
+               goto werr;
        }
        if ((dst_pio_disable(state)) < 0) {
                dprintk(verbose, DST_DEBUG, 1, "DST PIO disable failed !");
-               return -1;
+               goto error;
        }
        if ((read_dst(state, &reply, GET_ACK) < 0)) {
                dprintk(verbose, DST_DEBUG, 1, "read verify not successful.");
-               return -1;
+               goto error;
        }
        if (reply != ACK) {
                dprintk(verbose, DST_DEBUG, 1, "write not acknowledged 0x%02x ", reply);
-               return 0;
+               goto error;
        }
        state->diseq_flags |= ATTEMPT_TUNE;
-
-       return dst_get_tuna(state);
+       retval = dst_get_tuna(state);
+werr:
+       up(&state->dst_mutex);
+       return retval;
+
+error:
+       up(&state->dst_mutex);
+       return -EIO;
 }
 
 /*
index 6776a592045f36d7468d18baedffc32b5740bfeb..e6541aff39968597f67d390ab453e846bcc07d35 100644 (file)
@@ -69,62 +69,53 @@ static int ca_set_pid(void)
 }
 
 
-static int put_checksum(u8 *check_string, int length)
+static void put_checksum(u8 *check_string, int length)
 {
-       u8 i = 0, checksum = 0;
-
-       dprintk(verbose, DST_CA_DEBUG, 1, " ========================= Checksum calculation ===========================");
-       dprintk(verbose, DST_CA_DEBUG, 1, " String Length=[0x%02x]", length);
-       dprintk(verbose, DST_CA_DEBUG, 1, " String=[");
-
-       while (i < length) {
-               dprintk(verbose, DST_CA_DEBUG, 0, " %02x", check_string[i]);
-               checksum += check_string[i];
-               i++;
-       }
-       dprintk(verbose, DST_CA_DEBUG, 0, " ]\n");
-       dprintk(verbose, DST_CA_DEBUG, 1, "Sum=[%02x]\n", checksum);
-       check_string[length] = ~checksum + 1;
-       dprintk(verbose, DST_CA_DEBUG, 1, " Checksum=[%02x]", check_string[length]);
-       dprintk(verbose, DST_CA_DEBUG, 1, " ==========================================================================");
-
-       return 0;
+       dprintk(verbose, DST_CA_DEBUG, 1, " Computing string checksum.");
+       dprintk(verbose, DST_CA_DEBUG, 1, "  -> string length : 0x%02x", length);
+       check_string[length] = dst_check_sum (check_string, length);
+       dprintk(verbose, DST_CA_DEBUG, 1, "  -> checksum      : 0x%02x", check_string[length]);
 }
 
 static int dst_ci_command(struct dst_state* state, u8 * data, u8 *ca_string, u8 len, int read)
 {
        u8 reply;
 
+       down(&state->dst_mutex);
        dst_comm_init(state);
        msleep(65);
 
        if (write_dst(state, data, len)) {
                dprintk(verbose, DST_CA_INFO, 1, " Write not successful, trying to recover");
                dst_error_recovery(state);
-               return -1;
+               goto error;
        }
        if ((dst_pio_disable(state)) < 0) {
                dprintk(verbose, DST_CA_ERROR, 1, " DST PIO disable failed.");
-               return -1;
+               goto error;
        }
        if (read_dst(state, &reply, GET_ACK) < 0) {
                dprintk(verbose, DST_CA_INFO, 1, " Read not successful, trying to recover");
                dst_error_recovery(state);
-               return -1;
+               goto error;
        }
        if (read) {
                if (! dst_wait_dst_ready(state, LONG_DELAY)) {
                        dprintk(verbose, DST_CA_NOTICE, 1, " 8820 not ready");
-                       return -1;
+                       goto error;
                }
                if (read_dst(state, ca_string, 128) < 0) {      /*      Try to make this dynamic        */
                        dprintk(verbose, DST_CA_INFO, 1, " Read not successful, trying to recover");
                        dst_error_recovery(state);
-                       return -1;
+                       goto error;
                }
        }
-
+       up(&state->dst_mutex);
        return 0;
+
+error:
+       up(&state->dst_mutex);
+       return -EIO;
 }
 
 
@@ -166,7 +157,7 @@ static int ca_get_app_info(struct dst_state *state)
        return 0;
 }
 
-static int ca_get_slot_caps(struct dst_state *state, struct ca_caps *p_ca_caps, void *arg)
+static int ca_get_slot_caps(struct dst_state *state, struct ca_caps *p_ca_caps, void __user *arg)
 {
        int i;
        u8 slot_cap[256];
@@ -192,25 +183,25 @@ static int ca_get_slot_caps(struct dst_state *state, struct ca_caps *p_ca_caps,
        p_ca_caps->descr_num = slot_cap[7];
        p_ca_caps->descr_type = 1;
 
-       if (copy_to_user((struct ca_caps *)arg, p_ca_caps, sizeof (struct ca_caps)))
+       if (copy_to_user(arg, p_ca_caps, sizeof (struct ca_caps)))
                return -EFAULT;
 
        return 0;
 }
 
 /*     Need some more work     */
-static int ca_get_slot_descr(struct dst_state *state, struct ca_msg *p_ca_message, void *arg)
+static int ca_get_slot_descr(struct dst_state *state, struct ca_msg *p_ca_message, void __user *arg)
 {
        return -EOPNOTSUPP;
 }
 
 
-static int ca_get_slot_info(struct dst_state *state, struct ca_slot_info *p_ca_slot_info, void *arg)
+static int ca_get_slot_info(struct dst_state *state, struct ca_slot_info *p_ca_slot_info, void __user *arg)
 {
        int i;
        static u8 slot_command[8] = {0x00, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff};
 
-       u8 *slot_info = state->rxbuffer;
+       u8 *slot_info = state->messages;
 
        put_checksum(&slot_command[0], 7);
        if ((dst_put_ci(state, slot_command, sizeof (slot_command), slot_info, GET_REPLY)) < 0) {
@@ -238,19 +229,19 @@ static int ca_get_slot_info(struct dst_state *state, struct ca_slot_info *p_ca_s
        } else
                p_ca_slot_info->flags = 0;
 
-       if (copy_to_user((struct ca_slot_info *)arg, p_ca_slot_info, sizeof (struct ca_slot_info)))
+       if (copy_to_user(arg, p_ca_slot_info, sizeof (struct ca_slot_info)))
                return -EFAULT;
 
        return 0;
 }
 
 
-static int ca_get_message(struct dst_state *state, struct ca_msg *p_ca_message, void *arg)
+static int ca_get_message(struct dst_state *state, struct ca_msg *p_ca_message, void __user *arg)
 {
        u8 i = 0;
        u32 command = 0;
 
-       if (copy_from_user(p_ca_message, (void *)arg, sizeof (struct ca_msg)))
+       if (copy_from_user(p_ca_message, arg, sizeof (struct ca_msg)))
                return -EFAULT;
 
        if (p_ca_message->msg) {
@@ -266,7 +257,7 @@ static int ca_get_message(struct dst_state *state, struct ca_msg *p_ca_message,
                switch (command) {
                case CA_APP_INFO:
                        memcpy(p_ca_message->msg, state->messages, 128);
-                       if (copy_to_user((void *)arg, p_ca_message, sizeof (struct ca_msg)) )
+                       if (copy_to_user(arg, p_ca_message, sizeof (struct ca_msg)) )
                                return -EFAULT;
                        break;
                }
@@ -315,7 +306,7 @@ static int write_to_8820(struct dst_state *state, struct ca_msg *hw_buffer, u8 l
        return 0;
 }
 
-u32 asn_1_decode(u8 *asn_1_array)
+static u32 asn_1_decode(u8 *asn_1_array)
 {
        u8 length_field = 0, word_count = 0, count = 0;
        u32 length = 0;
@@ -328,7 +319,8 @@ u32 asn_1_decode(u8 *asn_1_array)
        } else {
                word_count = length_field & 0x7f;
                for (count = 0; count < word_count; count++) {
-                       length = (length | asn_1_array[count + 1]) << 8;
+                       length = length  << 8;
+                       length += asn_1_array[count + 1];
                        dprintk(verbose, DST_CA_DEBUG, 1, " Length=[%04x]", length);
                }
        }
@@ -399,13 +391,14 @@ static int dst_check_ca_pmt(struct dst_state *state, struct ca_msg *p_ca_message
        return 0;
 }
 
-static int ca_send_message(struct dst_state *state, struct ca_msg *p_ca_message, void *arg)
+static int ca_send_message(struct dst_state *state, struct ca_msg *p_ca_message, void __user *arg)
 {
        int i = 0;
        unsigned int ca_message_header_len;
 
        u32 command = 0;
        struct ca_msg *hw_buffer;
+       int result = 0;
 
        if ((hw_buffer = (struct ca_msg *) kmalloc(sizeof (struct ca_msg), GFP_KERNEL)) == NULL) {
                dprintk(verbose, DST_CA_ERROR, 1, " Memory allocation failure");
@@ -413,8 +406,11 @@ static int ca_send_message(struct dst_state *state, struct ca_msg *p_ca_message,
        }
        dprintk(verbose, DST_CA_DEBUG, 1, " ");
 
-       if (copy_from_user(p_ca_message, (void *)arg, sizeof (struct ca_msg)))
-               return -EFAULT;
+       if (copy_from_user(p_ca_message, (void *)arg, sizeof (struct ca_msg))) {
+               result = -EFAULT;
+               goto free_mem_and_exit;
+       }
+
 
        if (p_ca_message->msg) {
                ca_message_header_len = p_ca_message->length;   /*      Restore it back when you are done       */
@@ -433,7 +429,8 @@ static int ca_send_message(struct dst_state *state, struct ca_msg *p_ca_message,
                        dprintk(verbose, DST_CA_DEBUG, 1, "Command = SEND_CA_PMT");
                        if ((ca_set_pmt(state, p_ca_message, hw_buffer, 0, 0)) < 0) {   // code simplification started
                                dprintk(verbose, DST_CA_ERROR, 1, " -->CA_PMT Failed !");
-                               return -1;
+                               result = -1;
+                               goto free_mem_and_exit;
                        }
                        dprintk(verbose, DST_CA_INFO, 1, " -->CA_PMT Success !");
                        break;
@@ -442,7 +439,8 @@ static int ca_send_message(struct dst_state *state, struct ca_msg *p_ca_message,
                        /*      Have to handle the 2 basic types of cards here  */
                        if ((dst_check_ca_pmt(state, p_ca_message, hw_buffer)) < 0) {
                                dprintk(verbose, DST_CA_ERROR, 1, " -->CA_PMT_REPLY Failed !");
-                               return -1;
+                               result = -1;
+                               goto free_mem_and_exit;
                        }
                        dprintk(verbose, DST_CA_INFO, 1, " -->CA_PMT_REPLY Success !");
                        break;
@@ -451,22 +449,28 @@ static int ca_send_message(struct dst_state *state, struct ca_msg *p_ca_message,
 
                        if ((ca_get_app_info(state)) < 0) {
                                dprintk(verbose, DST_CA_ERROR, 1, " -->CA_APP_INFO_ENQUIRY Failed !");
-                               return -1;
+                               result = -1;
+                               goto free_mem_and_exit;
                        }
                        dprintk(verbose, DST_CA_INFO, 1, " -->CA_APP_INFO_ENQUIRY Success !");
                        break;
                }
        }
-       return 0;
+free_mem_and_exit:
+       kfree (hw_buffer);
+
+       return result;
 }
 
-static int dst_ca_ioctl(struct inode *inode, struct file *file, unsigned int cmd, void *arg)
+static int dst_ca_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long ioctl_arg)
 {
        struct dvb_device* dvbdev = (struct dvb_device*) file->private_data;
        struct dst_state* state = (struct dst_state*) dvbdev->priv;
        struct ca_slot_info *p_ca_slot_info;
        struct ca_caps *p_ca_caps;
        struct ca_msg *p_ca_message;
+       void __user *arg = (void __user *)ioctl_arg;
+       int result = 0;
 
        if ((p_ca_message = (struct ca_msg *) kmalloc(sizeof (struct ca_msg), GFP_KERNEL)) == NULL) {
                dprintk(verbose, DST_CA_ERROR, 1, " Memory allocation failure");
@@ -486,14 +490,16 @@ static int dst_ca_ioctl(struct inode *inode, struct file *file, unsigned int cmd
                dprintk(verbose, DST_CA_INFO, 1, " Sending message");
                if ((ca_send_message(state, p_ca_message, arg)) < 0) {
                        dprintk(verbose, DST_CA_ERROR, 1, " -->CA_SEND_MSG Failed !");
-                       return -1;
+                       result = -1;
+                       goto free_mem_and_exit;
                }
                break;
        case CA_GET_MSG:
                dprintk(verbose, DST_CA_INFO, 1, " Getting message");
                if ((ca_get_message(state, p_ca_message, arg)) < 0) {
                        dprintk(verbose, DST_CA_ERROR, 1, " -->CA_GET_MSG Failed !");
-                       return -1;
+                       result = -1;
+                       goto free_mem_and_exit;
                }
                dprintk(verbose, DST_CA_INFO, 1, " -->CA_GET_MSG Success !");
                break;
@@ -506,7 +512,8 @@ static int dst_ca_ioctl(struct inode *inode, struct file *file, unsigned int cmd
                dprintk(verbose, DST_CA_INFO, 1, " Getting Slot info");
                if ((ca_get_slot_info(state, p_ca_slot_info, arg)) < 0) {
                        dprintk(verbose, DST_CA_ERROR, 1, " -->CA_GET_SLOT_INFO Failed !");
-                       return -1;
+                       result = -1;
+                       goto free_mem_and_exit;
                }
                dprintk(verbose, DST_CA_INFO, 1, " -->CA_GET_SLOT_INFO Success !");
                break;
@@ -514,7 +521,8 @@ static int dst_ca_ioctl(struct inode *inode, struct file *file, unsigned int cmd
                dprintk(verbose, DST_CA_INFO, 1, " Getting Slot capabilities");
                if ((ca_get_slot_caps(state, p_ca_caps, arg)) < 0) {
                        dprintk(verbose, DST_CA_ERROR, 1, " -->CA_GET_CAP Failed !");
-                       return -1;
+                       result = -1;
+                       goto free_mem_and_exit;
                }
                dprintk(verbose, DST_CA_INFO, 1, " -->CA_GET_CAP Success !");
                break;
@@ -522,7 +530,8 @@ static int dst_ca_ioctl(struct inode *inode, struct file *file, unsigned int cmd
                dprintk(verbose, DST_CA_INFO, 1, " Getting descrambler description");
                if ((ca_get_slot_descr(state, p_ca_message, arg)) < 0) {
                        dprintk(verbose, DST_CA_ERROR, 1, " -->CA_GET_DESCR_INFO Failed !");
-                       return -1;
+                       result = -1;
+                       goto free_mem_and_exit;
                }
                dprintk(verbose, DST_CA_INFO, 1, " -->CA_GET_DESCR_INFO Success !");
                break;
@@ -530,7 +539,8 @@ static int dst_ca_ioctl(struct inode *inode, struct file *file, unsigned int cmd
                dprintk(verbose, DST_CA_INFO, 1, " Setting descrambler");
                if ((ca_set_slot_descr()) < 0) {
                        dprintk(verbose, DST_CA_ERROR, 1, " -->CA_SET_DESCR Failed !");
-                       return -1;
+                       result = -1;
+                       goto free_mem_and_exit;
                }
                dprintk(verbose, DST_CA_INFO, 1, " -->CA_SET_DESCR Success !");
                break;
@@ -538,14 +548,19 @@ static int dst_ca_ioctl(struct inode *inode, struct file *file, unsigned int cmd
                dprintk(verbose, DST_CA_INFO, 1, " Setting PID");
                if ((ca_set_pid()) < 0) {
                        dprintk(verbose, DST_CA_ERROR, 1, " -->CA_SET_PID Failed !");
-                       return -1;
+                       result = -1;
+                       goto free_mem_and_exit;
                }
                dprintk(verbose, DST_CA_INFO, 1, " -->CA_SET_PID Success !");
        default:
-               return -EOPNOTSUPP;
+               result = -EOPNOTSUPP;
        };
+ free_mem_and_exit:
+       kfree (p_ca_message);
+       kfree (p_ca_slot_info);
+       kfree (p_ca_caps);
 
-       return 0;
+       return result;
 }
 
 static int dst_ca_open(struct inode *inode, struct file *file)
@@ -582,7 +597,7 @@ static int dst_ca_write(struct file *file, const char __user *buffer, size_t len
 
 static struct file_operations dst_ca_fops = {
        .owner = THIS_MODULE,
-       .ioctl = (void *)dst_ca_ioctl,
+       .ioctl = dst_ca_ioctl,
        .open = dst_ca_open,
        .release = dst_ca_release,
        .read = dst_ca_read,
index 3281a6ca3685d46ea19ec12d9e88133ca228c6f8..81557f38fe3826aa0cfdc44ba0ac96f19de2eac6 100644 (file)
@@ -22,6 +22,7 @@
 #ifndef DST_COMMON_H
 #define DST_COMMON_H
 
+#include <linux/smp_lock.h>
 #include <linux/dvb/frontend.h>
 #include <linux/device.h>
 #include "bt878.h"
@@ -49,6 +50,7 @@
 #define DST_TYPE_HAS_FW_BUILD  64
 #define DST_TYPE_HAS_OBS_REGS  128
 #define DST_TYPE_HAS_INC_COUNT 256
+#define DST_TYPE_HAS_MULTI_FE  512
 
 /*     Card capability list    */
 
@@ -117,6 +119,9 @@ struct dst_state {
        u8 fw_version[8];
        u8 card_info[8];
        u8 vendor[8];
+       u8 board_info[8];
+
+       struct semaphore dst_mutex;
 };
 
 struct dst_types {
index c5c7672cd53819f9a3ab1fa391dcf039b73f9301..2e398090cf63e1e70d3af43aee7b9079862aa760 100644 (file)
@@ -34,6 +34,7 @@
 #include "dvb_frontend.h"
 #include "dvb-bt8xx.h"
 #include "bt878.h"
+#include "dvb-pll.h"
 
 static int debug;
 
@@ -279,7 +280,7 @@ static int microtune_mt7202dtf_pll_set(struct dvb_frontend* fe, struct dvb_front
        data[0] = (div >> 8) & 0x7f;
        data[1] = div & 0xff;
        data[2] = ((div >> 10) & 0x60) | cfg;
-       data[3] = cpump | band_select;
+       data[3] = (cpump << 6) | band_select;
 
        i2c_transfer(card->i2c_adapter, &msg, 1);
        return (div * 166666 - 36000000);
@@ -522,9 +523,7 @@ static void digitv_alps_tded4_reset(struct dvb_bt8xx_card *bt)
        /*
         * Reset the frontend, must be called before trying
         * to initialise the MT352 or mt352_attach
-        * will fail.
-        *
-        * Presumably not required for the NXT6000 frontend.
+        * will fail. Same goes for the nxt6000 frontend.
         *
         */
 
@@ -546,14 +545,63 @@ static struct mt352_config digitv_alps_tded4_config = {
        .pll_set = digitv_alps_tded4_pll_set,
 };
 
+static int tdvs_tua6034_pll_set(struct dvb_frontend* fe, struct dvb_frontend_parameters* params)
+{
+       struct dvb_bt8xx_card *card = (struct dvb_bt8xx_card *) fe->dvb->priv;
+       u8 buf[4];
+       struct i2c_msg msg = { .addr = 0x61, .flags = 0, .buf = buf, .len = sizeof(buf) };
+       int err;
+
+       dvb_pll_configure(&dvb_pll_tdvs_tua6034, buf, params->frequency, 0);
+       dprintk("%s: tuner at 0x%02x bytes: 0x%02x 0x%02x 0x%02x 0x%02x\n",
+               __FUNCTION__, msg.addr, buf[0],buf[1],buf[2],buf[3]);
+       if ((err = i2c_transfer(card->i2c_adapter, &msg, 1)) != 1) {
+               printk(KERN_WARNING "dvb-bt8xx: %s error "
+                       "(addr %02x <- %02x, err = %i)\n",
+                       __FUNCTION__, buf[0], buf[1], err);
+               if (err < 0)
+                       return err;
+               else
+                       return -EREMOTEIO;
+       }
+
+       /* Set the Auxiliary Byte. */
+       buf[2] &= ~0x20;
+       buf[2] |= 0x18;
+       buf[3] = 0x50;
+       i2c_transfer(card->i2c_adapter, &msg, 1);
+
+       return 0;
+}
+
+static struct lgdt330x_config tdvs_tua6034_config = {
+       .demod_address    = 0x0e,
+       .demod_chip       = LGDT3303,
+       .serial_mpeg      = 0x40, /* TPSERIAL for 3303 in TOP_CONTROL */
+       .pll_set          = tdvs_tua6034_pll_set,
+};
+
+static void lgdt330x_reset(struct dvb_bt8xx_card *bt)
+{
+       /* Set pin 27 of the lgdt3303 chip high to reset the frontend */
+
+       /* Pulse the reset line */
+       bttv_write_gpio(bt->bttv_nr, 0x00e00007, 0x00000001); /* High */
+       bttv_write_gpio(bt->bttv_nr, 0x00e00007, 0x00000000); /* Low  */
+       msleep(100);
+
+       bttv_write_gpio(bt->bttv_nr, 0x00e00007, 0x00000001); /* High */
+       msleep(100);
+}
+
 static void frontend_init(struct dvb_bt8xx_card *card, u32 type)
 {
        int ret;
        struct dst_state* state = NULL;
 
        switch(type) {
-#ifdef BTTV_DVICO_DVBT_LITE
-       case BTTV_DVICO_DVBT_LITE:
+#ifdef BTTV_BOARD_DVICO_DVBT_LITE
+       case BTTV_BOARD_DVICO_DVBT_LITE:
                card->fe = mt352_attach(&thomson_dtt7579_config, card->i2c_adapter);
                if (card->fe != NULL) {
                        card->fe->ops->info.frequency_min = 174000000;
@@ -562,10 +610,19 @@ static void frontend_init(struct dvb_bt8xx_card *card, u32 type)
                break;
 #endif
 
-#ifdef BTTV_TWINHAN_VP3021
-       case BTTV_TWINHAN_VP3021:
+#ifdef BTTV_BOARD_DVICO_FUSIONHDTV_5_LITE
+       case BTTV_BOARD_DVICO_FUSIONHDTV_5_LITE:
+               lgdt330x_reset(card);
+               card->fe = lgdt330x_attach(&tdvs_tua6034_config, card->i2c_adapter);
+               if (card->fe != NULL)
+                       dprintk ("dvb_bt8xx: lgdt330x detected\n");
+               break;
+#endif
+
+#ifdef BTTV_BOARD_TWINHAN_VP3021
+       case BTTV_BOARD_TWINHAN_VP3021:
 #else
-       case BTTV_NEBULA_DIGITV:
+       case BTTV_BOARD_NEBULA_DIGITV:
 #endif
                /*
                 * It is possible to determine the correct frontend using the I2C bus (see the Nebula SDK);
@@ -573,6 +630,7 @@ static void frontend_init(struct dvb_bt8xx_card *card, u32 type)
                 */
 
                /* Old Nebula (marked (c)2003 on high profile pci card) has nxt6000 demod */
+               digitv_alps_tded4_reset(card);
                card->fe = nxt6000_attach(&vp3021_alps_tded4_config, card->i2c_adapter);
                if (card->fe != NULL) {
                        dprintk ("dvb_bt8xx: an nxt6000 was detected on your digitv card\n");
@@ -587,11 +645,11 @@ static void frontend_init(struct dvb_bt8xx_card *card, u32 type)
                        dprintk ("dvb_bt8xx: an mt352 was detected on your digitv card\n");
                break;
 
-       case BTTV_AVDVBT_761:
+       case BTTV_BOARD_AVDVBT_761:
                card->fe = sp887x_attach(&microtune_mt7202dtf_config, card->i2c_adapter);
                break;
 
-       case BTTV_AVDVBT_771:
+       case BTTV_BOARD_AVDVBT_771:
                card->fe = mt352_attach(&advbt771_samsung_tdtc9251dh0_config, card->i2c_adapter);
                if (card->fe != NULL) {
                        card->fe->ops->info.frequency_min = 174000000;
@@ -599,7 +657,7 @@ static void frontend_init(struct dvb_bt8xx_card *card, u32 type)
                }
                break;
 
-       case BTTV_TWINHAN_DST:
+       case BTTV_BOARD_TWINHAN_DST:
                /*      DST is not a frontend driver !!!                */
                state = (struct dst_state *) kmalloc(sizeof (struct dst_state), GFP_KERNEL);
                /*      Setup the Card                                  */
@@ -620,11 +678,11 @@ static void frontend_init(struct dvb_bt8xx_card *card, u32 type)
                        ret = dst_ca_attach(state, &card->dvb_adapter);
                break;
 
-       case BTTV_PINNACLESAT:
+       case BTTV_BOARD_PINNACLESAT:
                card->fe = cx24110_attach(&pctvsat_config, card->i2c_adapter);
                break;
 
-       case BTTV_PC_HDTV:
+       case BTTV_BOARD_PC_HDTV:
                card->fe = or51211_attach(&or51211_config, card->i2c_adapter);
                break;
        }
@@ -746,7 +804,7 @@ static int dvb_bt8xx_probe(struct device *dev)
        card->i2c_adapter = &sub->core->i2c_adap;
 
        switch(sub->core->type) {
-       case BTTV_PINNACLESAT:
+       case BTTV_BOARD_PINNACLESAT:
                card->gpio_mode = 0x0400c060;
                /* should be: BT878_A_GAIN=0,BT878_A_PWRDN,BT878_DA_DPM,BT878_DA_SBR,
                              BT878_DA_IOM=1,BT878_DA_APP to enable serial highspeed mode. */
@@ -754,8 +812,8 @@ static int dvb_bt8xx_probe(struct device *dev)
                card->irq_err_ignore = 0;
                break;
 
-#ifdef BTTV_DVICO_DVBT_LITE
-       case BTTV_DVICO_DVBT_LITE:
+#ifdef BTTV_BOARD_DVICO_DVBT_LITE
+       case BTTV_BOARD_DVICO_DVBT_LITE:
 #endif
                card->gpio_mode = 0x0400C060;
                card->op_sync_orin = 0;
@@ -765,26 +823,34 @@ static int dvb_bt8xx_probe(struct device *dev)
                 * DA_APP(parallel) */
                break;
 
-#ifdef BTTV_TWINHAN_VP3021
-       case BTTV_TWINHAN_VP3021:
+#ifdef BTTV_BOARD_DVICO_FUSIONHDTV_5_LITE
+       case BTTV_BOARD_DVICO_FUSIONHDTV_5_LITE:
+#endif
+               card->gpio_mode = 0x0400c060;
+               card->op_sync_orin = BT878_RISC_SYNC_MASK;
+               card->irq_err_ignore = BT878_AFBUS | BT878_AFDSR;
+               break;
+
+#ifdef BTTV_BOARD_TWINHAN_VP3021
+       case BTTV_BOARD_TWINHAN_VP3021:
 #else
-       case BTTV_NEBULA_DIGITV:
+       case BTTV_BOARD_NEBULA_DIGITV:
 #endif
-       case BTTV_AVDVBT_761:
+       case BTTV_BOARD_AVDVBT_761:
                card->gpio_mode = (1 << 26) | (1 << 14) | (1 << 5);
                card->op_sync_orin = 0;
                card->irq_err_ignore = 0;
                /* A_PWRDN DA_SBR DA_APP (high speed serial) */
                break;
 
-       case BTTV_AVDVBT_771: //case 0x07711461:
+       case BTTV_BOARD_AVDVBT_771: //case 0x07711461:
                card->gpio_mode = 0x0400402B;
                card->op_sync_orin = BT878_RISC_SYNC_MASK;
                card->irq_err_ignore = 0;
                /* A_PWRDN DA_SBR  DA_APP[0] PKTP=10 RISC_ENABLE FIFO_ENABLE*/
                break;
 
-       case BTTV_TWINHAN_DST:
+       case BTTV_BOARD_TWINHAN_DST:
                card->gpio_mode = 0x2204f2c;
                card->op_sync_orin = BT878_RISC_SYNC_MASK;
                card->irq_err_ignore = BT878_APABORT | BT878_ARIPERR |
@@ -802,7 +868,7 @@ static int dvb_bt8xx_probe(struct device *dev)
                 * RISC+FIFO ENABLE */
                break;
 
-       case BTTV_PC_HDTV:
+       case BTTV_BOARD_PC_HDTV:
                card->gpio_mode = 0x0100EC7B;
                card->op_sync_orin = 0;
                card->irq_err_ignore = 0;
index 9ec8e5bd6c1fae8e60bc3c5eab60cbf61bb80b0b..cf035a80361ccb9cb596b62dc075a493beeb7065 100644 (file)
@@ -35,6 +35,7 @@
 #include "nxt6000.h"
 #include "cx24110.h"
 #include "or51211.h"
+#include "lgdt330x.h"
 
 struct dvb_bt8xx_card {
        struct semaphore lock;
index 9719a3b30f786fee49c23a075f7a900fd32b3737..7d7b0067f2281740f4e3393687744742ccbb948b 100644 (file)
  * DMX_MAX_SECFEED_SIZE: Maximum length (in bytes) of a private section feed filter.
  */
 
+#ifndef DMX_MAX_SECTION_SIZE
+#define DMX_MAX_SECTION_SIZE 4096
+#endif
 #ifndef DMX_MAX_SECFEED_SIZE
-#define DMX_MAX_SECFEED_SIZE 4096
+#define DMX_MAX_SECFEED_SIZE (DMX_MAX_SECTION_SIZE + 188)
 #endif
 
 
index dc476dda2b713242ab4185dab5889c7a80fab416..b4c899b15959c62d016388926b00ea2f83624670 100644 (file)
@@ -246,7 +246,7 @@ static int dvb_dmx_swfilter_section_copy_dump(struct dvb_demux_feed *feed,
 
        for (n = 0; sec->secbufp + 2 < limit; n++) {
                seclen = section_length(sec->secbuf);
-               if (seclen <= 0 || seclen > DMX_MAX_SECFEED_SIZE
+               if (seclen <= 0 || seclen > DMX_MAX_SECTION_SIZE
                    || seclen + sec->secbufp > limit)
                        return 0;
                sec->seclen = seclen;
index a8bc84240b50a8ea5b78338bd56df515d4cc77bd..6ffa6b2163631117661d16c7a7f540d79b3ee8b6 100644 (file)
@@ -42,8 +42,6 @@
 #include "dvb_frontend.h"
 #include "dvbdev.h"
 
-// #define DEBUG_LOCKLOSS 1
-
 static int dvb_frontend_debug;
 static int dvb_shutdown_timeout = 5;
 static int dvb_force_auto_inversion;
@@ -438,25 +436,6 @@ static int dvb_frontend_thread(void *data)
                        if (s & FE_HAS_LOCK)
                                continue;
                        else { /* if we _WERE_ tuned, but now don't have a lock */
-#ifdef DEBUG_LOCKLOSS
-                               /* first of all try setting the tone again if it was on - this
-                                * sometimes works around problems with noisy power supplies */
-                               if (fe->ops->set_tone && (fepriv->tone == SEC_TONE_ON)) {
-                                       fe->ops->set_tone(fe, fepriv->tone);
-                                       mdelay(100);
-                                       s = 0;
-                                       fe->ops->read_status(fe, &s);
-                                       if (s & FE_HAS_LOCK) {
-                                               printk("DVB%i: Lock was lost, but regained by setting "
-                                                      "the tone. This may indicate your power supply "
-                                                      "is noisy/slightly incompatable with this DVB-S "
-                                                      "adapter\n", fe->dvb->num);
-                                               fepriv->state = FESTATE_TUNED;
-                                               continue;
-                                       }
-                               }
-#endif
-                               /* some other reason for losing the lock - start zigzagging */
                                fepriv->state = FESTATE_ZIGZAG_FAST;
                                fepriv->started_auto_step = fepriv->auto_step;
                                check_wrapped = 0;
@@ -577,6 +556,49 @@ static void dvb_frontend_stop(struct dvb_frontend *fe)
                                fepriv->thread_pid);
 }
 
+s32 timeval_usec_diff(struct timeval lasttime, struct timeval curtime)
+{
+       return ((curtime.tv_usec < lasttime.tv_usec) ?
+               1000000 - lasttime.tv_usec + curtime.tv_usec :
+               curtime.tv_usec - lasttime.tv_usec);
+}
+EXPORT_SYMBOL(timeval_usec_diff);
+
+static inline void timeval_usec_add(struct timeval *curtime, u32 add_usec)
+{
+       curtime->tv_usec += add_usec;
+       if (curtime->tv_usec >= 1000000) {
+               curtime->tv_usec -= 1000000;
+               curtime->tv_sec++;
+       }
+}
+
+/*
+ * Sleep until gettimeofday() > waketime + add_usec
+ * This needs to be as precise as possible, but as the delay is
+ * usually between 2ms and 32ms, it is done using a scheduled msleep
+ * followed by usleep (normally a busy-wait loop) for the remainder
+ */
+void dvb_frontend_sleep_until(struct timeval *waketime, u32 add_usec)
+{
+       struct timeval lasttime;
+       s32 delta, newdelta;
+
+       timeval_usec_add(waketime, add_usec);
+
+       do_gettimeofday(&lasttime);
+       delta = timeval_usec_diff(lasttime, *waketime);
+       if (delta > 2500) {
+               msleep((delta - 1500) / 1000);
+               do_gettimeofday(&lasttime);
+               newdelta = timeval_usec_diff(lasttime, *waketime);
+               delta = (newdelta > delta) ? 0 : newdelta;
+       }
+       if (delta > 0)
+               udelay(delta);
+}
+EXPORT_SYMBOL(dvb_frontend_sleep_until);
+
 static int dvb_frontend_start(struct dvb_frontend *fe)
 {
        int ret;
@@ -728,6 +750,60 @@ static int dvb_frontend_ioctl(struct inode *inode, struct file *file,
                        err = fe->ops->dishnetwork_send_legacy_command(fe, (unsigned int) parg);
                        fepriv->state = FESTATE_DISEQC;
                        fepriv->status = 0;
+               } else if (fe->ops->set_voltage) {
+                       /*
+                        * NOTE: This is a fallback condition.  Some frontends
+                        * (stv0299 for instance) take longer than 8msec to
+                        * respond to a set_voltage command.  Those switches
+                        * need custom routines to switch properly.  For all
+                        * other frontends, the following shoule work ok.
+                        * Dish network legacy switches (as used by Dish500)
+                        * are controlled by sending 9-bit command words
+                        * spaced 8msec apart.
+                        * the actual command word is switch/port dependant
+                        * so it is up to the userspace application to send
+                        * the right command.
+                        * The command must always start with a '0' after
+                        * initialization, so parg is 8 bits and does not
+                        * include the initialization or start bit
+                        */
+                       unsigned int cmd = ((unsigned int) parg) << 1;
+                       struct timeval nexttime;
+                       struct timeval tv[10];
+                       int i;
+                       u8 last = 1;
+                       if (dvb_frontend_debug)
+                               printk("%s switch command: 0x%04x\n", __FUNCTION__, cmd);
+                       do_gettimeofday(&nexttime);
+                       if (dvb_frontend_debug)
+                               memcpy(&tv[0], &nexttime, sizeof(struct timeval));
+                       /* before sending a command, initialize by sending
+                        * a 32ms 18V to the switch
+                        */
+                       fe->ops->set_voltage(fe, SEC_VOLTAGE_18);
+                       dvb_frontend_sleep_until(&nexttime, 32000);
+
+                       for (i = 0; i < 9; i++) {
+                               if (dvb_frontend_debug)
+                                       do_gettimeofday(&tv[i + 1]);
+                               if ((cmd & 0x01) != last) {
+                                       /* set voltage to (last ? 13V : 18V) */
+                                       fe->ops->set_voltage(fe, (last) ? SEC_VOLTAGE_13 : SEC_VOLTAGE_18);
+                                       last = (last) ? 0 : 1;
+                               }
+                               cmd = cmd >> 1;
+                               if (i != 8)
+                                       dvb_frontend_sleep_until(&nexttime, 8000);
+                       }
+                       if (dvb_frontend_debug) {
+                               printk("%s(%d): switch delay (should be 32k followed by all 8k\n",
+                                       __FUNCTION__, fe->dvb->num);
+                               for (i = 1; i < 10; i++)
+                                       printk("%d: %d\n", i, timeval_usec_diff(tv[i-1] , tv[i]));
+                       }
+                       err = 0;
+                       fepriv->state = FESTATE_DISEQC;
+                       fepriv->status = 0;
                }
                break;
 
index 9c2c1d1136bd158ead80b9e7d902fbd84573127e..348c9b0b988aeab22245fd58ae369ae91b88fdaf 100644 (file)
@@ -101,4 +101,7 @@ extern int dvb_register_frontend(struct dvb_adapter* dvb,
 
 extern int dvb_unregister_frontend(struct dvb_frontend* fe);
 
+extern void dvb_frontend_sleep_until(struct timeval *waketime, u32 add_usec);
+extern s32 timeval_usec_diff(struct timeval lasttime, struct timeval curtime);
+
 #endif
index e55322ef76b393280d39ed542a959bc71debdb0f..49f541d9a042bd6448c77dfff3bfc11a627dabd5 100644 (file)
@@ -43,11 +43,9 @@ static struct dvb_usb_rc_key a800_rc_keys[] = {
        { 0x02, 0x13, KEY_RIGHT },       /* R / CH RTN */
        { 0x02, 0x17, KEY_PROG2 },       /* SNAP SHOT */
        { 0x02, 0x10, KEY_PROG3 },       /* 16-CH PREV */
-       { 0x02, 0x03, KEY_CHANNELUP },   /* CH UP */
        { 0x02, 0x1e, KEY_VOLUMEDOWN },  /* VOL DOWN */
        { 0x02, 0x0c, KEY_ZOOM },        /* FULL SCREEN */
        { 0x02, 0x1f, KEY_VOLUMEUP },    /* VOL UP */
-       { 0x02, 0x02, KEY_CHANNELDOWN }, /* CH DOWN */
        { 0x02, 0x14, KEY_MUTE },        /* MUTE */
        { 0x02, 0x08, KEY_AUDIO },       /* AUDIO */
        { 0x02, 0x19, KEY_RECORD },      /* RECORD */
@@ -57,8 +55,6 @@ static struct dvb_usb_rc_key a800_rc_keys[] = {
        { 0x02, 0x1d, KEY_BACK },        /* << / RED */
        { 0x02, 0x1c, KEY_FORWARD },     /* >> / YELLOW */
        { 0x02, 0x03, KEY_TEXT },        /* TELETEXT */
-       { 0x02, 0x01, KEY_FIRST },       /* |<< / GREEN */
-       { 0x02, 0x00, KEY_LAST },        /* >>| / BLUE */
        { 0x02, 0x04, KEY_EPG },         /* EPG */
        { 0x02, 0x15, KEY_MENU },        /* MENU */
 
index 0058505634a0be54a8209dea0fcf01945abba2ad..aa271a2496d5faaa27cc25c172a4682d6443b099 100644 (file)
@@ -82,13 +82,15 @@ static int dibusb_tuner_probe_and_attach(struct dvb_usb_device *d)
 static struct dvb_usb_properties dibusb1_1_properties;
 static struct dvb_usb_properties dibusb1_1_an2235_properties;
 static struct dvb_usb_properties dibusb2_0b_properties;
+static struct dvb_usb_properties artec_t1_usb2_properties;
 
 static int dibusb_probe(struct usb_interface *intf,
                const struct usb_device_id *id)
 {
        if (dvb_usb_device_init(intf,&dibusb1_1_properties,THIS_MODULE,NULL) == 0 ||
                dvb_usb_device_init(intf,&dibusb1_1_an2235_properties,THIS_MODULE,NULL) == 0 ||
-               dvb_usb_device_init(intf,&dibusb2_0b_properties,THIS_MODULE,NULL) == 0)
+               dvb_usb_device_init(intf,&dibusb2_0b_properties,THIS_MODULE,NULL) == 0 ||
+               dvb_usb_device_init(intf,&artec_t1_usb2_properties,THIS_MODULE,NULL) == 0)
                return 0;
 
        return -EINVAL;
@@ -128,10 +130,13 @@ static struct usb_device_id dibusb_dib3000mb_table [] = {
 
 /* 27 */       { USB_DEVICE(USB_VID_KWORLD,            USB_PID_KWORLD_VSTREAM_COLD) },
 
+/* 28 */       { USB_DEVICE(USB_VID_ULTIMA_ELECTRONIC,         USB_PID_ULTIMA_TVBOX_USB2_COLD) },
+/* 29 */       { USB_DEVICE(USB_VID_ULTIMA_ELECTRONIC,         USB_PID_ULTIMA_TVBOX_USB2_WARM) },
+
 // #define DVB_USB_DIBUSB_MB_FAULTY_USB_IDs
 
 #ifdef DVB_USB_DIBUSB_MB_FAULTY_USB_IDs
-/* 28 */       { USB_DEVICE(USB_VID_ANCHOR,            USB_PID_ULTIMA_TVBOX_ANCHOR_COLD) },
+/* 30 */       { USB_DEVICE(USB_VID_ANCHOR,            USB_PID_ULTIMA_TVBOX_ANCHOR_COLD) },
 #endif
                        { }             /* Terminating entry */
 };
@@ -264,7 +269,7 @@ static struct dvb_usb_properties dibusb1_1_an2235_properties = {
                },
 #ifdef DVB_USB_DIBUSB_MB_FAULTY_USB_IDs
                {       "Artec T1 USB1.1 TVBOX with AN2235 (faulty USB IDs)",
-                       { &dibusb_dib3000mb_table[28], NULL },
+                       { &dibusb_dib3000mb_table[30], NULL },
                        { NULL },
                },
 #endif
@@ -273,7 +278,7 @@ static struct dvb_usb_properties dibusb1_1_an2235_properties = {
 
 static struct dvb_usb_properties dibusb2_0b_properties = {
        .caps = DVB_USB_HAS_PID_FILTER | DVB_USB_PID_FILTER_CAN_BE_TURNED_OFF | DVB_USB_IS_AN_I2C_ADAPTER,
-       .pid_filter_count = 32,
+       .pid_filter_count = 16,
 
        .usb_ctrl = CYPRESS_FX2,
 
@@ -321,6 +326,52 @@ static struct dvb_usb_properties dibusb2_0b_properties = {
        }
 };
 
+static struct dvb_usb_properties artec_t1_usb2_properties = {
+       .caps = DVB_USB_HAS_PID_FILTER | DVB_USB_PID_FILTER_CAN_BE_TURNED_OFF | DVB_USB_IS_AN_I2C_ADAPTER,
+       .pid_filter_count = 16,
+
+       .usb_ctrl = CYPRESS_FX2,
+
+       .firmware = "dvb-usb-dibusb-6.0.0.8.fw",
+
+       .size_of_priv     = sizeof(struct dibusb_state),
+
+       .streaming_ctrl   = dibusb2_0_streaming_ctrl,
+       .pid_filter       = dibusb_pid_filter,
+       .pid_filter_ctrl  = dibusb_pid_filter_ctrl,
+       .power_ctrl       = dibusb2_0_power_ctrl,
+       .frontend_attach  = dibusb_dib3000mb_frontend_attach,
+       .tuner_attach     = dibusb_tuner_probe_and_attach,
+
+       .rc_interval      = DEFAULT_RC_INTERVAL,
+       .rc_key_map       = dibusb_rc_keys,
+       .rc_key_map_size  = 63, /* wow, that is ugly ... I want to load it to the driver dynamically */
+       .rc_query         = dibusb_rc_query,
+
+       .i2c_algo         = &dibusb_i2c_algo,
+
+       .generic_bulk_ctrl_endpoint = 0x01,
+       /* parameter for the MPEG2-data transfer */
+       .urb = {
+               .type = DVB_USB_BULK,
+               .count = 7,
+               .endpoint = 0x06,
+               .u = {
+                       .bulk = {
+                               .buffersize = 4096,
+                       }
+               }
+       },
+
+       .num_device_descs = 1,
+       .devices = {
+               {       "Artec T1 USB2.0",
+                       { &dibusb_dib3000mb_table[28], NULL },
+                       { &dibusb_dib3000mb_table[29], NULL },
+               },
+       }
+};
+
 static struct usb_driver dibusb_driver = {
        .owner          = THIS_MODULE,
        .name           = "dvb_usb_dibusb_mb",
index 6611f62977c055ce7f316c3aa4df828c2dd6f5fe..2d99d05c7eab3c9f7dde14fa17db918d5e56233e 100644 (file)
@@ -11,7 +11,9 @@
 #ifndef _DVB_USB_DIBUSB_H_
 #define _DVB_USB_DIBUSB_H_
 
-#define DVB_USB_LOG_PREFIX "dibusb"
+#ifndef DVB_USB_LOG_PREFIX
+ #define DVB_USB_LOG_PREFIX "dibusb"
+#endif
 #include "dvb-usb.h"
 
 #include "dib3000.h"
index 0818996bf1507cc032fb5e9e76ec11f72fda5d93..6be99e537e12904bf4475c6e3bc3f837ad80627d 100644 (file)
 #define USB_PID_COMPRO_DVBU2000_WARM           0xd001
 #define USB_PID_COMPRO_DVBU2000_UNK_COLD       0x010c
 #define USB_PID_COMPRO_DVBU2000_UNK_WARM       0x010d
+#define USB_PID_DIBCOM_HOOK_DEFAULT                    0x0064
+#define USB_PID_DIBCOM_HOOK_DEFAULT_REENUM     0x0065
 #define USB_PID_DIBCOM_MOD3000_COLD                    0x0bb8
 #define USB_PID_DIBCOM_MOD3000_WARM                    0x0bb9
 #define USB_PID_DIBCOM_MOD3001_COLD                    0x0bc6
 #define USB_PID_DIBCOM_MOD3001_WARM                    0x0bc7
+#define USB_PID_DIBCOM_STK7700                         0x1e14
+#define USB_PID_DIBCOM_STK7700_REENUM          0x1e15
 #define USB_PID_DIBCOM_ANCHOR_2135_COLD                0x2131
 #define USB_PID_GRANDTEC_DVBT_USB_COLD         0x0fa0
 #define USB_PID_GRANDTEC_DVBT_USB_WARM         0x0fa1
@@ -68,6 +72,7 @@
 #define USB_PID_ULTIMA_TVBOX_AN2235_WARM       0x8108
 #define USB_PID_ULTIMA_TVBOX_ANCHOR_COLD       0x2235
 #define USB_PID_ULTIMA_TVBOX_USB2_COLD         0x8109
+#define USB_PID_ULTIMA_TVBOX_USB2_WARM         0x810a
 #define USB_PID_ULTIMA_TVBOX_USB2_FX_COLD      0x8613
 #define USB_PID_ULTIMA_TVBOX_USB2_FX_WARM      0x1002
 #define USB_PID_UNK_HYPER_PALTEK_COLD          0x005e
index f5799a4c228e9610aa11151e97505f5430820e96..36b7048c02d26616a5f18794f0a7116cb5309f1c 100644 (file)
@@ -196,7 +196,9 @@ static int dvb_usb_allocate_stream_buffers(struct dvb_usb_device *d, int num, un
                        dvb_usb_free_stream_buffers(d);
                        return -ENOMEM;
                }
-               deb_mem("buffer %d: %p (dma: %d)\n",d->buf_num,d->buf_list[d->buf_num],d->dma_addr[d->buf_num]);
+               deb_mem("buffer %d: %p (dma: %llu)\n",
+                       d->buf_num, d->buf_list[d->buf_num],
+                       (unsigned long long)d->dma_addr[d->buf_num]);
                memset(d->buf_list[d->buf_num],0,size);
        }
        deb_mem("allocation successful\n");
index a50a41f6f79d4db95e92efb5844c577b82066b29..8e269e1c1f9dfb68e2ecae64e1a6b656da267741 100644 (file)
@@ -164,6 +164,14 @@ config DVB_NXT2002
        help
          An ATSC 8VSB tuner module. Say Y when you want to support this frontend.
 
+config DVB_NXT200X
+       tristate "Nextwave NXT2002/NXT2004 based"
+       depends on DVB_CORE
+       select FW_LOADER
+       help
+         An ATSC 8VSB and QAM64/256 tuner module. Say Y when you want
+         to support this frontend.
+
 config DVB_OR51211
        tristate "or51211 based (pcHDTV HD2000 card)"
        depends on DVB_CORE
index ad8658ffd60a8f318f1c324699e96e8bf0ce5958..a98760fe08a18a7c60d4f4e661dfe0fce514dfb3 100644 (file)
@@ -26,6 +26,7 @@ obj-$(CONFIG_DVB_TDA80XX) += tda80xx.o
 obj-$(CONFIG_DVB_TDA10021) += tda10021.o
 obj-$(CONFIG_DVB_STV0297) += stv0297.o
 obj-$(CONFIG_DVB_NXT2002) += nxt2002.o
+obj-$(CONFIG_DVB_NXT200X) += nxt200x.o
 obj-$(CONFIG_DVB_OR51211) += or51211.o
 obj-$(CONFIG_DVB_OR51132) += or51132.o
 obj-$(CONFIG_DVB_BCM3510) += bcm3510.o
index 536c35d969b7dca1c19a2d1bc3052f1cf8c241d4..f857b869616c305cff9cf1b66135eaa303eb6841 100644 (file)
@@ -226,7 +226,7 @@ struct dvb_pll_desc dvb_pll_tua6034 = {
 EXPORT_SYMBOL(dvb_pll_tua6034);
 
 /* Infineon TUA6034
- * used in LG Innotek TDVS-H062F
+ * used in LG TDVS H061F and LG TDVS H062F
  */
 struct dvb_pll_desc dvb_pll_tdvs_tua6034 = {
        .name  = "LG/Infineon TUA6034",
@@ -292,6 +292,58 @@ struct dvb_pll_desc dvb_pll_tded4 = {
 };
 EXPORT_SYMBOL(dvb_pll_tded4);
 
+/* ALPS TDHU2
+ * used in AverTVHD MCE A180
+ */
+struct dvb_pll_desc dvb_pll_tdhu2 = {
+       .name = "ALPS TDHU2",
+       .min = 54000000,
+       .max = 864000000,
+       .count = 4,
+       .entries = {
+               { 162000000, 44000000, 62500, 0x85, 0x01 },
+               { 426000000, 44000000, 62500, 0x85, 0x02 },
+               { 782000000, 44000000, 62500, 0x85, 0x08 },
+               { 999999999, 44000000, 62500, 0x85, 0x88 },
+       }
+};
+EXPORT_SYMBOL(dvb_pll_tdhu2);
+
+/* Philips TUV1236D
+ * used in ATI HDTV Wonder
+ */
+struct dvb_pll_desc dvb_pll_tuv1236d = {
+       .name  = "Philips TUV1236D",
+       .min   =  54000000,
+       .max   = 864000000,
+       .count = 3,
+       .entries = {
+               { 157250000, 44000000, 62500, 0xc6, 0x41 },
+               { 454000000, 44000000, 62500, 0xc6, 0x42 },
+               { 999999999, 44000000, 62500, 0xc6, 0x44 },
+       },
+};
+EXPORT_SYMBOL(dvb_pll_tuv1236d);
+
+/* Samsung TBMV30111IN
+ * used in Air2PC ATSC - 2nd generation (nxt2002)
+ */
+struct dvb_pll_desc dvb_pll_tbmv30111in = {
+       .name = "Samsung TBMV30111IN",
+       .min = 54000000,
+       .max = 860000000,
+       .count = 4,
+       .entries = {
+               { 172000000, 44000000, 166666, 0xb4, 0x01 },
+               { 214000000, 44000000, 166666, 0xb4, 0x02 },
+               { 467000000, 44000000, 166666, 0xbc, 0x02 },
+               { 721000000, 44000000, 166666, 0xbc, 0x08 },
+               { 841000000, 44000000, 166666, 0xf4, 0x08 },
+               { 999999999, 44000000, 166666, 0xfc, 0x02 },
+       }
+};
+EXPORT_SYMBOL(dvb_pll_tbmv30111in);
+
 /* ----------------------------------------------------------- */
 /* code                                                        */
 
index 205b2d1a88520a476a2fd7e05847f7debf05b8d4..497d31dcf41ebd0e832004ce6194f02a4b913287 100644 (file)
@@ -36,6 +36,10 @@ extern struct dvb_pll_desc dvb_pll_tda665x;
 extern struct dvb_pll_desc dvb_pll_fmd1216me;
 extern struct dvb_pll_desc dvb_pll_tded4;
 
+extern struct dvb_pll_desc dvb_pll_tuv1236d;
+extern struct dvb_pll_desc dvb_pll_tdhu2;
+extern struct dvb_pll_desc dvb_pll_tbmv30111in;
+
 int dvb_pll_configure(struct dvb_pll_desc *desc, u8 *buf,
                      u32 freq, int bandwidth);
 
index 7852b83b82d44737413cd013ff657b8afc0cfc7c..6a33f5a19a8d72d96312963f05bc745555f934b5 100644 (file)
@@ -26,6 +26,8 @@
  *   DViCO FusionHDTV 3 Gold-Q
  *   DViCO FusionHDTV 3 Gold-T
  *   DViCO FusionHDTV 5 Gold
+ *   DViCO FusionHDTV 5 Lite
+ *   Air2PC/AirStar 2 ATSC 3rd generation (HD5000)
  *
  * TODO:
  * signal strength always returns 0.
@@ -222,6 +224,11 @@ static int lgdt330x_init(struct dvb_frontend* fe)
                0x4c, 0x14
        };
 
+       static u8 flip_lgdt3303_init_data[] = {
+               0x4c, 0x14,
+               0x87, 0xf3
+       };
+
        struct lgdt330x_state* state = fe->demodulator_priv;
        char  *chip_name;
        int    err;
@@ -234,8 +241,13 @@ static int lgdt330x_init(struct dvb_frontend* fe)
                break;
        case LGDT3303:
                chip_name = "LGDT3303";
-               err = i2c_write_demod_bytes(state, lgdt3303_init_data,
-                                           sizeof(lgdt3303_init_data));
+               if (state->config->clock_polarity_flip) {
+                       err = i2c_write_demod_bytes(state, flip_lgdt3303_init_data,
+                                                   sizeof(flip_lgdt3303_init_data));
+               } else {
+                       err = i2c_write_demod_bytes(state, lgdt3303_init_data,
+                                                   sizeof(lgdt3303_init_data));
+               }
                break;
        default:
                chip_name = "undefined";
@@ -743,9 +755,8 @@ static struct dvb_frontend_ops lgdt3302_ops = {
                .frequency_min= 54000000,
                .frequency_max= 858000000,
                .frequency_stepsize= 62500,
-               /* Symbol rate is for all VSB modes need to check QAM */
-               .symbol_rate_min    = 10762000,
-               .symbol_rate_max    = 10762000,
+               .symbol_rate_min    = 5056941,  /* QAM 64 */
+               .symbol_rate_max    = 10762000, /* VSB 8  */
                .caps = FE_CAN_QAM_64 | FE_CAN_QAM_256 | FE_CAN_8VSB
        },
        .init                 = lgdt330x_init,
@@ -767,9 +778,8 @@ static struct dvb_frontend_ops lgdt3303_ops = {
                .frequency_min= 54000000,
                .frequency_max= 858000000,
                .frequency_stepsize= 62500,
-               /* Symbol rate is for all VSB modes need to check QAM */
-               .symbol_rate_min    = 10762000,
-               .symbol_rate_max    = 10762000,
+               .symbol_rate_min    = 5056941,  /* QAM 64 */
+               .symbol_rate_max    = 10762000, /* VSB 8  */
                .caps = FE_CAN_QAM_64 | FE_CAN_QAM_256 | FE_CAN_8VSB
        },
        .init                 = lgdt330x_init,
index e209ba1e47c5cb3bc9ecff6052e93cfa1eb4e158..2a6529cccf1afe59a1c5204b76c30dab1dc676e3 100644 (file)
@@ -47,6 +47,10 @@ struct lgdt330x_config
 
        /* Need to set device param for start_dma */
        int (*set_ts_params)(struct dvb_frontend* fe, int is_punctured);
+
+       /* Flip the polarity of the mpeg data transfer clock using alternate init data
+        * This option applies ONLY to LGDT3303 - 0:disabled (default) 1:enabled */
+       int clock_polarity_flip;
 };
 
 extern struct dvb_frontend* lgdt330x_attach(const struct lgdt330x_config* config,
diff --git a/drivers/media/dvb/frontends/nxt200x.c b/drivers/media/dvb/frontends/nxt200x.c
new file mode 100644 (file)
index 0000000..bad0933
--- /dev/null
@@ -0,0 +1,1205 @@
+/*
+ *    Support for NXT2002 and NXT2004 - VSB/QAM
+ *
+ *    Copyright (C) 2005 Kirk Lapray (kirk.lapray@gmail.com)
+ *    based on nxt2002 by Taylor Jacob <rtjacob@earthlink.net>
+ *    and nxt2004 by Jean-Francois Thibert (jeanfrancois@sagetv.com)
+ *
+ *    This program is free software; you can redistribute it and/or modify
+ *    it under the terms of the GNU General Public License as published by
+ *    the Free Software Foundation; either version 2 of the License, or
+ *    (at your option) any later version.
+ *
+ *    This program is distributed in the hope that it will be useful,
+ *    but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *    GNU General Public License for more details.
+ *
+ *    You should have received a copy of the GNU General Public License
+ *    along with this program; if not, write to the Free Software
+ *    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+*/
+
+/*
+ *                      NOTES ABOUT THIS DRIVER
+ *
+ * This Linux driver supports:
+ *   B2C2/BBTI Technisat Air2PC - ATSC (NXT2002)
+ *   AverTVHD MCE A180 (NXT2004)
+ *   ATI HDTV Wonder (NXT2004)
+ *
+ * This driver needs external firmware. Please use the command
+ * "<kerneldir>/Documentation/dvb/get_dvb_firmware nxt2002" or
+ * "<kerneldir>/Documentation/dvb/get_dvb_firmware nxt2004" to
+ * download/extract the appropriate firmware, and then copy it to
+ * /usr/lib/hotplug/firmware/ or /lib/firmware/
+ * (depending on configuration of firmware hotplug).
+ */
+#define NXT2002_DEFAULT_FIRMWARE "dvb-fe-nxt2002.fw"
+#define NXT2004_DEFAULT_FIRMWARE "dvb-fe-nxt2004.fw"
+#define CRC_CCIT_MASK 0x1021
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+
+#include "dvb_frontend.h"
+#include "dvb-pll.h"
+#include "nxt200x.h"
+
+struct nxt200x_state {
+
+       struct i2c_adapter* i2c;
+       struct dvb_frontend_ops ops;
+       const struct nxt200x_config* config;
+       struct dvb_frontend frontend;
+
+       /* demodulator private data */
+       nxt_chip_type demod_chip;
+       u8 initialised:1;
+};
+
+static int debug;
+#define dprintk(args...) \
+       do { \
+               if (debug) printk(KERN_DEBUG "nxt200x: " args); \
+       } while (0)
+
+static int i2c_writebytes (struct nxt200x_state* state, u8 addr, u8 *buf, u8 len)
+{
+       int err;
+       struct i2c_msg msg = { .addr = addr, .flags = 0, .buf = buf, .len = len };
+
+       if ((err = i2c_transfer (state->i2c, &msg, 1)) != 1) {
+               printk (KERN_WARNING "nxt200x: %s: i2c write error (addr 0x%02x, err == %i)\n",
+                       __FUNCTION__, addr, err);
+               return -EREMOTEIO;
+       }
+       return 0;
+}
+
+static u8 i2c_readbytes (struct nxt200x_state* state, u8 addr, u8* buf, u8 len)
+{
+       int err;
+       struct i2c_msg msg = { .addr = addr, .flags = I2C_M_RD, .buf = buf, .len = len };
+
+       if ((err = i2c_transfer (state->i2c, &msg, 1)) != 1) {
+               printk (KERN_WARNING "nxt200x: %s: i2c read error (addr 0x%02x, err == %i)\n",
+                       __FUNCTION__, addr, err);
+               return -EREMOTEIO;
+       }
+       return 0;
+}
+
+static int nxt200x_writebytes (struct nxt200x_state* state, u8 reg, u8 *buf, u8 len)
+{
+       u8 buf2 [len+1];
+       int err;
+       struct i2c_msg msg = { .addr = state->config->demod_address, .flags = 0, .buf = buf2, .len = len + 1 };
+
+       buf2[0] = reg;
+       memcpy(&buf2[1], buf, len);
+
+       if ((err = i2c_transfer (state->i2c, &msg, 1)) != 1) {
+               printk (KERN_WARNING "nxt200x: %s: i2c write error (addr 0x%02x, err == %i)\n",
+                       __FUNCTION__, state->config->demod_address, err);
+               return -EREMOTEIO;
+       }
+       return 0;
+}
+
+static u8 nxt200x_readbytes (struct nxt200x_state* state, u8 reg, u8* buf, u8 len)
+{
+       u8 reg2 [] = { reg };
+
+       struct i2c_msg msg [] = { { .addr = state->config->demod_address, .flags = 0, .buf = reg2, .len = 1 },
+                       { .addr = state->config->demod_address, .flags = I2C_M_RD, .buf = buf, .len = len } };
+
+       int err;
+
+       if ((err = i2c_transfer (state->i2c, msg, 2)) != 2) {
+               printk (KERN_WARNING "nxt200x: %s: i2c read error (addr 0x%02x, err == %i)\n",
+                       __FUNCTION__, state->config->demod_address, err);
+               return -EREMOTEIO;
+       }
+       return 0;
+}
+
+static u16 nxt200x_crc(u16 crc, u8 c)
+{
+       u8 i;
+       u16 input = (u16) c & 0xFF;
+
+       input<<=8;
+       for(i=0; i<8; i++) {
+               if((crc^input) & 0x8000)
+                       crc=(crc<<1)^CRC_CCIT_MASK;
+               else
+                       crc<<=1;
+               input<<=1;
+       }
+       return crc;
+}
+
+static int nxt200x_writereg_multibyte (struct nxt200x_state* state, u8 reg, u8* data, u8 len)
+{
+       u8 attr, len2, buf;
+       dprintk("%s\n", __FUNCTION__);
+
+       /* set mutli register register */
+       nxt200x_writebytes(state, 0x35, &reg, 1);
+
+       /* send the actual data */
+       nxt200x_writebytes(state, 0x36, data, len);
+
+       switch (state->demod_chip) {
+               case NXT2002:
+                       len2 = len;
+                       buf = 0x02;
+                       break;
+               case NXT2004:
+                       /* probably not right, but gives correct values */
+                       attr = 0x02;
+                       if (reg & 0x80) {
+                               attr = attr << 1;
+                               if (reg & 0x04)
+                                       attr = attr >> 1;
+                       }
+                       /* set write bit */
+                       len2 = ((attr << 4) | 0x10) | len;
+                       buf = 0x80;
+                       break;
+               default:
+                       return -EINVAL;
+                       break;
+       }
+
+       /* set multi register length */
+       nxt200x_writebytes(state, 0x34, &len2, 1);
+
+       /* toggle the multireg write bit */
+       nxt200x_writebytes(state, 0x21, &buf, 1);
+
+       nxt200x_readbytes(state, 0x21, &buf, 1);
+
+       switch (state->demod_chip) {
+               case NXT2002:
+                       if ((buf & 0x02) == 0)
+                               return 0;
+                       break;
+               case NXT2004:
+                       if (buf == 0)
+                               return 0;
+                       break;
+               default:
+                       return -EINVAL;
+                       break;
+       }
+
+       printk(KERN_WARNING "nxt200x: Error writing multireg register 0x%02X\n",reg);
+
+       return 0;
+}
+
+static int nxt200x_readreg_multibyte (struct nxt200x_state* state, u8 reg, u8* data, u8 len)
+{
+       int i;
+       u8 buf, len2, attr;
+       dprintk("%s\n", __FUNCTION__);
+
+       /* set mutli register register */
+       nxt200x_writebytes(state, 0x35, &reg, 1);
+
+       switch (state->demod_chip) {
+               case NXT2002:
+                       /* set multi register length */
+                       len2 = len & 0x80;
+                       nxt200x_writebytes(state, 0x34, &len2, 1);
+
+                       /* read the actual data */
+                       nxt200x_readbytes(state, reg, data, len);
+                       return 0;
+                       break;
+               case NXT2004:
+                       /* probably not right, but gives correct values */
+                       attr = 0x02;
+                       if (reg & 0x80) {
+                               attr = attr << 1;
+                               if (reg & 0x04)
+                                       attr = attr >> 1;
+                       }
+
+                       /* set multi register length */
+                       len2 = (attr << 4) | len;
+                       nxt200x_writebytes(state, 0x34, &len2, 1);
+
+                       /* toggle the multireg bit*/
+                       buf = 0x80;
+                       nxt200x_writebytes(state, 0x21, &buf, 1);
+
+                       /* read the actual data */
+                       for(i = 0; i < len; i++) {
+                               nxt200x_readbytes(state, 0x36 + i, &data[i], 1);
+                       }
+                       return 0;
+                       break;
+               default:
+                       return -EINVAL;
+                       break;
+       }
+}
+
+static void nxt200x_microcontroller_stop (struct nxt200x_state* state)
+{
+       u8 buf, stopval, counter = 0;
+       dprintk("%s\n", __FUNCTION__);
+
+       /* set correct stop value */
+       switch (state->demod_chip) {
+               case NXT2002:
+                       stopval = 0x40;
+                       break;
+               case NXT2004:
+                       stopval = 0x10;
+                       break;
+               default:
+                       stopval = 0;
+                       break;
+       }
+
+       buf = 0x80;
+       nxt200x_writebytes(state, 0x22, &buf, 1);
+
+       while (counter < 20) {
+               nxt200x_readbytes(state, 0x31, &buf, 1);
+               if (buf & stopval)
+                       return;
+               msleep(10);
+               counter++;
+       }
+
+       printk(KERN_WARNING "nxt200x: Timeout waiting for nxt200x to stop. This is ok after firmware upload.\n");
+       return;
+}
+
+static void nxt200x_microcontroller_start (struct nxt200x_state* state)
+{
+       u8 buf;
+       dprintk("%s\n", __FUNCTION__);
+
+       buf = 0x00;
+       nxt200x_writebytes(state, 0x22, &buf, 1);
+}
+
+static void nxt2004_microcontroller_init (struct nxt200x_state* state)
+{
+       u8 buf[9];
+       u8 counter = 0;
+       dprintk("%s\n", __FUNCTION__);
+
+       buf[0] = 0x00;
+       nxt200x_writebytes(state, 0x2b, buf, 1);
+       buf[0] = 0x70;
+       nxt200x_writebytes(state, 0x34, buf, 1);
+       buf[0] = 0x04;
+       nxt200x_writebytes(state, 0x35, buf, 1);
+       buf[0] = 0x01; buf[1] = 0x23; buf[2] = 0x45; buf[3] = 0x67; buf[4] = 0x89;
+       buf[5] = 0xAB; buf[6] = 0xCD; buf[7] = 0xEF; buf[8] = 0xC0;
+       nxt200x_writebytes(state, 0x36, buf, 9);
+       buf[0] = 0x80;
+       nxt200x_writebytes(state, 0x21, buf, 1);
+
+       while (counter < 20) {
+               nxt200x_readbytes(state, 0x21, buf, 1);
+               if (buf[0] == 0)
+                       return;
+               msleep(10);
+               counter++;
+       }
+
+       printk(KERN_WARNING "nxt200x: Timeout waiting for nxt2004 to init.\n");
+
+       return;
+}
+
+static int nxt200x_writetuner (struct nxt200x_state* state, u8* data)
+{
+       u8 buf, count = 0;
+
+       dprintk("%s\n", __FUNCTION__);
+
+       dprintk("Tuner Bytes: %02X %02X %02X %02X\n", data[0], data[1], data[2], data[3]);
+
+       /* if NXT2004, write directly to tuner. if NXT2002, write through NXT chip.
+        * direct write is required for Philips TUV1236D and ALPS TDHU2 */
+       switch (state->demod_chip) {
+               case NXT2004:
+                       if (i2c_writebytes(state, state->config->pll_address, data, 4))
+                               printk(KERN_WARNING "nxt200x: error writing to tuner\n");
+                       /* wait until we have a lock */
+                       while (count < 20) {
+                               i2c_readbytes(state, state->config->pll_address, &buf, 1);
+                               if (buf & 0x40)
+                                       return 0;
+                               msleep(100);
+                               count++;
+                       }
+                       printk("nxt2004: timeout waiting for tuner lock\n");
+                       break;
+               case NXT2002:
+                       /* set the i2c transfer speed to the tuner */
+                       buf = 0x03;
+                       nxt200x_writebytes(state, 0x20, &buf, 1);
+
+                       /* setup to transfer 4 bytes via i2c */
+                       buf = 0x04;
+                       nxt200x_writebytes(state, 0x34, &buf, 1);
+
+                       /* write actual tuner bytes */
+                       nxt200x_writebytes(state, 0x36, data, 4);
+
+                       /* set tuner i2c address */
+                       buf = state->config->pll_address;
+                       nxt200x_writebytes(state, 0x35, &buf, 1);
+
+                       /* write UC Opmode to begin transfer */
+                       buf = 0x80;
+                       nxt200x_writebytes(state, 0x21, &buf, 1);
+
+                       while (count < 20) {
+                               nxt200x_readbytes(state, 0x21, &buf, 1);
+                               if ((buf & 0x80)== 0x00)
+                                       return 0;
+                               msleep(100);
+                               count++;
+                       }
+                       printk("nxt2002: timeout error writing tuner\n");
+                       break;
+               default:
+                       return -EINVAL;
+                       break;
+       }
+       return 0;
+}
+
+static void nxt200x_agc_reset(struct nxt200x_state* state)
+{
+       u8 buf;
+       dprintk("%s\n", __FUNCTION__);
+
+       switch (state->demod_chip) {
+               case NXT2002:
+                       buf = 0x08;
+                       nxt200x_writebytes(state, 0x08, &buf, 1);
+                       buf = 0x00;
+                       nxt200x_writebytes(state, 0x08, &buf, 1);
+                       break;
+               case NXT2004:
+                       nxt200x_readreg_multibyte(state, 0x08, &buf, 1);
+                       buf = 0x08;
+                       nxt200x_writereg_multibyte(state, 0x08, &buf, 1);
+                       buf = 0x00;
+                       nxt200x_writereg_multibyte(state, 0x08, &buf, 1);
+                       break;
+               default:
+                       break;
+       }
+       return;
+}
+
+static int nxt2002_load_firmware (struct dvb_frontend* fe, const struct firmware *fw)
+{
+
+       struct nxt200x_state* state = fe->demodulator_priv;
+       u8 buf[3], written = 0, chunkpos = 0;
+       u16 rambase, position, crc = 0;
+
+       dprintk("%s\n", __FUNCTION__);
+       dprintk("Firmware is %zu bytes\n", fw->size);
+
+       /* Get the RAM base for this nxt2002 */
+       nxt200x_readbytes(state, 0x10, buf, 1);
+
+       if (buf[0] & 0x10)
+               rambase = 0x1000;
+       else
+               rambase = 0x0000;
+
+       dprintk("rambase on this nxt2002 is %04X\n", rambase);
+
+       /* Hold the micro in reset while loading firmware */
+       buf[0] = 0x80;
+       nxt200x_writebytes(state, 0x2B, buf, 1);
+
+       for (position = 0; position < fw->size; position++) {
+               if (written == 0) {
+                       crc = 0;
+                       chunkpos = 0x28;
+                       buf[0] = ((rambase + position) >> 8);
+                       buf[1] = (rambase + position) & 0xFF;
+                       buf[2] = 0x81;
+                       /* write starting address */
+                       nxt200x_writebytes(state, 0x29, buf, 3);
+               }
+               written++;
+               chunkpos++;
+
+               if ((written % 4) == 0)
+                       nxt200x_writebytes(state, chunkpos, &fw->data[position-3], 4);
+
+               crc = nxt200x_crc(crc, fw->data[position]);
+
+               if ((written == 255) || (position+1 == fw->size)) {
+                       /* write remaining bytes of firmware */
+                       nxt200x_writebytes(state, chunkpos+4-(written %4),
+                               &fw->data[position-(written %4) + 1],
+                               written %4);
+                       buf[0] = crc << 8;
+                       buf[1] = crc & 0xFF;
+
+                       /* write crc */
+                       nxt200x_writebytes(state, 0x2C, buf, 2);
+
+                       /* do a read to stop things */
+                       nxt200x_readbytes(state, 0x2A, buf, 1);
+
+                       /* set transfer mode to complete */
+                       buf[0] = 0x80;
+                       nxt200x_writebytes(state, 0x2B, buf, 1);
+
+                       written = 0;
+               }
+       }
+
+       return 0;
+};
+
+static int nxt2004_load_firmware (struct dvb_frontend* fe, const struct firmware *fw)
+{
+
+       struct nxt200x_state* state = fe->demodulator_priv;
+       u8 buf[3];
+       u16 rambase, position, crc=0;
+
+       dprintk("%s\n", __FUNCTION__);
+       dprintk("Firmware is %zu bytes\n", fw->size);
+
+       /* set rambase */
+       rambase = 0x1000;
+
+       /* hold the micro in reset while loading firmware */
+       buf[0] = 0x80;
+       nxt200x_writebytes(state, 0x2B, buf,1);
+
+       /* calculate firmware CRC */
+       for (position = 0; position < fw->size; position++) {
+               crc = nxt200x_crc(crc, fw->data[position]);
+       }
+
+       buf[0] = rambase >> 8;
+       buf[1] = rambase & 0xFF;
+       buf[2] = 0x81;
+       /* write starting address */
+       nxt200x_writebytes(state,0x29,buf,3);
+
+       for (position = 0; position < fw->size;) {
+               nxt200x_writebytes(state, 0x2C, &fw->data[position],
+                       fw->size-position > 255 ? 255 : fw->size-position);
+               position += (fw->size-position > 255 ? 255 : fw->size-position);
+       }
+       buf[0] = crc >> 8;
+       buf[1] = crc & 0xFF;
+
+       dprintk("firmware crc is 0x%02X 0x%02X\n", buf[0], buf[1]);
+
+       /* write crc */
+       nxt200x_writebytes(state, 0x2C, buf,2);
+
+       /* do a read to stop things */
+       nxt200x_readbytes(state, 0x2C, buf, 1);
+
+       /* set transfer mode to complete */
+       buf[0] = 0x80;
+       nxt200x_writebytes(state, 0x2B, buf,1);
+
+       return 0;
+};
+
+static int nxt200x_setup_frontend_parameters (struct dvb_frontend* fe,
+                                            struct dvb_frontend_parameters *p)
+{
+       struct nxt200x_state* state = fe->demodulator_priv;
+       u8 buf[4];
+
+       /* stop the micro first */
+       nxt200x_microcontroller_stop(state);
+
+       if (state->demod_chip == NXT2004) {
+               /* make sure demod is set to digital */
+               buf[0] = 0x04;
+               nxt200x_writebytes(state, 0x14, buf, 1);
+               buf[0] = 0x00;
+               nxt200x_writebytes(state, 0x17, buf, 1);
+       }
+
+       /* get tuning information */
+       dvb_pll_configure(state->config->pll_desc, buf, p->frequency, 0);
+
+       /* set additional params */
+       switch (p->u.vsb.modulation) {
+               case QAM_64:
+               case QAM_256:
+                       /* Set punctured clock for QAM */
+                       /* This is just a guess since I am unable to test it */
+                       if (state->config->set_ts_params)
+                               state->config->set_ts_params(fe, 1);
+
+                       /* set input */
+                       if (state->config->set_pll_input)
+                               state->config->set_pll_input(buf, 1);
+                       break;
+               case VSB_8:
+                       /* Set non-punctured clock for VSB */
+                       if (state->config->set_ts_params)
+                               state->config->set_ts_params(fe, 0);
+
+                       /* set input */
+                       if (state->config->set_pll_input)
+                               state->config->set_pll_input(buf, 0);
+                       break;
+               default:
+                       return -EINVAL;
+                       break;
+       }
+
+       /* write frequency information */
+       nxt200x_writetuner(state, buf);
+
+       /* reset the agc now that tuning has been completed */
+       nxt200x_agc_reset(state);
+
+       /* set target power level */
+       switch (p->u.vsb.modulation) {
+               case QAM_64:
+               case QAM_256:
+                       buf[0] = 0x74;
+                       break;
+               case VSB_8:
+                       buf[0] = 0x70;
+                       break;
+               default:
+                       return -EINVAL;
+                       break;
+       }
+       nxt200x_writebytes(state, 0x42, buf, 1);
+
+       /* configure sdm */
+       switch (state->demod_chip) {
+               case NXT2002:
+                       buf[0] = 0x87;
+                       break;
+               case NXT2004:
+                       buf[0] = 0x07;
+                       break;
+               default:
+                       return -EINVAL;
+                       break;
+       }
+       nxt200x_writebytes(state, 0x57, buf, 1);
+
+       /* write sdm1 input */
+       buf[0] = 0x10;
+       buf[1] = 0x00;
+       nxt200x_writebytes(state, 0x58, buf, 2);
+
+       /* write sdmx input */
+       switch (p->u.vsb.modulation) {
+               case QAM_64:
+                               buf[0] = 0x68;
+                               break;
+               case QAM_256:
+                               buf[0] = 0x64;
+                               break;
+               case VSB_8:
+                               buf[0] = 0x60;
+                               break;
+               default:
+                               return -EINVAL;
+                               break;
+       }
+       buf[1] = 0x00;
+       nxt200x_writebytes(state, 0x5C, buf, 2);
+
+       /* write adc power lpf fc */
+       buf[0] = 0x05;
+       nxt200x_writebytes(state, 0x43, buf, 1);
+
+       if (state->demod_chip == NXT2004) {
+               /* write ??? */
+               buf[0] = 0x00;
+               buf[1] = 0x00;
+               nxt200x_writebytes(state, 0x46, buf, 2);
+       }
+
+       /* write accumulator2 input */
+       buf[0] = 0x80;
+       buf[1] = 0x00;
+       nxt200x_writebytes(state, 0x4B, buf, 2);
+
+       /* write kg1 */
+       buf[0] = 0x00;
+       nxt200x_writebytes(state, 0x4D, buf, 1);
+
+       /* write sdm12 lpf fc */
+       buf[0] = 0x44;
+       nxt200x_writebytes(state, 0x55, buf, 1);
+
+       /* write agc control reg */
+       buf[0] = 0x04;
+       nxt200x_writebytes(state, 0x41, buf, 1);
+
+       if (state->demod_chip == NXT2004) {
+               nxt200x_readreg_multibyte(state, 0x80, buf, 1);
+               buf[0] = 0x24;
+               nxt200x_writereg_multibyte(state, 0x80, buf, 1);
+
+               /* soft reset? */
+               nxt200x_readreg_multibyte(state, 0x08, buf, 1);
+               buf[0] = 0x10;
+               nxt200x_writereg_multibyte(state, 0x08, buf, 1);
+               nxt200x_readreg_multibyte(state, 0x08, buf, 1);
+               buf[0] = 0x00;
+               nxt200x_writereg_multibyte(state, 0x08, buf, 1);
+
+               nxt200x_readreg_multibyte(state, 0x80, buf, 1);
+               buf[0] = 0x04;
+               nxt200x_writereg_multibyte(state, 0x80, buf, 1);
+               buf[0] = 0x00;
+               nxt200x_writereg_multibyte(state, 0x81, buf, 1);
+               buf[0] = 0x80; buf[1] = 0x00; buf[2] = 0x00;
+               nxt200x_writereg_multibyte(state, 0x82, buf, 3);
+               nxt200x_readreg_multibyte(state, 0x88, buf, 1);
+               buf[0] = 0x11;
+               nxt200x_writereg_multibyte(state, 0x88, buf, 1);
+               nxt200x_readreg_multibyte(state, 0x80, buf, 1);
+               buf[0] = 0x44;
+               nxt200x_writereg_multibyte(state, 0x80, buf, 1);
+       }
+
+       /* write agc ucgp0 */
+       switch (p->u.vsb.modulation) {
+               case QAM_64:
+                               buf[0] = 0x02;
+                               break;
+               case QAM_256:
+                               buf[0] = 0x03;
+                               break;
+               case VSB_8:
+                               buf[0] = 0x00;
+                               break;
+               default:
+                               return -EINVAL;
+                               break;
+       }
+       nxt200x_writebytes(state, 0x30, buf, 1);
+
+       /* write agc control reg */
+       buf[0] = 0x00;
+       nxt200x_writebytes(state, 0x41, buf, 1);
+
+       /* write accumulator2 input */
+       buf[0] = 0x80;
+       buf[1] = 0x00;
+       nxt200x_writebytes(state, 0x49, buf,2);
+       nxt200x_writebytes(state, 0x4B, buf,2);
+
+       /* write agc control reg */
+       buf[0] = 0x04;
+       nxt200x_writebytes(state, 0x41, buf, 1);
+
+       nxt200x_microcontroller_start(state);
+
+       if (state->demod_chip == NXT2004) {
+               nxt2004_microcontroller_init(state);
+
+               /* ???? */
+               buf[0] = 0xF0;
+               buf[1] = 0x00;
+               nxt200x_writebytes(state, 0x5C, buf, 2);
+       }
+
+       /* adjacent channel detection should be done here, but I don't
+       have any stations with this need so I cannot test it */
+
+       return 0;
+}
+
+static int nxt200x_read_status(struct dvb_frontend* fe, fe_status_t* status)
+{
+       struct nxt200x_state* state = fe->demodulator_priv;
+       u8 lock;
+       nxt200x_readbytes(state, 0x31, &lock, 1);
+
+       *status = 0;
+       if (lock & 0x20) {
+               *status |= FE_HAS_SIGNAL;
+               *status |= FE_HAS_CARRIER;
+               *status |= FE_HAS_VITERBI;
+               *status |= FE_HAS_SYNC;
+               *status |= FE_HAS_LOCK;
+       }
+       return 0;
+}
+
+static int nxt200x_read_ber(struct dvb_frontend* fe, u32* ber)
+{
+       struct nxt200x_state* state = fe->demodulator_priv;
+       u8 b[3];
+
+       nxt200x_readreg_multibyte(state, 0xE6, b, 3);
+
+       *ber = ((b[0] << 8) + b[1]) * 8;
+
+       return 0;
+}
+
+static int nxt200x_read_signal_strength(struct dvb_frontend* fe, u16* strength)
+{
+       struct nxt200x_state* state = fe->demodulator_priv;
+       u8 b[2];
+       u16 temp = 0;
+
+       /* setup to read cluster variance */
+       b[0] = 0x00;
+       nxt200x_writebytes(state, 0xA1, b, 1);
+
+       /* get multreg val */
+       nxt200x_readreg_multibyte(state, 0xA6, b, 2);
+
+       temp = (b[0] << 8) | b[1];
+       *strength = ((0x7FFF - temp) & 0x0FFF) * 16;
+
+       return 0;
+}
+
+static int nxt200x_read_snr(struct dvb_frontend* fe, u16* snr)
+{
+
+       struct nxt200x_state* state = fe->demodulator_priv;
+       u8 b[2];
+       u16 temp = 0, temp2;
+       u32 snrdb = 0;
+
+       /* setup to read cluster variance */
+       b[0] = 0x00;
+       nxt200x_writebytes(state, 0xA1, b, 1);
+
+       /* get multreg val from 0xA6 */
+       nxt200x_readreg_multibyte(state, 0xA6, b, 2);
+
+       temp = (b[0] << 8) | b[1];
+       temp2 = 0x7FFF - temp;
+
+       /* snr will be in db */
+       if (temp2 > 0x7F00)
+               snrdb = 1000*24 + ( 1000*(30-24) * ( temp2 - 0x7F00 ) / ( 0x7FFF - 0x7F00 ) );
+       else if (temp2 > 0x7EC0)
+               snrdb = 1000*18 + ( 1000*(24-18) * ( temp2 - 0x7EC0 ) / ( 0x7F00 - 0x7EC0 ) );
+       else if (temp2 > 0x7C00)
+               snrdb = 1000*12 + ( 1000*(18-12) * ( temp2 - 0x7C00 ) / ( 0x7EC0 - 0x7C00 ) );
+       else
+               snrdb = 1000*0 + ( 1000*(12-0) * ( temp2 - 0 ) / ( 0x7C00 - 0 ) );
+
+       /* the value reported back from the frontend will be FFFF=32db 0000=0db */
+       *snr = snrdb * (0xFFFF/32000);
+
+       return 0;
+}
+
+static int nxt200x_read_ucblocks(struct dvb_frontend* fe, u32* ucblocks)
+{
+       struct nxt200x_state* state = fe->demodulator_priv;
+       u8 b[3];
+
+       nxt200x_readreg_multibyte(state, 0xE6, b, 3);
+       *ucblocks = b[2];
+
+       return 0;
+}
+
+static int nxt200x_sleep(struct dvb_frontend* fe)
+{
+       return 0;
+}
+
+static int nxt2002_init(struct dvb_frontend* fe)
+{
+       struct nxt200x_state* state = fe->demodulator_priv;
+       const struct firmware *fw;
+       int ret;
+       u8 buf[2];
+
+       /* request the firmware, this will block until someone uploads it */
+       printk("nxt2002: Waiting for firmware upload (%s)...\n", NXT2002_DEFAULT_FIRMWARE);
+       ret = request_firmware(&fw, NXT2002_DEFAULT_FIRMWARE, &state->i2c->dev);
+       printk("nxt2002: Waiting for firmware upload(2)...\n");
+       if (ret) {
+               printk("nxt2002: No firmware uploaded (timeout or file not found?)\n");
+               return ret;
+       }
+
+       ret = nxt2002_load_firmware(fe, fw);
+       if (ret) {
+               printk("nxt2002: Writing firmware to device failed\n");
+               release_firmware(fw);
+               return ret;
+       }
+       printk("nxt2002: Firmware upload complete\n");
+
+       /* Put the micro into reset */
+       nxt200x_microcontroller_stop(state);
+
+       /* ensure transfer is complete */
+       buf[0]=0x00;
+       nxt200x_writebytes(state, 0x2B, buf, 1);
+
+       /* Put the micro into reset for real this time */
+       nxt200x_microcontroller_stop(state);
+
+       /* soft reset everything (agc,frontend,eq,fec)*/
+       buf[0] = 0x0F;
+       nxt200x_writebytes(state, 0x08, buf, 1);
+       buf[0] = 0x00;
+       nxt200x_writebytes(state, 0x08, buf, 1);
+
+       /* write agc sdm configure */
+       buf[0] = 0xF1;
+       nxt200x_writebytes(state, 0x57, buf, 1);
+
+       /* write mod output format */
+       buf[0] = 0x20;
+       nxt200x_writebytes(state, 0x09, buf, 1);
+
+       /* write fec mpeg mode */
+       buf[0] = 0x7E;
+       buf[1] = 0x00;
+       nxt200x_writebytes(state, 0xE9, buf, 2);
+
+       /* write mux selection */
+       buf[0] = 0x00;
+       nxt200x_writebytes(state, 0xCC, buf, 1);
+
+       return 0;
+}
+
+static int nxt2004_init(struct dvb_frontend* fe)
+{
+       struct nxt200x_state* state = fe->demodulator_priv;
+       const struct firmware *fw;
+       int ret;
+       u8 buf[3];
+
+       /* ??? */
+       buf[0]=0x00;
+       nxt200x_writebytes(state, 0x1E, buf, 1);
+
+       /* request the firmware, this will block until someone uploads it */
+       printk("nxt2004: Waiting for firmware upload (%s)...\n", NXT2004_DEFAULT_FIRMWARE);
+       ret = request_firmware(&fw, NXT2004_DEFAULT_FIRMWARE, &state->i2c->dev);
+       printk("nxt2004: Waiting for firmware upload(2)...\n");
+       if (ret) {
+               printk("nxt2004: No firmware uploaded (timeout or file not found?)\n");
+               return ret;
+       }
+
+       ret = nxt2004_load_firmware(fe, fw);
+       if (ret) {
+               printk("nxt2004: Writing firmware to device failed\n");
+               release_firmware(fw);
+               return ret;
+       }
+       printk("nxt2004: Firmware upload complete\n");
+
+       /* ensure transfer is complete */
+       buf[0] = 0x01;
+       nxt200x_writebytes(state, 0x19, buf, 1);
+
+       nxt2004_microcontroller_init(state);
+       nxt200x_microcontroller_stop(state);
+       nxt200x_microcontroller_stop(state);
+       nxt2004_microcontroller_init(state);
+       nxt200x_microcontroller_stop(state);
+
+       /* soft reset everything (agc,frontend,eq,fec)*/
+       buf[0] = 0xFF;
+       nxt200x_writereg_multibyte(state, 0x08, buf, 1);
+       buf[0] = 0x00;
+       nxt200x_writereg_multibyte(state, 0x08, buf, 1);
+
+       /* write agc sdm configure */
+       buf[0] = 0xD7;
+       nxt200x_writebytes(state, 0x57, buf, 1);
+
+       /* ???*/
+       buf[0] = 0x07;
+       buf[1] = 0xfe;
+       nxt200x_writebytes(state, 0x35, buf, 2);
+       buf[0] = 0x12;
+       nxt200x_writebytes(state, 0x34, buf, 1);
+       buf[0] = 0x80;
+       nxt200x_writebytes(state, 0x21, buf, 1);
+
+       /* ???*/
+       buf[0] = 0x21;
+       nxt200x_writebytes(state, 0x0A, buf, 1);
+
+       /* ???*/
+       buf[0] = 0x01;
+       nxt200x_writereg_multibyte(state, 0x80, buf, 1);
+
+       /* write fec mpeg mode */
+       buf[0] = 0x7E;
+       buf[1] = 0x00;
+       nxt200x_writebytes(state, 0xE9, buf, 2);
+
+       /* write mux selection */
+       buf[0] = 0x00;
+       nxt200x_writebytes(state, 0xCC, buf, 1);
+
+       /* ???*/
+       nxt200x_readreg_multibyte(state, 0x80, buf, 1);
+       buf[0] = 0x00;
+       nxt200x_writereg_multibyte(state, 0x80, buf, 1);
+
+       /* soft reset? */
+       nxt200x_readreg_multibyte(state, 0x08, buf, 1);
+       buf[0] = 0x10;
+       nxt200x_writereg_multibyte(state, 0x08, buf, 1);
+       nxt200x_readreg_multibyte(state, 0x08, buf, 1);
+       buf[0] = 0x00;
+       nxt200x_writereg_multibyte(state, 0x08, buf, 1);
+
+       /* ???*/
+       nxt200x_readreg_multibyte(state, 0x80, buf, 1);
+       buf[0] = 0x01;
+       nxt200x_writereg_multibyte(state, 0x80, buf, 1);
+       buf[0] = 0x70;
+       nxt200x_writereg_multibyte(state, 0x81, buf, 1);
+       buf[0] = 0x31; buf[1] = 0x5E; buf[2] = 0x66;
+       nxt200x_writereg_multibyte(state, 0x82, buf, 3);
+
+       nxt200x_readreg_multibyte(state, 0x88, buf, 1);
+       buf[0] = 0x11;
+       nxt200x_writereg_multibyte(state, 0x88, buf, 1);
+       nxt200x_readreg_multibyte(state, 0x80, buf, 1);
+       buf[0] = 0x40;
+       nxt200x_writereg_multibyte(state, 0x80, buf, 1);
+
+       nxt200x_readbytes(state, 0x10, buf, 1);
+       buf[0] = 0x10;
+       nxt200x_writebytes(state, 0x10, buf, 1);
+       nxt200x_readbytes(state, 0x0A, buf, 1);
+       buf[0] = 0x21;
+       nxt200x_writebytes(state, 0x0A, buf, 1);
+
+       nxt2004_microcontroller_init(state);
+
+       buf[0] = 0x21;
+       nxt200x_writebytes(state, 0x0A, buf, 1);
+       buf[0] = 0x7E;
+       nxt200x_writebytes(state, 0xE9, buf, 1);
+       buf[0] = 0x00;
+       nxt200x_writebytes(state, 0xEA, buf, 1);
+
+       nxt200x_readreg_multibyte(state, 0x80, buf, 1);
+       buf[0] = 0x00;
+       nxt200x_writereg_multibyte(state, 0x80, buf, 1);
+       nxt200x_readreg_multibyte(state, 0x80, buf, 1);
+       buf[0] = 0x00;
+       nxt200x_writereg_multibyte(state, 0x80, buf, 1);
+
+       /* soft reset? */
+       nxt200x_readreg_multibyte(state, 0x08, buf, 1);
+       buf[0] = 0x10;
+       nxt200x_writereg_multibyte(state, 0x08, buf, 1);
+       nxt200x_readreg_multibyte(state, 0x08, buf, 1);
+       buf[0] = 0x00;
+       nxt200x_writereg_multibyte(state, 0x08, buf, 1);
+
+       nxt200x_readreg_multibyte(state, 0x80, buf, 1);
+       buf[0] = 0x04;
+       nxt200x_writereg_multibyte(state, 0x80, buf, 1);
+       buf[0] = 0x00;
+       nxt200x_writereg_multibyte(state, 0x81, buf, 1);
+       buf[0] = 0x80; buf[1] = 0x00; buf[2] = 0x00;
+       nxt200x_writereg_multibyte(state, 0x82, buf, 3);
+
+       nxt200x_readreg_multibyte(state, 0x88, buf, 1);
+       buf[0] = 0x11;
+       nxt200x_writereg_multibyte(state, 0x88, buf, 1);
+
+       nxt200x_readreg_multibyte(state, 0x80, buf, 1);
+       buf[0] = 0x44;
+       nxt200x_writereg_multibyte(state, 0x80, buf, 1);
+
+       /* initialize tuner */
+       nxt200x_readbytes(state, 0x10, buf, 1);
+       buf[0] = 0x12;
+       nxt200x_writebytes(state, 0x10, buf, 1);
+       buf[0] = 0x04;
+       nxt200x_writebytes(state, 0x13, buf, 1);
+       buf[0] = 0x00;
+       nxt200x_writebytes(state, 0x16, buf, 1);
+       buf[0] = 0x04;
+       nxt200x_writebytes(state, 0x14, buf, 1);
+       buf[0] = 0x00;
+       nxt200x_writebytes(state, 0x14, buf, 1);
+       nxt200x_writebytes(state, 0x17, buf, 1);
+       nxt200x_writebytes(state, 0x14, buf, 1);
+       nxt200x_writebytes(state, 0x17, buf, 1);
+
+       return 0;
+}
+
+static int nxt200x_init(struct dvb_frontend* fe)
+{
+       struct nxt200x_state* state = fe->demodulator_priv;
+       int ret = 0;
+
+       if (!state->initialised) {
+               switch (state->demod_chip) {
+                       case NXT2002:
+                               ret = nxt2002_init(fe);
+                               break;
+                       case NXT2004:
+                               ret = nxt2004_init(fe);
+                               break;
+                       default:
+                               return -EINVAL;
+                               break;
+               }
+               state->initialised = 1;
+       }
+       return ret;
+}
+
+static int nxt200x_get_tune_settings(struct dvb_frontend* fe, struct dvb_frontend_tune_settings* fesettings)
+{
+       fesettings->min_delay_ms = 500;
+       fesettings->step_size = 0;
+       fesettings->max_drift = 0;
+       return 0;
+}
+
+static void nxt200x_release(struct dvb_frontend* fe)
+{
+       struct nxt200x_state* state = fe->demodulator_priv;
+       kfree(state);
+}
+
+static struct dvb_frontend_ops nxt200x_ops;
+
+struct dvb_frontend* nxt200x_attach(const struct nxt200x_config* config,
+                                  struct i2c_adapter* i2c)
+{
+       struct nxt200x_state* state = NULL;
+       u8 buf [] = {0,0,0,0,0};
+
+       /* allocate memory for the internal state */
+       state = (struct nxt200x_state*) kmalloc(sizeof(struct nxt200x_state), GFP_KERNEL);
+       if (state == NULL)
+               goto error;
+       memset(state,0,sizeof(*state));
+
+       /* setup the state */
+       state->config = config;
+       state->i2c = i2c;
+       memcpy(&state->ops, &nxt200x_ops, sizeof(struct dvb_frontend_ops));
+       state->initialised = 0;
+
+       /* read card id */
+       nxt200x_readbytes(state, 0x00, buf, 5);
+       dprintk("NXT info: %02X %02X %02X %02X %02X\n",
+               buf[0], buf[1], buf[2], buf[3], buf[4]);
+
+       /* set demod chip */
+       switch (buf[0]) {
+               case 0x04:
+                       state->demod_chip = NXT2002;
+                       printk("nxt200x: NXT2002 Detected\n");
+                       break;
+               case 0x05:
+                       state->demod_chip = NXT2004;
+                       printk("nxt200x: NXT2004 Detected\n");
+                       break;
+               default:
+                       goto error;
+       }
+
+       /* make sure demod chip is supported */
+       switch (state->demod_chip) {
+               case NXT2002:
+                       if (buf[0] != 0x04) goto error;         /* device id */
+                       if (buf[1] != 0x02) goto error;         /* fab id */
+                       if (buf[2] != 0x11) goto error;         /* month */
+                       if (buf[3] != 0x20) goto error;         /* year msb */
+                       if (buf[4] != 0x00) goto error;         /* year lsb */
+                       break;
+               case NXT2004:
+                       if (buf[0] != 0x05) goto error;         /* device id */
+                       break;
+               default:
+                       goto error;
+       }
+
+       /* create dvb_frontend */
+       state->frontend.ops = &state->ops;
+       state->frontend.demodulator_priv = state;
+       return &state->frontend;
+
+error:
+       kfree(state);
+       printk("Unknown/Unsupported NXT chip: %02X %02X %02X %02X %02X\n",
+               buf[0], buf[1], buf[2], buf[3], buf[4]);
+       return NULL;
+}
+
+static struct dvb_frontend_ops nxt200x_ops = {
+
+       .info = {
+               .name = "Nextwave NXT200X VSB/QAM frontend",
+               .type = FE_ATSC,
+               .frequency_min =  54000000,
+               .frequency_max = 860000000,
+               .frequency_stepsize = 166666,   /* stepsize is just a guess */
+               .caps = FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 |
+                       FE_CAN_FEC_5_6 | FE_CAN_FEC_7_8 | FE_CAN_FEC_AUTO |
+                       FE_CAN_8VSB | FE_CAN_QAM_64 | FE_CAN_QAM_256
+       },
+
+       .release = nxt200x_release,
+
+       .init = nxt200x_init,
+       .sleep = nxt200x_sleep,
+
+       .set_frontend = nxt200x_setup_frontend_parameters,
+       .get_tune_settings = nxt200x_get_tune_settings,
+
+       .read_status = nxt200x_read_status,
+       .read_ber = nxt200x_read_ber,
+       .read_signal_strength = nxt200x_read_signal_strength,
+       .read_snr = nxt200x_read_snr,
+       .read_ucblocks = nxt200x_read_ucblocks,
+};
+
+module_param(debug, int, 0644);
+MODULE_PARM_DESC(debug, "Turn on/off frontend debugging (default:off).");
+
+MODULE_DESCRIPTION("NXT200X (ATSC 8VSB & ITU-T J.83 AnnexB 64/256 QAM) Demodulator Driver");
+MODULE_AUTHOR("Kirk Lapray, Jean-Francois Thibert, and Taylor Jacob");
+MODULE_LICENSE("GPL");
+
+EXPORT_SYMBOL(nxt200x_attach);
+
diff --git a/drivers/media/dvb/frontends/nxt200x.h b/drivers/media/dvb/frontends/nxt200x.h
new file mode 100644 (file)
index 0000000..1d9d70b
--- /dev/null
@@ -0,0 +1,61 @@
+/*
+ *    Support for NXT2002 and NXT2004 - VSB/QAM
+ *
+ *    Copyright (C) 2005 Kirk Lapray (kirk.lapray@gmail.com)
+ *    based on nxt2002 by Taylor Jacob <rtjacob@earthlink.net>
+ *    and nxt2004 by Jean-Francois Thibert (jeanfrancois@sagetv.com)
+ *
+ *    This program is free software; you can redistribute it and/or modify
+ *    it under the terms of the GNU General Public License as published by
+ *    the Free Software Foundation; either version 2 of the License, or
+ *    (at your option) any later version.
+ *
+ *    This program is distributed in the hope that it will be useful,
+ *    but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *    GNU General Public License for more details.
+ *
+ *    You should have received a copy of the GNU General Public License
+ *    along with this program; if not, write to the Free Software
+ *    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+*/
+
+#ifndef NXT200X_H
+#define NXT200X_H
+
+#include <linux/dvb/frontend.h>
+#include <linux/firmware.h>
+
+typedef enum nxt_chip_t {
+               NXTUNDEFINED,
+               NXT2002,
+               NXT2004
+}nxt_chip_type;
+
+struct nxt200x_config
+{
+       /* the demodulator's i2c address */
+       u8 demod_address;
+
+       /* tuner information */
+       u8 pll_address;
+       struct dvb_pll_desc *pll_desc;
+
+       /* used to set pll input */
+       int (*set_pll_input)(u8* buf, int input);
+
+       /* need to set device param for start_dma */
+       int (*set_ts_params)(struct dvb_frontend* fe, int is_punctured);
+};
+
+extern struct dvb_frontend* nxt200x_attach(const struct nxt200x_config* config,
+                                          struct i2c_adapter* i2c);
+
+#endif /* NXT200X_H */
+
+/*
+ * Local variables:
+ * c-basic-offset: 8
+ * End:
+ */
index fc74c40d64777a500ae7748fde5e06bfdb11a7bd..78bded861d02bb8d2c0c807bbbb9277f52cc8466 100644 (file)
@@ -468,6 +468,7 @@ static int or51132_read_signal_strength(struct dvb_frontend* fe, u16* strength)
        unsigned char snd_buf[2];
        u8 rcvr_stat;
        u16 snr_equ;
+       u32 signal_strength;
        int usK;
 
        snd_buf[0]=0x04;
@@ -503,7 +504,11 @@ static int or51132_read_signal_strength(struct dvb_frontend* fe, u16* strength)
        usK = (rcvr_stat & 0x10) ? 3 : 0;
 
         /* The value reported back from the frontend will be FFFF=100% 0000=0% */
-       *strength = (((8952 - i20Log10(snr_equ) - usK*100)/3+5)*65535)/1000;
+       signal_strength = (((8952 - i20Log10(snr_equ) - usK*100)/3+5)*65535)/1000;
+       if (signal_strength > 0xffff)
+               *strength = 0xffff;
+       else
+               *strength = signal_strength;
        dprintk("read_signal_strength %i\n",*strength);
 
        return 0;
index 8a9db23dd1b705578bffa9467e47990e06ee5a9d..531f76246e5f71bdd226632f4f908a5d8fcc60ec 100644 (file)
@@ -339,6 +339,7 @@ static int or51211_read_signal_strength(struct dvb_frontend* fe, u16* strength)
        u8 rec_buf[2];
        u8 snd_buf[4];
        u8 snr_equ;
+       u32 signal_strength;
 
        /* SNR after Equalizer */
        snd_buf[0] = 0x04;
@@ -358,8 +359,11 @@ static int or51211_read_signal_strength(struct dvb_frontend* fe, u16* strength)
        snr_equ = rec_buf[0] & 0xff;
 
        /* The value reported back from the frontend will be FFFF=100% 0000=0% */
-       *strength = (((5334 - i20Log10(snr_equ))/3+5)*65535)/1000;
-
+       signal_strength = (((5334 - i20Log10(snr_equ))/3+5)*65535)/1000;
+       if (signal_strength > 0xffff)
+               *strength = 0xffff;
+       else
+               *strength = signal_strength;
        dprintk("read_signal_strength %i\n",*strength);
 
        return 0;
index 889d9257215d733893d2deb16caed9ae66b4384d..29c48665e1309eb1e95500eac5909d663b09f4b1 100644 (file)
@@ -64,8 +64,12 @@ struct stv0299_state {
        u32 tuner_frequency;
        u32 symbol_rate;
        fe_code_rate_t fec_inner;
+       int errmode;
 };
 
+#define STATUS_BER 0
+#define STATUS_UCBLOCKS 1
+
 static int debug;
 static int debug_legacy_dish_switch;
 #define dprintk(args...) \
@@ -383,36 +387,6 @@ static int stv0299_set_voltage (struct dvb_frontend* fe, fe_sec_voltage_t voltag
        };
 }
 
-static inline s32 stv0299_calc_usec_delay (struct timeval lasttime, struct timeval curtime)
-{
-       return ((curtime.tv_usec < lasttime.tv_usec) ?
-               1000000 - lasttime.tv_usec + curtime.tv_usec :
-               curtime.tv_usec - lasttime.tv_usec);
-}
-
-static void stv0299_sleep_until (struct timeval *waketime, u32 add_usec)
-{
-       struct timeval lasttime;
-       s32 delta, newdelta;
-
-       waketime->tv_usec += add_usec;
-       if (waketime->tv_usec >= 1000000) {
-               waketime->tv_usec -= 1000000;
-               waketime->tv_sec++;
-       }
-
-       do_gettimeofday (&lasttime);
-       delta = stv0299_calc_usec_delay (lasttime, *waketime);
-       if (delta > 2500) {
-               msleep ((delta - 1500) / 1000);
-               do_gettimeofday (&lasttime);
-               newdelta = stv0299_calc_usec_delay (lasttime, *waketime);
-               delta = (newdelta > delta) ? 0 : newdelta;
-       }
-       if (delta > 0)
-               udelay (delta);
-}
-
 static int stv0299_send_legacy_dish_cmd (struct dvb_frontend* fe, u32 cmd)
 {
        struct stv0299_state* state = fe->demodulator_priv;
@@ -440,7 +414,7 @@ static int stv0299_send_legacy_dish_cmd (struct dvb_frontend* fe, u32 cmd)
                memcpy (&tv[0], &nexttime, sizeof (struct timeval));
        stv0299_writeregI (state, 0x0c, reg0x0c | 0x50); /* set LNB to 18V */
 
-       stv0299_sleep_until (&nexttime, 32000);
+       dvb_frontend_sleep_until(&nexttime, 32000);
 
        for (i=0; i<9; i++) {
                if (debug_legacy_dish_switch)
@@ -454,13 +428,13 @@ static int stv0299_send_legacy_dish_cmd (struct dvb_frontend* fe, u32 cmd)
                cmd = cmd >> 1;
 
                if (i != 8)
-                       stv0299_sleep_until (&nexttime, 8000);
+                       dvb_frontend_sleep_until(&nexttime, 8000);
        }
        if (debug_legacy_dish_switch) {
                printk ("%s(%d): switch delay (should be 32k followed by all 8k\n",
                        __FUNCTION__, fe->dvb->num);
-               for (i=1; i < 10; i++)
-                       printk ("%d: %d\n", i, stv0299_calc_usec_delay (tv[i-1] , tv[i]));
+               for (i = 1; i < 10; i++)
+                       printk ("%d: %d\n", i, timeval_usec_diff(tv[i-1] , tv[i]));
        }
 
        return 0;
@@ -517,8 +491,7 @@ static int stv0299_read_ber(struct dvb_frontend* fe, u32* ber)
 {
         struct stv0299_state* state = fe->demodulator_priv;
 
-       stv0299_writeregI(state, 0x34, (stv0299_readreg(state, 0x34) & 0xcf) | 0x10);
-       msleep(100);
+       if (state->errmode != STATUS_BER) return 0;
        *ber = (stv0299_readreg (state, 0x1d) << 8) | stv0299_readreg (state, 0x1e);
 
        return 0;
@@ -557,9 +530,8 @@ static int stv0299_read_ucblocks(struct dvb_frontend* fe, u32* ucblocks)
 {
         struct stv0299_state* state = fe->demodulator_priv;
 
-       stv0299_writeregI(state, 0x34, (stv0299_readreg(state, 0x34) & 0xcf) | 0x30);
-       msleep(100);
-       *ucblocks = (stv0299_readreg (state, 0x1d) << 8) | stv0299_readreg (state, 0x1e);
+       if (state->errmode != STATUS_UCBLOCKS) *ucblocks = 0;
+       else *ucblocks = (stv0299_readreg (state, 0x1d) << 8) | stv0299_readreg (state, 0x1e);
 
        return 0;
 }
@@ -581,49 +553,14 @@ static int stv0299_set_frontend(struct dvb_frontend* fe, struct dvb_frontend_par
        if (state->config->invert) invval = (~invval) & 1;
        stv0299_writeregI(state, 0x0c, (stv0299_readreg(state, 0x0c) & 0xfe) | invval);
 
-       if (state->config->enhanced_tuning) {
-               /* check if we should do a finetune */
-               int frequency_delta = p->frequency - state->tuner_frequency;
-               int minmax = p->u.qpsk.symbol_rate / 2000;
-               if (minmax < 5000) minmax = 5000;
-
-               if ((frequency_delta > -minmax) && (frequency_delta < minmax) && (frequency_delta != 0) &&
-                   (state->fec_inner == p->u.qpsk.fec_inner) &&
-                   (state->symbol_rate == p->u.qpsk.symbol_rate)) {
-                       int Drot_freq = (frequency_delta << 16) / (state->config->mclk / 1000);
-
-                       // zap the derotator registers first
-                       stv0299_writeregI(state, 0x22, 0x00);
-                       stv0299_writeregI(state, 0x23, 0x00);
-
-                       // now set them as we want
-                       stv0299_writeregI(state, 0x22, Drot_freq >> 8);
-                       stv0299_writeregI(state, 0x23, Drot_freq);
-               } else {
-                       /* A "normal" tune is requested */
-                       stv0299_writeregI(state, 0x05, 0xb5);   /*  enable i2c repeater on stv0299  */
-                       state->config->pll_set(fe, state->i2c, p);
-                       stv0299_writeregI(state, 0x05, 0x35);   /*  disable i2c repeater on stv0299  */
-
-                       stv0299_writeregI(state, 0x32, 0x80);
-                       stv0299_writeregI(state, 0x22, 0x00);
-                       stv0299_writeregI(state, 0x23, 0x00);
-                       stv0299_writeregI(state, 0x32, 0x19);
-                       stv0299_set_symbolrate (fe, p->u.qpsk.symbol_rate);
-                       stv0299_set_FEC (state, p->u.qpsk.fec_inner);
-               }
-       } else {
-               stv0299_writeregI(state, 0x05, 0xb5);   /*  enable i2c repeater on stv0299  */
-               state->config->pll_set(fe, state->i2c, p);
-               stv0299_writeregI(state, 0x05, 0x35);   /*  disable i2c repeater on stv0299  */
+       stv0299_writeregI(state, 0x05, 0xb5);   /*  enable i2c repeater on stv0299  */
+       state->config->pll_set(fe, state->i2c, p);
+       stv0299_writeregI(state, 0x05, 0x35);   /*  disable i2c repeater on stv0299  */
 
-               stv0299_set_FEC (state, p->u.qpsk.fec_inner);
-               stv0299_set_symbolrate (fe, p->u.qpsk.symbol_rate);
-               stv0299_writeregI(state, 0x22, 0x00);
-               stv0299_writeregI(state, 0x23, 0x00);
-               stv0299_readreg (state, 0x23);
-               stv0299_writeregI(state, 0x12, 0xb9);
-       }
+       stv0299_set_FEC (state, p->u.qpsk.fec_inner);
+       stv0299_set_symbolrate (fe, p->u.qpsk.symbol_rate);
+       stv0299_writeregI(state, 0x22, 0x00);
+       stv0299_writeregI(state, 0x23, 0x00);
 
        state->tuner_frequency = p->frequency;
        state->fec_inner = p->u.qpsk.fec_inner;
@@ -708,6 +645,7 @@ struct dvb_frontend* stv0299_attach(const struct stv0299_config* config,
        state->tuner_frequency = 0;
        state->symbol_rate = 0;
        state->fec_inner = 0;
+       state->errmode = STATUS_BER;
 
        /* check if the demod is there */
        stv0299_writeregI(state, 0x02, 0x34); /* standby off */
index d0c4484861e19dccd740ff361e0f0967807bc206..9af3d71c89dbe9a6c5e5a90f54fe6bdd6f2c692f 100644 (file)
@@ -73,9 +73,6 @@ struct stv0299_config
        /* does the inversion require inversion? */
        u8 invert:1;
 
-       /* Should the enhanced tuning code be used? */
-       u8 enhanced_tuning:1;
-
        /* Skip reinitialisation? */
        u8 skip_reinit:1;
 
index 3529c618f8287f3de6101ecf3e48dfa965c1f8c0..7968743826fc50072d3a968baf4a76011cd03525 100644 (file)
@@ -420,7 +420,7 @@ static void tda10046_init_plls(struct dvb_frontend* fe)
        struct tda1004x_state* state = fe->demodulator_priv;
 
        tda1004x_write_byteI(state, TDA10046H_CONFPLL1, 0xf0);
-       tda1004x_write_byteI(state, TDA10046H_CONFPLL2, 10); // PLL M = 10
+       tda1004x_write_byteI(state, TDA10046H_CONFPLL2, 0x0a); // PLL M = 10
        if (state->config->xtal_freq == TDA10046_XTAL_4M ) {
                dprintk("%s: setting up PLLs for a 4 MHz Xtal\n", __FUNCTION__);
                tda1004x_write_byteI(state, TDA10046H_CONFPLL3, 0); // PLL P = N = 0
@@ -597,7 +597,10 @@ static int tda10046_init(struct dvb_frontend* fe)
        // Init the tuner PLL
        if (state->config->pll_init) {
                tda1004x_enable_tuner_i2c(state);
-               state->config->pll_init(fe);
+               if (state->config->pll_init(fe)) {
+                       printk(KERN_ERR "tda1004x: pll init failed\n");
+                       return  -EIO;
+               }
                tda1004x_disable_tuner_i2c(state);
        }
 
@@ -667,7 +670,10 @@ static int tda1004x_set_fe(struct dvb_frontend* fe,
 
        // set frequency
        tda1004x_enable_tuner_i2c(state);
-       state->config->pll_set(fe, fe_params);
+       if (state->config->pll_set(fe, fe_params)) {
+               printk(KERN_ERR "tda1004x: pll set failed\n");
+               return  -EIO;
+       }
        tda1004x_disable_tuner_i2c(state);
 
        // Hardcoded to use auto as much as possible on the TDA10045 as it
@@ -832,6 +838,8 @@ static int tda1004x_set_fe(struct dvb_frontend* fe,
 
        case TDA1004X_DEMOD_TDA10046:
                tda1004x_write_mask(state, TDA1004X_AUTO, 0x40, 0x40);
+               msleep(1);
+               tda1004x_write_mask(state, TDA10046H_AGC_CONF, 4, 1);
                break;
        }
 
@@ -1129,7 +1137,12 @@ static int tda1004x_sleep(struct dvb_frontend* fe)
                if (state->config->pll_sleep != NULL) {
                        tda1004x_enable_tuner_i2c(state);
                        state->config->pll_sleep(fe);
-                       tda1004x_disable_tuner_i2c(state);
+                       if (state->config->if_freq != TDA10046_FREQ_052) {
+                               /* special hack for Philips EUROPA Based boards:
+                                * keep the I2c bridge open for tuner access in analog mode
+                                */
+                               tda1004x_disable_tuner_i2c(state);
+                       }
                }
                tda1004x_write_mask(state, TDA1004X_CONFC4, 1, 1);
                break;
index 85b437bbddcdaed624b6a1389dafd982b5560c07..bbebd1c4caca575fb7cd0890e30105bd68ae7b34 100644 (file)
@@ -286,15 +286,10 @@ static void pluto_dma_end(struct pluto *pluto, unsigned int nbpackets)
         *     although one packet has been transfered.
         */
        if ((nbpackets == 0) || (nbpackets > TS_DMA_PACKETS)) {
-               unsigned int i = 0, valid;
+               unsigned int i = 0;
                while (pluto->dma_buf[i] == 0x47)
                        i += 188;
-               valid = i / 188;
-               if (nbpackets != valid) {
-                       dev_err(&pluto->pdev->dev, "nbpackets=%u valid=%u\n",
-                                       nbpackets, valid);
-                       nbpackets = valid;
-               }
+               nbpackets = i / 188;
        }
 
        dvb_dmx_swfilter_packets(&pluto->demux, pluto->dma_buf, nbpackets);
index 22b203f8ff27a42b0693ef8061e8dda1c0c8c007..87ea52757a2171243bb7e543d22506ea35a8cb02 100644 (file)
@@ -1566,7 +1566,7 @@ static u8 alps_bsru6_inittab[] = {
        0x0e, 0x23,   /* alpha_tmg = 2, beta_tmg = 3 */
        0x10, 0x3f,   // AGC2  0x3d
        0x11, 0x84,
-       0x12, 0xb5,   // Lock detect: -64  Carrier freq detect:on
+       0x12, 0xb9,
        0x15, 0xc9,   // lock detector threshold
        0x16, 0x00,
        0x17, 0x00,
@@ -1644,7 +1644,6 @@ static struct stv0299_config alps_bsru6_config = {
        .inittab = alps_bsru6_inittab,
        .mclk = 88000000UL,
        .invert = 1,
-       .enhanced_tuning = 0,
        .skip_reinit = 0,
        .lock_output = STV0229_LOCKOUTPUT_1,
        .volt13_op0_op1 = STV0299_VOLT13_OP1,
@@ -1669,7 +1668,7 @@ static u8 alps_bsbe1_inittab[] = {
        0x0e, 0x23,   /* alpha_tmg = 2, beta_tmg = 3 */
        0x10, 0x3f,   // AGC2  0x3d
        0x11, 0x84,
-       0x12, 0xb5,   // Lock detect: -64  Carrier freq detect:on
+       0x12, 0xb9,
        0x15, 0xc9,   // lock detector threshold
        0x16, 0x00,
        0x17, 0x00,
@@ -1721,7 +1720,6 @@ static struct stv0299_config alps_bsbe1_config = {
        .inittab = alps_bsbe1_inittab,
        .mclk = 88000000UL,
        .invert = 1,
-       .enhanced_tuning = 0,
        .skip_reinit = 0,
        .min_delay_ms = 100,
        .set_symbol_rate = alps_bsru6_set_symbol_rate,
index 7692cd23f839cb13fb865c25196b179aa1f279c2..aa75dc03a0b3ae082179ff5c01a4ad2aa52b84bf 100644 (file)
@@ -499,7 +499,7 @@ static u8 typhoon_cinergy1200s_inittab[] = {
        0x0e, 0x23,             /* alpha_tmg = 2, beta_tmg = 3 */
        0x10, 0x3f,             // AGC2  0x3d
        0x11, 0x84,
-       0x12, 0xb5,             // Lock detect: -64  Carrier freq detect:on
+       0x12, 0xb9,
        0x15, 0xc9,             // lock detector threshold
        0x16, 0x00,
        0x17, 0x00,
@@ -531,7 +531,6 @@ static struct stv0299_config typhoon_config = {
        .inittab = typhoon_cinergy1200s_inittab,
        .mclk = 88000000UL,
        .invert = 0,
-       .enhanced_tuning = 0,
        .skip_reinit = 0,
        .lock_output = STV0229_LOCKOUTPUT_1,
        .volt13_op0_op1 = STV0299_VOLT13_OP0,
@@ -546,7 +545,6 @@ static struct stv0299_config cinergy_1200s_config = {
        .inittab = typhoon_cinergy1200s_inittab,
        .mclk = 88000000UL,
        .invert = 0,
-       .enhanced_tuning = 0,
        .skip_reinit = 0,
        .lock_output = STV0229_LOCKOUTPUT_0,
        .volt13_op0_op1 = STV0299_VOLT13_OP0,
index 51c30ba68140acd5d636d63f644b14e4a54b831b..75fb92d60998128ff1ad9f08e56fe1cb153be8f6 100644 (file)
@@ -490,7 +490,7 @@ static u8 alps_bsru6_inittab[] = {
        0x0e, 0x23,             /* alpha_tmg = 2, beta_tmg = 3 */
        0x10, 0x3f,             // AGC2  0x3d
        0x11, 0x84,
-       0x12, 0xb5,             // Lock detect: -64  Carrier freq detect:on
+       0x12, 0xb9,
        0x15, 0xc9,             // lock detector threshold
        0x16, 0x00,
        0x17, 0x00,
@@ -580,7 +580,6 @@ static struct stv0299_config alps_bsru6_config = {
        .inittab = alps_bsru6_inittab,
        .mclk = 88000000UL,
        .invert = 1,
-       .enhanced_tuning = 0,
        .skip_reinit = 0,
        .lock_output = STV0229_LOCKOUTPUT_1,
        .volt13_op0_op1 = STV0299_VOLT13_OP1,
@@ -710,7 +709,6 @@ static struct stv0299_config philips_su1278_tt_config = {
        .inittab = philips_su1278_tt_inittab,
        .mclk = 64000000UL,
        .invert = 0,
-       .enhanced_tuning = 1,
        .skip_reinit = 1,
        .lock_output = STV0229_LOCKOUTPUT_1,
        .volt13_op0_op1 = STV0299_VOLT13_OP1,
index b1f21ef0e3b39ec6b3f2229608e0d04f22430af3..755df81cbc49af739387b8a7e42cc8f0b41df35d 100644 (file)
@@ -305,7 +305,7 @@ static u8 alps_bsru6_inittab[] = {
        0x0e, 0x23,   /* alpha_tmg = 2, beta_tmg = 3 */
        0x10, 0x3f,   // AGC2  0x3d
        0x11, 0x84,
-       0x12, 0xb5,   // Lock detect: -64  Carrier freq detect:on
+       0x12, 0xb9,
        0x15, 0xc9,   // lock detector threshold
        0x16, 0x00,
        0x17, 0x00,
@@ -379,7 +379,6 @@ static struct stv0299_config alps_bsru6_config = {
        .inittab = alps_bsru6_inittab,
        .mclk = 88000000UL,
        .invert = 1,
-       .enhanced_tuning = 0,
        .skip_reinit = 0,
        .lock_output = STV0229_LOCKOUTPUT_1,
        .volt13_op0_op1 = STV0299_VOLT13_OP1,
index 43d6c8268642b5670a5fe40bb4c828b5e1c8ff96..4fd8bbc47037e7e8effa17ee5a2a4d80aef14bbc 100644 (file)
@@ -226,12 +226,14 @@ static int lnbp21_enable_high_lnb_voltage(struct dvb_frontend* fe, int arg)
        return 0;
 }
 
-static void lnbp21_init(struct budget* budget)
+static int lnbp21_init(struct budget* budget)
 {
        u8 buf = 0x00;
        struct i2c_msg msg = { .addr = 0x08, .flags = 0, .buf = &buf, .len = sizeof(buf) };
 
-       i2c_transfer (&budget->i2c_adap, &msg, 1);
+       if (i2c_transfer (&budget->i2c_adap, &msg, 1) != 1)
+               return -EIO;
+       return 0;
 }
 
 static int alps_bsrv2_pll_set(struct dvb_frontend* fe, struct dvb_frontend_parameters* params)
@@ -273,7 +275,7 @@ static u8 alps_bsru6_inittab[] = {
        0x01, 0x15,
        0x02, 0x00,
        0x03, 0x00,
-        0x04, 0x7d,   /* F22FR = 0x7d, F22 = f_VCO / 128 / 0x7d = 22 kHz */
+       0x04, 0x7d,   /* F22FR = 0x7d, F22 = f_VCO / 128 / 0x7d = 22 kHz */
        0x05, 0x35,   /* I2CT = 0, SCLT = 1, SDAT = 1 */
        0x06, 0x40,   /* DAC not used, set to high impendance mode */
        0x07, 0x00,   /* DAC LSB */
@@ -284,7 +286,7 @@ static u8 alps_bsru6_inittab[] = {
        0x0e, 0x23,   /* alpha_tmg = 2, beta_tmg = 3 */
        0x10, 0x3f,   // AGC2  0x3d
        0x11, 0x84,
-       0x12, 0xb5,   // Lock detect: -64  Carrier freq detect:on
+       0x12, 0xb9,
        0x15, 0xc9,   // lock detector threshold
        0x16, 0x00,
        0x17, 0x00,
@@ -358,7 +360,6 @@ static struct stv0299_config alps_bsru6_config = {
        .inittab = alps_bsru6_inittab,
        .mclk = 88000000UL,
        .invert = 1,
-       .enhanced_tuning = 0,
        .skip_reinit = 0,
        .lock_output = STV0229_LOCKOUTPUT_1,
        .volt13_op0_op1 = STV0299_VOLT13_OP1,
@@ -367,6 +368,79 @@ static struct stv0299_config alps_bsru6_config = {
        .pll_set = alps_bsru6_pll_set,
 };
 
+static u8 alps_bsbe1_inittab[] = {
+       0x01, 0x15,
+       0x02, 0x30,
+       0x03, 0x00,
+       0x04, 0x7d,  /* F22FR = 0x7d, F22 = f_VCO / 128 / 0x7d = 22 kHz */
+       0x05, 0x35,  /* I2CT = 0, SCLT = 1, SDAT = 1 */
+       0x06, 0x40,  /* DAC not used, set to high impendance mode */
+       0x07, 0x00,  /* DAC LSB */
+       0x08, 0x40,  /* DiSEqC off, LNB power on OP2/LOCK pin on */
+       0x09, 0x00,  /* FIFO */
+       0x0c, 0x51,  /* OP1 ctl = Normal, OP1 val = 1 (LNB Power ON) */
+       0x0d, 0x82,  /* DC offset compensation = ON, beta_agc1 = 2 */
+       0x0e, 0x23,  /* alpha_tmg = 2, beta_tmg = 3 */
+       0x10, 0x3f,  // AGC2 0x3d
+       0x11, 0x84,
+       0x12, 0xb9,
+       0x15, 0xc9,  // lock detector threshold
+       0x16, 0x00,
+       0x17, 0x00,
+       0x18, 0x00,
+       0x19, 0x00,
+       0x1a, 0x00,
+       0x1f, 0x50,
+       0x20, 0x00,
+       0x21, 0x00,
+       0x22, 0x00,
+       0x23, 0x00,
+       0x28, 0x00, // out imp: normal out type: parallel FEC mode:0
+       0x29, 0x1e, // 1/2 threshold
+       0x2a, 0x14, // 2/3 threshold
+       0x2b, 0x0f, // 3/4 threshold
+       0x2c, 0x09, // 5/6 threshold
+       0x2d, 0x05, // 7/8 threshold
+       0x2e, 0x01,
+       0x31, 0x1f, // test all FECs
+       0x32, 0x19, // viterbi and synchro search
+       0x33, 0xfc, // rs control
+       0x34, 0x93, // error control
+       0x0f, 0x92, // 0x80 = inverse AGC
+       0xff, 0xff
+};
+
+static int alps_bsbe1_pll_set(struct dvb_frontend* fe, struct i2c_adapter *i2c, struct dvb_frontend_parameters* params)
+{
+       int ret;
+       u8 data[4];
+       u32 div;
+       struct i2c_msg msg = { .addr = 0x61, .flags = 0, .buf = data, .len = sizeof(data) };
+
+       if ((params->frequency < 950000) || (params->frequency > 2150000))
+               return -EINVAL;
+
+       div = (params->frequency + (125 - 1)) / 125; // round correctly
+       data[0] = (div >> 8) & 0x7f;
+       data[1] = div & 0xff;
+       data[2] = 0x80 | ((div & 0x18000) >> 10) | 4;
+       data[3] = (params->frequency > 1530000) ? 0xE0 : 0xE4;
+
+       ret = i2c_transfer(i2c, &msg, 1);
+       return (ret != 1) ? -EIO : 0;
+}
+
+static struct stv0299_config alps_bsbe1_config = {
+       .demod_address = 0x68,
+       .inittab = alps_bsbe1_inittab,
+       .mclk = 88000000UL,
+       .invert = 1,
+       .skip_reinit = 0,
+       .min_delay_ms = 100,
+       .set_symbol_rate = alps_bsru6_set_symbol_rate,
+       .pll_set = alps_bsbe1_pll_set,
+};
+
 static int alps_tdbe2_pll_set(struct dvb_frontend* fe, struct dvb_frontend_parameters* params)
 {
        struct budget* budget = (struct budget*) fe->dvb->priv;
@@ -500,6 +574,19 @@ static u8 read_pwm(struct budget* budget)
 static void frontend_init(struct budget *budget)
 {
        switch(budget->dev->pci->subsystem_device) {
+       case 0x1017:
+               // try the ALPS BSBE1 now
+               budget->dvb_frontend = stv0299_attach(&alps_bsbe1_config, &budget->i2c_adap);
+               if (budget->dvb_frontend) {
+                       budget->dvb_frontend->ops->set_voltage = lnbp21_set_voltage;
+                       budget->dvb_frontend->ops->enable_high_lnb_voltage = lnbp21_enable_high_lnb_voltage;
+                       if (lnbp21_init(budget)) {
+                               printk("%s: No LNBP21 found!\n", __FUNCTION__);
+                               goto error_out;
+                       }
+               }
+
+               break;
        case 0x1003: // Hauppauge/TT Nova budget (stv0299/ALPS BSRU6(tsa5059) OR ves1893/ALPS BSRV2(sp5659))
        case 0x1013:
                // try the ALPS BSRV2 first of all
@@ -554,7 +641,10 @@ static void frontend_init(struct budget *budget)
                if (budget->dvb_frontend) {
                        budget->dvb_frontend->ops->set_voltage = lnbp21_set_voltage;
                        budget->dvb_frontend->ops->enable_high_lnb_voltage = lnbp21_enable_high_lnb_voltage;
-                       lnbp21_init(budget);
+                       if (lnbp21_init(budget)) {
+                               printk("%s: No LNBP21 found!\n", __FUNCTION__);
+                               goto error_out;
+                       }
                        break;
                }
        }
@@ -566,13 +656,17 @@ static void frontend_init(struct budget *budget)
                       budget->dev->pci->subsystem_vendor,
                       budget->dev->pci->subsystem_device);
        } else {
-               if (dvb_register_frontend(&budget->dvb_adapter, budget->dvb_frontend)) {
-                       printk("budget: Frontend registration failed!\n");
-                       if (budget->dvb_frontend->ops->release)
-                               budget->dvb_frontend->ops->release(budget->dvb_frontend);
-                       budget->dvb_frontend = NULL;
-               }
+               if (dvb_register_frontend(&budget->dvb_adapter, budget->dvb_frontend))
+                       goto error_out;
        }
+       return;
+
+error_out:
+       printk("budget: Frontend registration failed!\n");
+       if (budget->dvb_frontend->ops->release)
+               budget->dvb_frontend->ops->release(budget->dvb_frontend);
+       budget->dvb_frontend = NULL;
+       return;
 }
 
 static int budget_attach (struct saa7146_dev* dev, struct saa7146_pci_extension_data *info)
@@ -618,6 +712,7 @@ static int budget_detach (struct saa7146_dev* dev)
 
 static struct saa7146_extension budget_extension;
 
+MAKE_BUDGET_INFO(ttbs2, "TT-Budget/WinTV-NOVA-S PCI (rev AL/alps bsbe1 lnbp21 frontend)", BUDGET_TT);
 MAKE_BUDGET_INFO(ttbs, "TT-Budget/WinTV-NOVA-S  PCI",  BUDGET_TT);
 MAKE_BUDGET_INFO(ttbc, "TT-Budget/WinTV-NOVA-C  PCI",  BUDGET_TT);
 MAKE_BUDGET_INFO(ttbt, "TT-Budget/WinTV-NOVA-T  PCI",  BUDGET_TT);
@@ -630,6 +725,7 @@ static struct pci_device_id pci_tbl[] = {
        MAKE_EXTENSION_PCI(ttbc,  0x13c2, 0x1004),
        MAKE_EXTENSION_PCI(ttbt,  0x13c2, 0x1005),
        MAKE_EXTENSION_PCI(satel, 0x13c2, 0x1013),
+       MAKE_EXTENSION_PCI(ttbs2, 0x13c2, 0x1017),
        MAKE_EXTENSION_PCI(ttbs,  0x13c2, 0x1016),
        MAKE_EXTENSION_PCI(fsacs1,0x1131, 0x4f60),
        MAKE_EXTENSION_PCI(fsacs0,0x1131, 0x4f61),
index d200ab0ad9e7fbf05c5d3225aabe1add5988c71c..fd53d6010502fa54d108769b06ea01060da92772 100644 (file)
@@ -1198,7 +1198,7 @@ static u8 alps_bsbe1_inittab[] = {
         0x0e, 0x23,             /* alpha_tmg = 2, beta_tmg = 3 */
         0x10, 0x3f,             // AGC2  0x3d
         0x11, 0x84,
-        0x12, 0xb5,             // Lock detect: -64  Carrier freq detect:on
+        0x12, 0xb9,
         0x15, 0xc9,             // lock detector threshold
         0x16, 0x00,
         0x17, 0x00,
@@ -1240,7 +1240,7 @@ static u8 alps_bsru6_inittab[] = {
        0x0e, 0x23,             /* alpha_tmg = 2, beta_tmg = 3 */
        0x10, 0x3f,             // AGC2  0x3d
        0x11, 0x84,
-       0x12, 0xb5,             // Lock detect: -64  Carrier freq detect:on
+       0x12, 0xb9,
        0x15, 0xc9,             // lock detector threshold
        0x16, 0x00,
        0x17, 0x00,
@@ -1335,7 +1335,6 @@ static struct stv0299_config alps_stv0299_config = {
        .inittab = alps_bsru6_inittab,
        .mclk = 88000000UL,
        .invert = 1,
-       .enhanced_tuning = 0,
        .skip_reinit = 0,
        .lock_output = STV0229_LOCKOUTPUT_1,
        .volt13_op0_op1 = STV0299_VOLT13_OP1,
index bbb989df4cf05dbfd62a883a2d539a443cd0ae30..199b01188858325e169adb8f9a3e5caa6fc509bf 100644 (file)
@@ -25,6 +25,16 @@ config VIDEO_BT848
          To compile this driver as a module, choose M here: the
          module will be called bttv.
 
+config VIDEO_BT848_DVB
+       tristate "DVB/ATSC Support for bt878 based TV cards"
+       depends on VIDEO_BT848 && DVB_CORE
+       select DVB_BT8XX
+       ---help---
+         This adds support for DVB/ATSC cards based on the BT878 chip.
+
+         To compile this driver as a module, choose M here: the
+         module will be called dvb-bt8xx.
+
 config VIDEO_SAA6588
        tristate "SAA6588 Radio Chip RDS decoder support on BT848 cards"
        depends on VIDEO_DEV && I2C && VIDEO_BT848
@@ -243,29 +253,7 @@ config VIDEO_MEYE
          To compile this driver as a module, choose M here: the
          module will be called meye.
 
-config VIDEO_SAA7134
-       tristate "Philips SAA7134 support"
-       depends on VIDEO_DEV && PCI && I2C && SOUND
-       select VIDEO_BUF
-       select VIDEO_IR
-       select VIDEO_TUNER
-       select CRC32
-       ---help---
-         This is a video4linux driver for Philips SAA7130/7134 based
-         TV cards.
-
-         To compile this driver as a module, choose M here: the
-         module will be called saa7134.
-
-config VIDEO_SAA7134_DVB
-       tristate "DVB Support for saa7134 based TV cards"
-       depends on VIDEO_SAA7134 && DVB_CORE
-       select VIDEO_BUF_DVB
-       select DVB_MT352
-       select DVB_TDA1004X
-       ---help---
-         This adds support for DVB cards based on the
-         Philips saa7134 chip.
+source "drivers/media/video/saa7134/Kconfig"
 
 config VIDEO_MXB
        tristate "Siemens-Nixdorf 'Multimedia eXtension Board'"
@@ -316,34 +304,9 @@ config VIDEO_HEXIUM_GEMINI
          To compile this driver as a module, choose M here: the
          module will be called hexium_gemini.
 
-config VIDEO_CX88
-       tristate "Conexant 2388x (bt878 successor) support"
-       depends on VIDEO_DEV && PCI && I2C && EXPERIMENTAL
-       select I2C_ALGOBIT
-       select FW_LOADER
-       select VIDEO_BTCX
-       select VIDEO_BUF
-       select VIDEO_TUNER
-       select VIDEO_TVEEPROM
-       select VIDEO_IR
-       ---help---
-         This is a video4linux driver for Conexant 2388x based
-         TV cards.
+source "drivers/media/video/cx88/Kconfig"
 
-         To compile this driver as a module, choose M here: the
-         module will be called cx8800
-
-config VIDEO_CX88_DVB
-       tristate "DVB Support for cx2388x based TV cards"
-       depends on VIDEO_CX88 && DVB_CORE
-       select VIDEO_BUF_DVB
-       select DVB_MT352
-       select DVB_OR51132
-       select DVB_CX22702
-       select DVB_LGDT330X
-       ---help---
-         This adds support for DVB/ATSC cards based on the
-         Connexant 2388x chip.
+source "drivers/media/video/em28xx/Kconfig"
 
 config VIDEO_OVCAMCHIP
        tristate "OmniVision Camera Chip support"
index 046b82de92859c52e92812ed4235f2cdd7a8ff4a..3ac465992400b12ab438ffca5306d59c73fbca65 100644 (file)
@@ -5,7 +5,6 @@
 bttv-objs      :=      bttv-driver.o bttv-cards.o bttv-if.o \
                        bttv-risc.o bttv-vbi.o bttv-i2c.o bttv-gpio.o
 zoran-objs      :=     zr36120.o zr36120_i2c.o zr36120_mem.o
-rds-objs        :=     saa6588.o
 zr36067-objs   :=      zoran_procfs.o zoran_device.o \
                        zoran_driver.o zoran_card.o
 tuner-objs     :=      tuner-core.o tuner-simple.o mt20xx.o tda8290.o tea5767.o
@@ -16,7 +15,7 @@ obj-$(CONFIG_VIDEO_BT848) += bttv.o msp3400.o tvaudio.o \
 obj-$(CONFIG_SOUND_TVMIXER) += tvmixer.o
 
 obj-$(CONFIG_VIDEO_ZR36120) += zoran.o
-obj-$(CONFIG_VIDEO_SAA6588) += rds.o
+obj-$(CONFIG_VIDEO_SAA6588) += saa6588.o
 obj-$(CONFIG_VIDEO_SAA5246A) += saa5246a.o
 obj-$(CONFIG_VIDEO_SAA5249) += saa5249.o
 obj-$(CONFIG_VIDEO_CQCAM) += c-qcam.o
@@ -39,6 +38,8 @@ obj-$(CONFIG_VIDEO_CPIA_USB) += cpia_usb.o
 obj-$(CONFIG_VIDEO_MEYE) += meye.o
 obj-$(CONFIG_VIDEO_SAA7134) += saa7134/
 obj-$(CONFIG_VIDEO_CX88) += cx88/
+obj-$(CONFIG_VIDEO_EM28XX) += em28xx/
+obj-$(CONFIG_VIDEO_EM28XX) += saa711x.o tvp5150.o
 obj-$(CONFIG_VIDEO_OVCAMCHIP) += ovcamchip/
 obj-$(CONFIG_VIDEO_MXB) += saa7111.o tuner.o tda9840.o tea6415c.o tea6420.o mxb.o
 obj-$(CONFIG_VIDEO_HEXIUM_ORION) += hexium_orion.o
index 0823ddaf70049a0daa625196da95b80662f49fe0..881cdcb1875d3f6dce6f9200065e27fe502738f7 100644 (file)
@@ -22,7 +22,6 @@
 #include <linux/init.h>
 #include <linux/devfs_fs_kernel.h>
 #include <linux/module.h>
-#include <linux/version.h>
 #include <linux/delay.h>
 #include <linux/errno.h>
 #include <linux/fs.h>
index 76c1b63ebdf27b4eb78c47cdd8a4d74065ca62dc..e4063950ae57d7782ac7ce8d6d71f862acf55372 100644 (file)
@@ -32,7 +32,6 @@
 #include <linux/slab.h>
 
 #include <media/audiochip.h>
-#include <media/id.h>
 #include "bttv.h"
 #include "bt832.h"
 
@@ -54,36 +53,36 @@ static struct i2c_driver driver;
 static struct i2c_client client_template;
 
 struct bt832 {
-        struct i2c_client client;
+       struct i2c_client client;
 };
 
 int bt832_hexdump(struct i2c_client *i2c_client_s, unsigned char *buf)
 {
        int i,rc;
        buf[0]=0x80; // start at register 0 with auto-increment
-        if (1 != (rc = i2c_master_send(i2c_client_s,buf,1)))
-                printk("bt832: i2c i/o error: rc == %d (should be 1)\n",rc);
+       if (1 != (rc = i2c_master_send(i2c_client_s,buf,1)))
+               printk("bt832: i2c i/o error: rc == %d (should be 1)\n",rc);
 
-        for(i=0;i<65;i++)
-                buf[i]=0;
-        if (65 != (rc=i2c_master_recv(i2c_client_s,buf,65)))
-                printk("bt832: i2c i/o error: rc == %d (should be 65)\n",rc);
+       for(i=0;i<65;i++)
+               buf[i]=0;
+       if (65 != (rc=i2c_master_recv(i2c_client_s,buf,65)))
+               printk("bt832: i2c i/o error: rc == %d (should be 65)\n",rc);
 
-        // Note: On READ the first byte is the current index
-        //  (e.g. 0x80, what we just wrote)
+       // Note: On READ the first byte is the current index
+       //  (e.g. 0x80, what we just wrote)
 
-        if(1) {
-                int i;
-                printk("BT832 hexdump:\n");
-                for(i=1;i<65;i++) {
+       if(1) {
+               int i;
+               printk("BT832 hexdump:\n");
+               for(i=1;i<65;i++) {
                        if(i!=1) {
                          if(((i-1)%8)==0) printk(" ");
-                          if(((i-1)%16)==0) printk("\n");
+                         if(((i-1)%16)==0) printk("\n");
                        }
-                        printk(" %02x",buf[i]);
-                }
-                printk("\n");
-        }
+                       printk(" %02x",buf[i]);
+               }
+               printk("\n");
+       }
        return 0;
 }
 
@@ -102,13 +101,13 @@ int bt832_init(struct i2c_client *i2c_client_s)
                return 0;
        }
 
-        printk("Write 0 tp VPSTATUS\n");
-        buf[0]=BT832_VP_STATUS; // Reg.52
-        buf[1]= 0x00;
-        if (2 != (rc = i2c_master_send(i2c_client_s,buf,2)))
-                printk("bt832: i2c i/o error VPS: rc == %d (should be 2)\n",rc);
+       printk("Write 0 tp VPSTATUS\n");
+       buf[0]=BT832_VP_STATUS; // Reg.52
+       buf[1]= 0x00;
+       if (2 != (rc = i2c_master_send(i2c_client_s,buf,2)))
+               printk("bt832: i2c i/o error VPS: rc == %d (should be 2)\n",rc);
 
-        bt832_hexdump(i2c_client_s,buf);
+       bt832_hexdump(i2c_client_s,buf);
 
 
        // Leave low power mode:
@@ -116,17 +115,17 @@ int bt832_init(struct i2c_client *i2c_client_s)
        buf[0]=BT832_CAM_SETUP0; //0x39 57
        buf[1]=0x08;
        if (2 != (rc = i2c_master_send(i2c_client_s,buf,2)))
-                printk("bt832: i2c i/o error LLPM: rc == %d (should be 2)\n",rc);
+               printk("bt832: i2c i/o error LLPM: rc == %d (should be 2)\n",rc);
 
-        bt832_hexdump(i2c_client_s,buf);
+       bt832_hexdump(i2c_client_s,buf);
 
        printk("Write 0 tp VPSTATUS\n");
-        buf[0]=BT832_VP_STATUS; // Reg.52
-        buf[1]= 0x00;
-        if (2 != (rc = i2c_master_send(i2c_client_s,buf,2)))
-                printk("bt832: i2c i/o error VPS: rc == %d (should be 2)\n",rc);
+       buf[0]=BT832_VP_STATUS; // Reg.52
+       buf[1]= 0x00;
+       if (2 != (rc = i2c_master_send(i2c_client_s,buf,2)))
+               printk("bt832: i2c i/o error VPS: rc == %d (should be 2)\n",rc);
 
-        bt832_hexdump(i2c_client_s,buf);
+       bt832_hexdump(i2c_client_s,buf);
 
 
        // Enable Output
@@ -134,22 +133,22 @@ int bt832_init(struct i2c_client *i2c_client_s)
        buf[0]=BT832_VP_CONTROL1; // Reg.40
        buf[1]= 0x27 & (~0x01); // Default | !skip
        if (2 != (rc = i2c_master_send(i2c_client_s,buf,2)))
-                printk("bt832: i2c i/o error EO: rc == %d (should be 2)\n",rc);
+               printk("bt832: i2c i/o error EO: rc == %d (should be 2)\n",rc);
 
-        bt832_hexdump(i2c_client_s,buf);
+       bt832_hexdump(i2c_client_s,buf);
 
 
        // for testing (even works when no camera attached)
        printk("bt832: *** Generate NTSC M Bars *****\n");
        buf[0]=BT832_VP_TESTCONTROL0; // Reg. 42
        buf[1]=3; // Generate NTSC System M bars, Generate Frame timing internally
-        if (2 != (rc = i2c_master_send(i2c_client_s,buf,2)))
-                printk("bt832: i2c i/o error MBAR: rc == %d (should be 2)\n",rc);
+       if (2 != (rc = i2c_master_send(i2c_client_s,buf,2)))
+               printk("bt832: i2c i/o error MBAR: rc == %d (should be 2)\n",rc);
 
        printk("Bt832: Camera Present: %s\n",
                (buf[1+BT832_CAM_STATUS] & BT832_56_CAMERA_PRESENT) ? "yes":"no");
 
-        bt832_hexdump(i2c_client_s,buf);
+       bt832_hexdump(i2c_client_s,buf);
        kfree(buf);
        return 1;
 }
@@ -162,17 +161,17 @@ static int bt832_attach(struct i2c_adapter *adap, int addr, int kind)
 
        printk("bt832_attach\n");
 
-        client_template.adapter = adap;
-        client_template.addr    = addr;
+       client_template.adapter = adap;
+       client_template.addr    = addr;
 
-        printk("bt832: chip found @ 0x%x\n", addr<<1);
+       printk("bt832: chip found @ 0x%x\n", addr<<1);
 
-        if (NULL == (t = kmalloc(sizeof(*t), GFP_KERNEL)))
-                return -ENOMEM;
+       if (NULL == (t = kmalloc(sizeof(*t), GFP_KERNEL)))
+               return -ENOMEM;
        memset(t,0,sizeof(*t));
        t->client = client_template;
-        i2c_set_clientdata(&t->client, t);
-        i2c_attach_client(&t->client);
+       i2c_set_clientdata(&t->client, t);
+       i2c_attach_client(&t->client);
 
        if(! bt832_init(&t->client)) {
                bt832_detach(&t->client);
@@ -211,7 +210,7 @@ bt832_command(struct i2c_client *client, unsigned int cmd, void *arg)
 
        printk("bt832: command %x\n",cmd);
 
-        switch (cmd) {
+       switch (cmd) {
                case BT832_HEXDUMP: {
                        unsigned char *buf;
                        buf=kmalloc(65,GFP_KERNEL);
index 9b6a8d2c96b5a37e398a13b969b213537d6c55ee..1ce8fa71f7db76b4771152b87d67a00e3957190a 100644 (file)
@@ -233,8 +233,8 @@ SetInterlaceMode( spec.interlace );
 /* from web:
  Video Sampling
 Digital video is a sampled form of analog video. The most common sampling schemes in use today are:
-                  Pixel Clock   Horiz    Horiz    Vert
-                   Rate         Total    Active
+                 Pixel Clock   Horiz    Horiz    Vert
+                  Rate         Total    Active
 NTSC square pixel  12.27 MHz    780      640      525
 NTSC CCIR-601      13.5  MHz    858      720      525
 NTSC 4FSc          14.32 MHz    910      768      525
index 0881a17d5226416723edfb1e2bc64a66a2d388a1..3413bace443a6a06da2d0de1a4db9aad6c82d017 100644 (file)
@@ -6,7 +6,7 @@
     like the big tvcards array for the most part
 
     Copyright (C) 1996,97,98 Ralph  Metzler (rjkm@thp.uni-koeln.de)
-                           & Marcus Metzler (mocm@thp.uni-koeln.de)
+                          & Marcus Metzler (mocm@thp.uni-koeln.de)
     (c) 1999-2001 Gerd Knorr <kraxel@goldbach.in-berlin.de>
 
     This program is free software; you can redistribute it and/or modify
@@ -145,162 +145,163 @@ static struct CARD {
        int cardnr;
        char *name;
 } cards[] __devinitdata = {
-       { 0x13eb0070, BTTV_HAUPPAUGE878,  "Hauppauge WinTV" },
-       { 0x39000070, BTTV_HAUPPAUGE878,  "Hauppauge WinTV-D" },
-       { 0x45000070, BTTV_HAUPPAUGEPVR,  "Hauppauge WinTV/PVR" },
-       { 0xff000070, BTTV_OSPREY1x0,     "Osprey-100" },
-       { 0xff010070, BTTV_OSPREY2x0_SVID,"Osprey-200" },
-       { 0xff020070, BTTV_OSPREY500,     "Osprey-500" },
-       { 0xff030070, BTTV_OSPREY2000,    "Osprey-2000" },
-       { 0xff040070, BTTV_OSPREY540,     "Osprey-540" },
-
-       { 0x00011002, BTTV_ATI_TVWONDER,  "ATI TV Wonder" },
-       { 0x00031002, BTTV_ATI_TVWONDERVE,"ATI TV Wonder/VE" },
-
-       { 0x6606107d, BTTV_WINFAST2000,   "Leadtek WinFast TV 2000" },
-       { 0x6607107d, BTTV_WINFASTVC100,  "Leadtek WinFast VC 100" },
-       { 0x6609107d, BTTV_WINFAST2000,   "Leadtek TV 2000 XP" },
-       { 0x263610b4, BTTV_STB2,          "STB TV PCI FM, Gateway P/N 6000704" },
-       { 0x264510b4, BTTV_STB2,          "STB TV PCI FM, Gateway P/N 6000704" },
-       { 0x402010fc, BTTV_GVBCTV3PCI,    "I-O Data Co. GV-BCTV3/PCI" },
-       { 0x405010fc, BTTV_GVBCTV4PCI,    "I-O Data Co. GV-BCTV4/PCI" },
-       { 0x407010fc, BTTV_GVBCTV5PCI,    "I-O Data Co. GV-BCTV5/PCI" },
-       { 0xd01810fc, BTTV_GVBCTV5PCI,    "I-O Data Co. GV-BCTV5/PCI" },
-
-       { 0x001211bd, BTTV_PINNACLE,      "Pinnacle PCTV" },
+       { 0x13eb0070, BTTV_BOARD_HAUPPAUGE878,  "Hauppauge WinTV" },
+       { 0x39000070, BTTV_BOARD_HAUPPAUGE878,  "Hauppauge WinTV-D" },
+       { 0x45000070, BTTV_BOARD_HAUPPAUGEPVR,  "Hauppauge WinTV/PVR" },
+       { 0xff000070, BTTV_BOARD_OSPREY1x0,     "Osprey-100" },
+       { 0xff010070, BTTV_BOARD_OSPREY2x0_SVID,"Osprey-200" },
+       { 0xff020070, BTTV_BOARD_OSPREY500,     "Osprey-500" },
+       { 0xff030070, BTTV_BOARD_OSPREY2000,    "Osprey-2000" },
+       { 0xff040070, BTTV_BOARD_OSPREY540,     "Osprey-540" },
+       { 0xff070070, BTTV_BOARD_OSPREY440,     "Osprey-440" },
+
+       { 0x00011002, BTTV_BOARD_ATI_TVWONDER,  "ATI TV Wonder" },
+       { 0x00031002, BTTV_BOARD_ATI_TVWONDERVE,"ATI TV Wonder/VE" },
+
+       { 0x6606107d, BTTV_BOARD_WINFAST2000,   "Leadtek WinFast TV 2000" },
+       { 0x6607107d, BTTV_BOARD_WINFASTVC100,  "Leadtek WinFast VC 100" },
+       { 0x6609107d, BTTV_BOARD_WINFAST2000,   "Leadtek TV 2000 XP" },
+       { 0x263610b4, BTTV_BOARD_STB2,          "STB TV PCI FM, Gateway P/N 6000704" },
+       { 0x264510b4, BTTV_BOARD_STB2,          "STB TV PCI FM, Gateway P/N 6000704" },
+       { 0x402010fc, BTTV_BOARD_GVBCTV3PCI,    "I-O Data Co. GV-BCTV3/PCI" },
+       { 0x405010fc, BTTV_BOARD_GVBCTV4PCI,    "I-O Data Co. GV-BCTV4/PCI" },
+       { 0x407010fc, BTTV_BOARD_GVBCTV5PCI,    "I-O Data Co. GV-BCTV5/PCI" },
+       { 0xd01810fc, BTTV_BOARD_GVBCTV5PCI,    "I-O Data Co. GV-BCTV5/PCI" },
+
+       { 0x001211bd, BTTV_BOARD_PINNACLE,      "Pinnacle PCTV" },
        /* some cards ship with byteswapped IDs ... */
-       { 0x1200bd11, BTTV_PINNACLE,      "Pinnacle PCTV [bswap]" },
-       { 0xff00bd11, BTTV_PINNACLE,      "Pinnacle PCTV [bswap]" },
+       { 0x1200bd11, BTTV_BOARD_PINNACLE,      "Pinnacle PCTV [bswap]" },
+       { 0xff00bd11, BTTV_BOARD_PINNACLE,      "Pinnacle PCTV [bswap]" },
        /* this seems to happen as well ... */
-       { 0xff1211bd, BTTV_PINNACLE,      "Pinnacle PCTV" },
-
-       { 0x3000121a, BTTV_VOODOOTV_FM,   "3Dfx VoodooTV FM/ VoodooTV 200" },
-       { 0x263710b4, BTTV_VOODOOTV_FM,   "3Dfx VoodooTV FM/ VoodooTV 200" },
-       { 0x3060121a, BTTV_STB2,          "3Dfx VoodooTV 100/ STB OEM" },
-
-       { 0x3000144f, BTTV_MAGICTVIEW063, "(Askey Magic/others) TView99 CPH06x" },
-       { 0xa005144f, BTTV_MAGICTVIEW063, "CPH06X TView99-Card" },
-       { 0x3002144f, BTTV_MAGICTVIEW061, "(Askey Magic/others) TView99 CPH05x" },
-       { 0x3005144f, BTTV_MAGICTVIEW061, "(Askey Magic/others) TView99 CPH061/06L (T1/LC)" },
-       { 0x5000144f, BTTV_MAGICTVIEW061, "Askey CPH050" },
-       { 0x300014ff, BTTV_MAGICTVIEW061, "TView 99 (CPH061)" },
-       { 0x300214ff, BTTV_PHOEBE_TVMAS,  "Phoebe TV Master (CPH060)" },
-
-       { 0x00011461, BTTV_AVPHONE98,     "AVerMedia TVPhone98" },
-       { 0x00021461, BTTV_AVERMEDIA98,   "AVermedia TVCapture 98" },
-       { 0x00031461, BTTV_AVPHONE98,     "AVerMedia TVPhone98" },
-       { 0x00041461, BTTV_AVERMEDIA98,   "AVerMedia TVCapture 98" },
-       { 0x03001461, BTTV_AVERMEDIA98,   "VDOMATE TV TUNER CARD" },
-
-       { 0x1117153b, BTTV_TERRATVALUE,   "Terratec TValue (Philips PAL B/G)" },
-       { 0x1118153b, BTTV_TERRATVALUE,   "Terratec TValue (Temic PAL B/G)" },
-       { 0x1119153b, BTTV_TERRATVALUE,   "Terratec TValue (Philips PAL I)" },
-       { 0x111a153b, BTTV_TERRATVALUE,   "Terratec TValue (Temic PAL I)" },
-
-       { 0x1123153b, BTTV_TERRATVRADIO,  "Terratec TV Radio+" },
-       { 0x1127153b, BTTV_TERRATV,       "Terratec TV+ (V1.05)"    },
+       { 0xff1211bd, BTTV_BOARD_PINNACLE,      "Pinnacle PCTV" },
+
+       { 0x3000121a, BTTV_BOARD_VOODOOTV_FM,   "3Dfx VoodooTV FM/ VoodooTV 200" },
+       { 0x263710b4, BTTV_BOARD_VOODOOTV_FM,   "3Dfx VoodooTV FM/ VoodooTV 200" },
+       { 0x3060121a, BTTV_BOARD_STB2,    "3Dfx VoodooTV 100/ STB OEM" },
+
+       { 0x3000144f, BTTV_BOARD_MAGICTVIEW063, "(Askey Magic/others) TView99 CPH06x" },
+       { 0xa005144f, BTTV_BOARD_MAGICTVIEW063, "CPH06X TView99-Card" },
+       { 0x3002144f, BTTV_BOARD_MAGICTVIEW061, "(Askey Magic/others) TView99 CPH05x" },
+       { 0x3005144f, BTTV_BOARD_MAGICTVIEW061, "(Askey Magic/others) TView99 CPH061/06L (T1/LC)" },
+       { 0x5000144f, BTTV_BOARD_MAGICTVIEW061, "Askey CPH050" },
+       { 0x300014ff, BTTV_BOARD_MAGICTVIEW061, "TView 99 (CPH061)" },
+       { 0x300214ff, BTTV_BOARD_PHOEBE_TVMAS,  "Phoebe TV Master (CPH060)" },
+
+       { 0x00011461, BTTV_BOARD_AVPHONE98,     "AVerMedia TVPhone98" },
+       { 0x00021461, BTTV_BOARD_AVERMEDIA98,   "AVermedia TVCapture 98" },
+       { 0x00031461, BTTV_BOARD_AVPHONE98,     "AVerMedia TVPhone98" },
+       { 0x00041461, BTTV_BOARD_AVERMEDIA98,   "AVerMedia TVCapture 98" },
+       { 0x03001461, BTTV_BOARD_AVERMEDIA98,   "VDOMATE TV TUNER CARD" },
+
+       { 0x1117153b, BTTV_BOARD_TERRATVALUE,   "Terratec TValue (Philips PAL B/G)" },
+       { 0x1118153b, BTTV_BOARD_TERRATVALUE,   "Terratec TValue (Temic PAL B/G)" },
+       { 0x1119153b, BTTV_BOARD_TERRATVALUE,   "Terratec TValue (Philips PAL I)" },
+       { 0x111a153b, BTTV_BOARD_TERRATVALUE,   "Terratec TValue (Temic PAL I)" },
+
+       { 0x1123153b, BTTV_BOARD_TERRATVRADIO,  "Terratec TV Radio+" },
+       { 0x1127153b, BTTV_BOARD_TERRATV,       "Terratec TV+ (V1.05)"    },
        /* clashes with FlyVideo
-        *{ 0x18521852, BTTV_TERRATV,     "Terratec TV+ (V1.10)"    }, */
-       { 0x1134153b, BTTV_TERRATVALUE,   "Terratec TValue (LR102)" },
-       { 0x1135153b, BTTV_TERRATVALUER,  "Terratec TValue Radio" }, /* LR102 */
-       { 0x5018153b, BTTV_TERRATVALUE,   "Terratec TValue" },       /* ?? */
-       { 0xff3b153b, BTTV_TERRATVALUER,  "Terratec TValue Radio" }, /* ?? */
-
-       { 0x400015b0, BTTV_ZOLTRIX_GENIE, "Zoltrix Genie TV" },
-       { 0x400a15b0, BTTV_ZOLTRIX_GENIE, "Zoltrix Genie TV" },
-       { 0x400d15b0, BTTV_ZOLTRIX_GENIE, "Zoltrix Genie TV / Radio" },
-       { 0x401015b0, BTTV_ZOLTRIX_GENIE, "Zoltrix Genie TV / Radio" },
-       { 0x401615b0, BTTV_ZOLTRIX_GENIE, "Zoltrix Genie TV / Radio" },
-
-       { 0x1430aa00, BTTV_PV143,         "Provideo PV143A" },
-       { 0x1431aa00, BTTV_PV143,         "Provideo PV143B" },
-       { 0x1432aa00, BTTV_PV143,         "Provideo PV143C" },
-       { 0x1433aa00, BTTV_PV143,         "Provideo PV143D" },
-       { 0x1433aa03, BTTV_PV143,         "Security Eyes" },
-
-       { 0x1460aa00, BTTV_PV150,         "Provideo PV150A-1" },
-       { 0x1461aa01, BTTV_PV150,         "Provideo PV150A-2" },
-       { 0x1462aa02, BTTV_PV150,         "Provideo PV150A-3" },
-       { 0x1463aa03, BTTV_PV150,         "Provideo PV150A-4" },
-
-       { 0x1464aa04, BTTV_PV150,         "Provideo PV150B-1" },
-       { 0x1465aa05, BTTV_PV150,         "Provideo PV150B-2" },
-       { 0x1466aa06, BTTV_PV150,         "Provideo PV150B-3" },
-       { 0x1467aa07, BTTV_PV150,         "Provideo PV150B-4" },
-
-       { 0xa132ff00, BTTV_IVC100,        "IVC-100"  },
-       { 0xa1550000, BTTV_IVC200,        "IVC-200"  },
-       { 0xa1550001, BTTV_IVC200,        "IVC-200"  },
-       { 0xa1550002, BTTV_IVC200,        "IVC-200"  },
-       { 0xa1550003, BTTV_IVC200,        "IVC-200"  },
-       { 0xa1550100, BTTV_IVC200,        "IVC-200G" },
-       { 0xa1550101, BTTV_IVC200,        "IVC-200G" },
-       { 0xa1550102, BTTV_IVC200,        "IVC-200G" },
-       { 0xa1550103, BTTV_IVC200,        "IVC-200G" },
-       { 0xa182ff00, BTTV_IVC120,        "IVC-120G" },
-       { 0xa182ff01, BTTV_IVC120,        "IVC-120G" },
-       { 0xa182ff02, BTTV_IVC120,        "IVC-120G" },
-       { 0xa182ff03, BTTV_IVC120,        "IVC-120G" },
-       { 0xa182ff04, BTTV_IVC120,        "IVC-120G" },
-       { 0xa182ff05, BTTV_IVC120,        "IVC-120G" },
-       { 0xa182ff06, BTTV_IVC120,        "IVC-120G" },
-       { 0xa182ff07, BTTV_IVC120,        "IVC-120G" },
-       { 0xa182ff08, BTTV_IVC120,        "IVC-120G" },
-       { 0xa182ff09, BTTV_IVC120,        "IVC-120G" },
-       { 0xa182ff0a, BTTV_IVC120,        "IVC-120G" },
-       { 0xa182ff0b, BTTV_IVC120,        "IVC-120G" },
-       { 0xa182ff0c, BTTV_IVC120,        "IVC-120G" },
-       { 0xa182ff0d, BTTV_IVC120,        "IVC-120G" },
-       { 0xa182ff0e, BTTV_IVC120,        "IVC-120G" },
-       { 0xa182ff0f, BTTV_IVC120,        "IVC-120G" },
-
-       { 0x41424344, BTTV_GRANDTEC,      "GrandTec Multi Capture" },
-       { 0x01020304, BTTV_XGUARD,        "Grandtec Grand X-Guard" },
-
-       { 0x18501851, BTTV_CHRONOS_VS2,   "FlyVideo 98 (LR50)/ Chronos Video Shuttle II" },
-       { 0xa0501851, BTTV_CHRONOS_VS2,   "FlyVideo 98 (LR50)/ Chronos Video Shuttle II" },
-       { 0x18511851, BTTV_FLYVIDEO98EZ,  "FlyVideo 98EZ (LR51)/ CyberMail AV" },
-       { 0x18521852, BTTV_TYPHOON_TVIEW, "FlyVideo 98FM (LR50)/ Typhoon TView TV/FM Tuner" },
-       { 0x41a0a051, BTTV_FLYVIDEO_98FM, "Lifeview FlyVideo 98 LR50 Rev Q" },
-       { 0x18501f7f, BTTV_FLYVIDEO_98,   "Lifeview Flyvideo 98" },
-
-       { 0x010115cb, BTTV_GMV1,          "AG GMV1" },
-       { 0x010114c7, BTTV_MODTEC_205,    "Modular Technology MM201/MM202/MM205/MM210/MM215 PCTV" },
-
-       { 0x10b42636, BTTV_HAUPPAUGE878,  "STB ???" },
-       { 0x217d6606, BTTV_WINFAST2000,   "Leadtek WinFast TV 2000" },
-       { 0xfff6f6ff, BTTV_WINFAST2000,   "Leadtek WinFast TV 2000" },
-       { 0x03116000, BTTV_SENSORAY311,   "Sensoray 311" },
-       { 0x00790e11, BTTV_WINDVR,        "Canopus WinDVR PCI" },
-       { 0xa0fca1a0, BTTV_ZOLTRIX,       "Face to Face Tvmax" },
-       { 0x20007063, BTTV_PC_HDTV,       "pcHDTV HD-2000 TV"},
-       { 0x82b2aa6a, BTTV_SIMUS_GVC1100, "SIMUS GVC1100" },
-       { 0x146caa0c, BTTV_PV951,         "ituner spectra8" },
-       { 0x200a1295, BTTV_PXC200,        "ImageNation PXC200A" },
-
-       { 0x40111554, BTTV_PV_BT878P_9B,  "Prolink Pixelview PV-BT" },
-       { 0x17de0a01, BTTV_KWORLD,        "Mecer TV/FM/Video Tuner" },
-
-       { 0x01051805, BTTV_PICOLO_TETRA_CHIP, "Picolo Tetra Chip #1" },
-       { 0x01061805, BTTV_PICOLO_TETRA_CHIP, "Picolo Tetra Chip #2" },
-       { 0x01071805, BTTV_PICOLO_TETRA_CHIP, "Picolo Tetra Chip #3" },
-       { 0x01081805, BTTV_PICOLO_TETRA_CHIP, "Picolo Tetra Chip #4" },
-
-       { 0x15409511, BTTV_ACORP_Y878F, "Acorp Y878F" },
+        *{ 0x18521852, BTTV_BOARD_TERRATV,     "Terratec TV+ (V1.10)"    }, */
+       { 0x1134153b, BTTV_BOARD_TERRATVALUE,   "Terratec TValue (LR102)" },
+       { 0x1135153b, BTTV_BOARD_TERRATVALUER,  "Terratec TValue Radio" }, /* LR102 */
+       { 0x5018153b, BTTV_BOARD_TERRATVALUE,   "Terratec TValue" },       /* ?? */
+       { 0xff3b153b, BTTV_BOARD_TERRATVALUER,  "Terratec TValue Radio" }, /* ?? */
+
+       { 0x400015b0, BTTV_BOARD_ZOLTRIX_GENIE, "Zoltrix Genie TV" },
+       { 0x400a15b0, BTTV_BOARD_ZOLTRIX_GENIE, "Zoltrix Genie TV" },
+       { 0x400d15b0, BTTV_BOARD_ZOLTRIX_GENIE, "Zoltrix Genie TV / Radio" },
+       { 0x401015b0, BTTV_BOARD_ZOLTRIX_GENIE, "Zoltrix Genie TV / Radio" },
+       { 0x401615b0, BTTV_BOARD_ZOLTRIX_GENIE, "Zoltrix Genie TV / Radio" },
+
+       { 0x1430aa00, BTTV_BOARD_PV143,         "Provideo PV143A" },
+       { 0x1431aa00, BTTV_BOARD_PV143,         "Provideo PV143B" },
+       { 0x1432aa00, BTTV_BOARD_PV143,         "Provideo PV143C" },
+       { 0x1433aa00, BTTV_BOARD_PV143,         "Provideo PV143D" },
+       { 0x1433aa03, BTTV_BOARD_PV143,         "Security Eyes" },
+
+       { 0x1460aa00, BTTV_BOARD_PV150,         "Provideo PV150A-1" },
+       { 0x1461aa01, BTTV_BOARD_PV150,         "Provideo PV150A-2" },
+       { 0x1462aa02, BTTV_BOARD_PV150,         "Provideo PV150A-3" },
+       { 0x1463aa03, BTTV_BOARD_PV150,         "Provideo PV150A-4" },
+
+       { 0x1464aa04, BTTV_BOARD_PV150,         "Provideo PV150B-1" },
+       { 0x1465aa05, BTTV_BOARD_PV150,         "Provideo PV150B-2" },
+       { 0x1466aa06, BTTV_BOARD_PV150,         "Provideo PV150B-3" },
+       { 0x1467aa07, BTTV_BOARD_PV150,         "Provideo PV150B-4" },
+
+       { 0xa132ff00, BTTV_BOARD_IVC100,        "IVC-100"  },
+       { 0xa1550000, BTTV_BOARD_IVC200,        "IVC-200"  },
+       { 0xa1550001, BTTV_BOARD_IVC200,        "IVC-200"  },
+       { 0xa1550002, BTTV_BOARD_IVC200,        "IVC-200"  },
+       { 0xa1550003, BTTV_BOARD_IVC200,        "IVC-200"  },
+       { 0xa1550100, BTTV_BOARD_IVC200,        "IVC-200G" },
+       { 0xa1550101, BTTV_BOARD_IVC200,        "IVC-200G" },
+       { 0xa1550102, BTTV_BOARD_IVC200,        "IVC-200G" },
+       { 0xa1550103, BTTV_BOARD_IVC200,        "IVC-200G" },
+       { 0xa182ff00, BTTV_BOARD_IVC120,        "IVC-120G" },
+       { 0xa182ff01, BTTV_BOARD_IVC120,        "IVC-120G" },
+       { 0xa182ff02, BTTV_BOARD_IVC120,        "IVC-120G" },
+       { 0xa182ff03, BTTV_BOARD_IVC120,        "IVC-120G" },
+       { 0xa182ff04, BTTV_BOARD_IVC120,        "IVC-120G" },
+       { 0xa182ff05, BTTV_BOARD_IVC120,        "IVC-120G" },
+       { 0xa182ff06, BTTV_BOARD_IVC120,        "IVC-120G" },
+       { 0xa182ff07, BTTV_BOARD_IVC120,        "IVC-120G" },
+       { 0xa182ff08, BTTV_BOARD_IVC120,        "IVC-120G" },
+       { 0xa182ff09, BTTV_BOARD_IVC120,        "IVC-120G" },
+       { 0xa182ff0a, BTTV_BOARD_IVC120,        "IVC-120G" },
+       { 0xa182ff0b, BTTV_BOARD_IVC120,        "IVC-120G" },
+       { 0xa182ff0c, BTTV_BOARD_IVC120,        "IVC-120G" },
+       { 0xa182ff0d, BTTV_BOARD_IVC120,        "IVC-120G" },
+       { 0xa182ff0e, BTTV_BOARD_IVC120,        "IVC-120G" },
+       { 0xa182ff0f, BTTV_BOARD_IVC120,        "IVC-120G" },
+
+       { 0x41424344, BTTV_BOARD_GRANDTEC,      "GrandTec Multi Capture" },
+       { 0x01020304, BTTV_BOARD_XGUARD,        "Grandtec Grand X-Guard" },
+
+       { 0x18501851, BTTV_BOARD_CHRONOS_VS2,   "FlyVideo 98 (LR50)/ Chronos Video Shuttle II" },
+       { 0xa0501851, BTTV_BOARD_CHRONOS_VS2,   "FlyVideo 98 (LR50)/ Chronos Video Shuttle II" },
+       { 0x18511851, BTTV_BOARD_FLYVIDEO98EZ,  "FlyVideo 98EZ (LR51)/ CyberMail AV" },
+       { 0x18521852, BTTV_BOARD_TYPHOON_TVIEW, "FlyVideo 98FM (LR50)/ Typhoon TView TV/FM Tuner" },
+       { 0x41a0a051, BTTV_BOARD_FLYVIDEO_98FM, "Lifeview FlyVideo 98 LR50 Rev Q" },
+       { 0x18501f7f, BTTV_BOARD_FLYVIDEO_98,   "Lifeview Flyvideo 98" },
+
+       { 0x010115cb, BTTV_BOARD_GMV1,          "AG GMV1" },
+       { 0x010114c7, BTTV_BOARD_MODTEC_205,    "Modular Technology MM201/MM202/MM205/MM210/MM215 PCTV" },
+
+       { 0x10b42636, BTTV_BOARD_HAUPPAUGE878,  "STB ???" },
+       { 0x217d6606, BTTV_BOARD_WINFAST2000,   "Leadtek WinFast TV 2000" },
+       { 0xfff6f6ff, BTTV_BOARD_WINFAST2000,   "Leadtek WinFast TV 2000" },
+       { 0x03116000, BTTV_BOARD_SENSORAY311,   "Sensoray 311" },
+       { 0x00790e11, BTTV_BOARD_WINDVR,        "Canopus WinDVR PCI" },
+       { 0xa0fca1a0, BTTV_BOARD_ZOLTRIX,       "Face to Face Tvmax" },
+       { 0x20007063, BTTV_BOARD_PC_HDTV,       "pcHDTV HD-2000 TV"},
+       { 0x82b2aa6a, BTTV_BOARD_SIMUS_GVC1100, "SIMUS GVC1100" },
+       { 0x146caa0c, BTTV_BOARD_PV951,         "ituner spectra8" },
+       { 0x200a1295, BTTV_BOARD_PXC200,        "ImageNation PXC200A" },
+
+       { 0x40111554, BTTV_BOARD_PV_BT878P_9B,  "Prolink Pixelview PV-BT" },
+       { 0x17de0a01, BTTV_BOARD_KWORLD,        "Mecer TV/FM/Video Tuner" },
+
+       { 0x01051805, BTTV_BOARD_PICOLO_TETRA_CHIP, "Picolo Tetra Chip #1" },
+       { 0x01061805, BTTV_BOARD_PICOLO_TETRA_CHIP, "Picolo Tetra Chip #2" },
+       { 0x01071805, BTTV_BOARD_PICOLO_TETRA_CHIP, "Picolo Tetra Chip #3" },
+       { 0x01081805, BTTV_BOARD_PICOLO_TETRA_CHIP, "Picolo Tetra Chip #4" },
+
+       { 0x15409511, BTTV_BOARD_ACORP_Y878F, "Acorp Y878F" },
 
        /* likely broken, vendor id doesn't match the other magic views ...
-        * { 0xa0fca04f, BTTV_MAGICTVIEW063, "Guillemot Maxi TV Video 3" }, */
+        * { 0xa0fca04f, BTTV_BOARD_MAGICTVIEW063, "Guillemot Maxi TV Video 3" }, */
 
        /* DVB cards (using pci function .1 for mpeg data xfer) */
-       { 0x01010071, BTTV_NEBULA_DIGITV, "Nebula Electronics DigiTV" },
-       { 0x07611461, BTTV_AVDVBT_761,    "AverMedia AverTV DVB-T 761" },
-       { 0x001c11bd, BTTV_PINNACLESAT,   "Pinnacle PCTV Sat" },
-       { 0x002611bd, BTTV_TWINHAN_DST,   "Pinnacle PCTV SAT CI" },
-       { 0x00011822, BTTV_TWINHAN_DST,   "Twinhan VisionPlus DVB" },
-       { 0xfc00270f, BTTV_TWINHAN_DST,   "ChainTech digitop DST-1000 DVB-S" },
-       { 0x07711461, BTTV_AVDVBT_771,    "AVermedia AverTV DVB-T 771" },
-       { 0xdb1018ac, BTTV_DVICO_DVBT_LITE,    "DViCO FusionHDTV DVB-T Lite" },
-       { 0xd50018ac, BTTV_DVICO_FUSIONHDTV_5_LITE,    "DViCO FusionHDTV 5 Lite" },
+       { 0x01010071, BTTV_BOARD_NEBULA_DIGITV, "Nebula Electronics DigiTV" },
+       { 0x07611461, BTTV_BOARD_AVDVBT_761,    "AverMedia AverTV DVB-T 761" },
+       { 0x001c11bd, BTTV_BOARD_PINNACLESAT,   "Pinnacle PCTV Sat" },
+       { 0x002611bd, BTTV_BOARD_TWINHAN_DST,   "Pinnacle PCTV SAT CI" },
+       { 0x00011822, BTTV_BOARD_TWINHAN_DST,   "Twinhan VisionPlus DVB" },
+       { 0xfc00270f, BTTV_BOARD_TWINHAN_DST,   "ChainTech digitop DST-1000 DVB-S" },
+       { 0x07711461, BTTV_BOARD_AVDVBT_771,    "AVermedia AverTV DVB-T 771" },
+       { 0xdb1018ac, BTTV_BOARD_DVICO_DVBT_LITE,    "DViCO FusionHDTV DVB-T Lite" },
+       { 0xd50018ac, BTTV_BOARD_DVICO_FUSIONHDTV_5_LITE,    "DViCO FusionHDTV 5 Lite" },
 
        { 0, -1, NULL }
 };
@@ -309,2116 +310,2494 @@ static struct CARD {
 /* array with description for bt848 / bt878 tv/grabber cards               */
 
 struct tvcard bttv_tvcards[] = {
-{
-/* ---- card 0x00 ---------------------------------- */
-       .name           = " *** UNKNOWN/GENERIC *** ",
-       .video_inputs   = 4,
-       .audio_inputs   = 1,
-       .tuner          = 0,
-       .svhs           = 2,
-       .muxsel         = { 2, 3, 1, 0},
-       .tuner_type     = -1,
-       .tuner_addr     = ADDR_UNSET,
-},{
-       .name           = "MIRO PCTV",
-       .video_inputs   = 4,
-       .audio_inputs   = 1,
-       .tuner          = 0,
-       .svhs           = 2,
-       .gpiomask       = 15,
-       .muxsel         = { 2, 3, 1, 1},
-       .audiomux       = { 2, 0, 0, 0, 10},
-       .needs_tvaudio  = 1,
-       .tuner_type     = -1,
-       .tuner_addr     = ADDR_UNSET,
-},{
-       .name           = "Hauppauge (bt848)",
-       .video_inputs   = 4,
-       .audio_inputs   = 1,
-       .tuner          = 0,
-       .svhs           = 2,
-       .gpiomask       = 7,
-       .muxsel         = { 2, 3, 1, 1},
-       .audiomux       = { 0, 1, 2, 3, 4},
-       .needs_tvaudio  = 1,
-       .tuner_type     = -1,
-       .tuner_addr     = ADDR_UNSET,
-},{
-       .name           = "STB, Gateway P/N 6000699 (bt848)",
-       .video_inputs   = 3,
-       .audio_inputs   = 1,
-       .tuner          = 0,
-       .svhs           = 2,
-       .gpiomask       = 7,
-       .muxsel         = { 2, 3, 1, 1},
-       .audiomux       = { 4, 0, 2, 3, 1},
-       .no_msp34xx     = 1,
-       .needs_tvaudio  = 1,
-       .tuner_type     = TUNER_PHILIPS_NTSC,
-       .tuner_addr     = ADDR_UNSET,
-       .pll            = PLL_28,
-       .has_radio      = 1,
-},{
-
-/* ---- card 0x04 ---------------------------------- */
-       .name           = "Intel Create and Share PCI/ Smart Video Recorder III",
-       .video_inputs   = 4,
-       .audio_inputs   = 0,
-       .tuner          = -1,
-       .svhs           = 2,
-       .gpiomask       = 0,
-       .muxsel         = { 2, 3, 1, 1},
-       .audiomux       = { 0 },
-       .needs_tvaudio  = 0,
-       .tuner_type     = 4,
-       .tuner_addr     = ADDR_UNSET,
-},{
-       .name           = "Diamond DTV2000",
-       .video_inputs   = 4,
-       .audio_inputs   = 1,
-       .tuner          = 0,
-       .svhs           = 2,
-       .gpiomask       = 3,
-       .muxsel         = { 2, 3, 1, 0},
-       .audiomux       = { 0, 1, 0, 1, 3},
-       .needs_tvaudio  = 1,
-       .tuner_type     = -1,
-       .tuner_addr     = ADDR_UNSET,
-},{
-       .name           = "AVerMedia TVPhone",
-       .video_inputs   = 3,
-       .audio_inputs   = 1,
-       .tuner          = 0,
-       .svhs           = 3,
-       .muxsel         = { 2, 3, 1, 1},
-       .gpiomask       = 0x0f,
-       .audiomux       = { 0x0c, 0x04, 0x08, 0x04, 0},
-       /*                0x04 for some cards ?? */
-       .needs_tvaudio  = 1,
-       .tuner_type     = -1,
-       .tuner_addr     = ADDR_UNSET,
-       .audio_hook     = avermedia_tvphone_audio,
-       .has_remote     = 1,
-},{
-       .name           = "MATRIX-Vision MV-Delta",
-       .video_inputs   = 5,
-       .audio_inputs   = 1,
-       .tuner          = -1,
-       .svhs           = 3,
-       .gpiomask       = 0,
-       .muxsel         = { 2, 3, 1, 0, 0},
-       .audiomux       = {0 },
-       .needs_tvaudio  = 1,
-       .tuner_type     = -1,
-       .tuner_addr     = ADDR_UNSET,
-},{
-
-/* ---- card 0x08 ---------------------------------- */
-       .name           = "Lifeview FlyVideo II (Bt848) LR26 / MAXI TV Video PCI2 LR26",
-       .video_inputs   = 4,
-       .audio_inputs   = 1,
-       .tuner          = 0,
-       .svhs           = 2,
-       .gpiomask       = 0xc00,
-       .muxsel         = { 2, 3, 1, 1},
-       .audiomux       = { 0, 0xc00, 0x800, 0x400, 0xc00, 0},
-       .needs_tvaudio  = 1,
-       .pll            = PLL_28,
-       .tuner_type     = -1,
-       .tuner_addr     = ADDR_UNSET,
-},{
-       .name           = "IMS/IXmicro TurboTV",
-       .video_inputs   = 3,
-       .audio_inputs   = 1,
-       .tuner          = 0,
-       .svhs           = 2,
-       .gpiomask       = 3,
-       .muxsel         = { 2, 3, 1, 1},
-       .audiomux       = { 1, 1, 2, 3, 0},
-       .needs_tvaudio  = 0,
-       .pll            = PLL_28,
-       .tuner_type     = TUNER_TEMIC_PAL,
-       .tuner_addr     = ADDR_UNSET,
-},{
-       .name           = "Hauppauge (bt878)",
-       .video_inputs   = 4,
-       .audio_inputs   = 1,
-       .tuner          = 0,
-       .svhs           = 2,
-       .gpiomask       = 0x0f, /* old: 7 */
-       .muxsel         = { 2, 0, 1, 1},
-       .audiomux       = { 0, 1, 2, 3, 4},
-       .needs_tvaudio  = 1,
-       .pll            = PLL_28,
-       .tuner_type     = -1,
-       .tuner_addr     = ADDR_UNSET,
-},{
-       .name           = "MIRO PCTV pro",
-       .video_inputs   = 3,
-       .audio_inputs   = 1,
-       .tuner          = 0,
-       .svhs           = 2,
-       .gpiomask       = 0x3014f,
-       .muxsel         = { 2, 3, 1, 1},
-       .audiomux       = { 0x20001,0x10001, 0, 0,10},
-       .needs_tvaudio  = 1,
-       .tuner_type     = -1,
-       .tuner_addr     = ADDR_UNSET,
-},{
-
-/* ---- card 0x0c ---------------------------------- */
-       .name           = "ADS Technologies Channel Surfer TV (bt848)",
-       .video_inputs   = 3,
-       .audio_inputs   = 1,
-       .tuner          = 0,
-       .svhs           = 2,
-       .gpiomask       = 15,
-       .muxsel         = { 2, 3, 1, 1},
-       .audiomux       = { 13, 14, 11, 7, 0, 0},
-       .needs_tvaudio  = 1,
-       .tuner_type     = -1,
-       .tuner_addr     = ADDR_UNSET,
-},{
-       .name           = "AVerMedia TVCapture 98",
-       .video_inputs   = 3,
-       .audio_inputs   = 4,
-       .tuner          = 0,
-       .svhs           = 2,
-       .gpiomask       = 15,
-       .muxsel         = { 2, 3, 1, 1},
-       .audiomux       = { 13, 14, 11, 7, 0, 0},
-       .needs_tvaudio  = 1,
-       .msp34xx_alt    = 1,
-       .pll            = PLL_28,
-       .tuner_type     = TUNER_PHILIPS_PAL,
-       .tuner_addr     = ADDR_UNSET,
-       .audio_hook     = avermedia_tv_stereo_audio,
-},{
-       .name           = "Aimslab Video Highway Xtreme (VHX)",
-       .video_inputs   = 3,
-       .audio_inputs   = 1,
-       .tuner          = 0,
-       .svhs           = 2,
-       .gpiomask       = 7,
-       .muxsel         = { 2, 3, 1, 1},
-       .audiomux       = { 0, 2, 1, 3, 4}, /* old: { 0, 1, 2, 3, 4} */
-       .needs_tvaudio  = 1,
-       .pll            = PLL_28,
-       .tuner_type     = -1,
-       .tuner_addr     = ADDR_UNSET,
-},{
-       .name           = "Zoltrix TV-Max",
-       .video_inputs   = 3,
-       .audio_inputs   = 1,
-       .tuner          = 0,
-       .svhs           = 2,
-       .gpiomask       = 15,
-       .muxsel         = { 2, 3, 1, 1},
-       .audiomux       = {0 , 0, 1 , 0, 10},
-       .needs_tvaudio  = 1,
-       .tuner_type     = -1,
-       .tuner_addr     = ADDR_UNSET,
-},{
-
-/* ---- card 0x10 ---------------------------------- */
-       .name           = "Prolink Pixelview PlayTV (bt878)",
-       .video_inputs   = 3,
-       .audio_inputs   = 1,
-       .tuner          = 0,
-       .svhs           = 2,
-       .gpiomask       = 0x01fe00,
-       .muxsel         = { 2, 3, 1, 1},
-       /* 2003-10-20 by "Anton A. Arapov" <arapov@mail.ru> */
-       .audiomux       = { 0x001e00, 0, 0x018000, 0x014000, 0x002000, 0 },
-       .needs_tvaudio  = 1,
-       .pll            = PLL_28,
-       .tuner_type     = -1,
-},{
-       .name           = "Leadtek WinView 601",
-       .video_inputs   = 3,
-       .audio_inputs   = 1,
-       .tuner          = 0,
-       .svhs           = 2,
-       .gpiomask       = 0x8300f8,
-       .muxsel         = { 2, 3, 1, 1,0},
-       .audiomux       = { 0x4fa007,0xcfa007,0xcfa007,0xcfa007,0xcfa007,0xcfa007},
-       .needs_tvaudio  = 1,
-       .tuner_type     = -1,
-       .tuner_addr     = ADDR_UNSET,
-       .audio_hook     = winview_audio,
-       .has_radio      = 1,
-},{
-       .name           = "AVEC Intercapture",
-       .video_inputs   = 3,
-       .audio_inputs   = 2,
-       .tuner          = 0,
-       .svhs           = 2,
-       .gpiomask       = 0,
-       .muxsel         = {2, 3, 1, 1},
-       .audiomux       = {1, 0, 0, 0, 0},
-       .needs_tvaudio  = 1,
-       .tuner_type     = -1,
-       .tuner_addr     = ADDR_UNSET,
-},{
-       .name           = "Lifeview FlyVideo II EZ /FlyKit LR38 Bt848 (capture only)",
-       .video_inputs   = 4,
-       .audio_inputs   = 1,
-       .tuner          = -1,
-       .svhs           = -1,
-       .gpiomask       = 0x8dff00,
-       .muxsel         = { 2, 3, 1, 1},
-       .audiomux       = { 0 },
-       .no_msp34xx     = 1,
-       .tuner_type     = -1,
-       .tuner_addr     = ADDR_UNSET,
-},{
-
-/* ---- card 0x14 ---------------------------------- */
-       .name           = "CEI Raffles Card",
-       .video_inputs   = 3,
-       .audio_inputs   = 3,
-       .tuner          = 0,
-       .svhs           = 2,
-       .muxsel         = {2, 3, 1, 1},
-       .tuner_type     = -1,
-       .tuner_addr     = ADDR_UNSET,
-},{
-       .name           = "Lifeview FlyVideo 98/ Lucky Star Image World ConferenceTV LR50",
-       .video_inputs   = 4,
-       .audio_inputs   = 2,  /* tuner, line in */
-       .tuner          = 0,
-       .svhs           = 2,
-       .gpiomask       = 0x1800,
-       .muxsel         = { 2, 3, 1, 1},
-       .audiomux       = { 0, 0x800, 0x1000, 0x1000, 0x1800},
-       .pll            = PLL_28,
-       .tuner_type     = TUNER_PHILIPS_PAL_I,
-       .tuner_addr     = ADDR_UNSET,
-},{
-       .name           = "Askey CPH050/ Phoebe Tv Master + FM",
-       .video_inputs   = 3,
-       .audio_inputs   = 1,
-       .tuner          = 0,
-       .svhs           = 2,
-       .gpiomask       = 0xc00,
-       .muxsel         = { 2, 3, 1, 1},
-       .audiomux       = {0, 1, 0x800, 0x400, 0xc00, 0},
-       .needs_tvaudio  = 1,
-       .pll            = PLL_28,
-       .tuner_type     = -1,
-       .tuner_addr     = ADDR_UNSET,
-},{
-       .name           = "Modular Technology MM201/MM202/MM205/MM210/MM215 PCTV, bt878",
-       .video_inputs   = 3,
-       .audio_inputs   = 1,
-       .tuner          = 0,
-       .svhs           = -1,
-       .gpiomask       = 7,
-       .muxsel         = { 2, 3, -1 },
-       .digital_mode   = DIGITAL_MODE_CAMERA,
-       .audiomux       = { 0, 0, 0, 0, 0 },
-       .no_msp34xx     = 1,
-       .pll            = PLL_28,
-       .tuner_type     = TUNER_ALPS_TSBB5_PAL_I,
-       .tuner_addr     = ADDR_UNSET,
-},{
-
-/* ---- card 0x18 ---------------------------------- */
-       .name           = "Askey CPH05X/06X (bt878) [many vendors]",
-       .video_inputs   = 3,
-       .audio_inputs   = 1,
-       .tuner          = 0,
-       .svhs           = 2,
-       .gpiomask       = 0xe00,
-       .muxsel         = { 2, 3, 1, 1},
-       .audiomux       = {0x400, 0x400, 0x400, 0x400, 0xc00},
-       .needs_tvaudio  = 1,
-       .pll            = PLL_28,
-       .tuner_type     = -1,
-       .tuner_addr     = ADDR_UNSET,
-       .has_remote     = 1,
-},{
-       .name           = "Terratec TerraTV+ Version 1.0 (Bt848)/ Terra TValue Version 1.0/ Vobis TV-Boostar",
-       .video_inputs   = 3,
-       .audio_inputs   = 1,
-       .tuner          = 0,
-       .svhs           = 2,
-       .gpiomask       = 0x1f0fff,
-       .muxsel         = { 2, 3, 1, 1},
-       .audiomux       = { 0x20000, 0x30000, 0x10000, 0, 0x40000},
-       .needs_tvaudio  = 0,
-       .tuner_type     = TUNER_PHILIPS_PAL,
-       .tuner_addr     = ADDR_UNSET,
-       .audio_hook     = terratv_audio,
-},{
-       .name           = "Hauppauge WinCam newer (bt878)",
-       .video_inputs   = 4,
-       .audio_inputs   = 1,
-       .tuner          = 0,
-       .svhs           = 3,
-       .gpiomask       = 7,
-       .muxsel         = { 2, 0, 1, 1},
-       .audiomux       = { 0, 1, 2, 3, 4},
-       .needs_tvaudio  = 1,
-       .tuner_type     = -1,
-       .tuner_addr     = ADDR_UNSET,
-},{
-       .name           = "Lifeview FlyVideo 98/ MAXI TV Video PCI2 LR50",
-       .video_inputs   = 4,
-       .audio_inputs   = 2,
-       .tuner          = 0,
-       .svhs           = 2,
-       .gpiomask       = 0x1800,
-       .muxsel         = { 2, 3, 1, 1},
-       .audiomux       = { 0, 0x800, 0x1000, 0x1000, 0x1800},
-       .pll            = PLL_28,
-       .tuner_type     = TUNER_PHILIPS_SECAM,
-       .tuner_addr     = ADDR_UNSET,
-},{
-
-/* ---- card 0x1c ---------------------------------- */
-       .name           = "Terratec TerraTV+ Version 1.1 (bt878)",
-       .video_inputs   = 3,
-       .audio_inputs   = 1,
-       .tuner          = 0,
-       .svhs           = 2,
-       .gpiomask       = 0x1f0fff,
-       .muxsel         = { 2, 3, 1, 1},
-       .audiomux       = { 0x20000, 0x30000, 0x10000, 0x00000, 0x40000},
-       .needs_tvaudio  = 0,
-       .tuner_type     = TUNER_PHILIPS_PAL,
-       .tuner_addr     = ADDR_UNSET,
-       .audio_hook     = terratv_audio,
-       /* GPIO wiring:
-       External 20 pin connector (for Active Radio Upgrade board)
-       gpio00: i2c-sda
-       gpio01: i2c-scl
-       gpio02: om5610-data
-       gpio03: om5610-clk
-       gpio04: om5610-wre
-       gpio05: om5610-stereo
-       gpio06: rds6588-davn
-       gpio07: Pin 7 n.c.
-       gpio08: nIOW
-       gpio09+10: nIOR, nSEL ?? (bt878)
-               gpio09: nIOR (bt848)
-               gpio10: nSEL (bt848)
-       Sound Routing:
-       gpio16: u2-A0 (1st 4052bt)
-       gpio17: u2-A1
-       gpio18: u2-nEN
-       gpio19: u4-A0 (2nd 4052)
-       gpio20: u4-A1
-               u4-nEN - GND
-       Btspy:
-               00000 : Cdrom (internal audio input)
-               10000 : ext. Video audio input
-               20000 : TV Mono
-               a0000 : TV Mono/2
-       1a0000 : TV Stereo
-               30000 : Radio
-               40000 : Mute
-*/
-
-},{
-       /* Jannik Fritsch <jannik@techfak.uni-bielefeld.de> */
-       .name           = "Imagenation PXC200",
-       .video_inputs   = 5,
-       .audio_inputs   = 1,
-       .tuner          = -1,
-       .svhs           = 1, /* was: 4 */
-       .gpiomask       = 0,
-       .muxsel         = { 2, 3, 1, 0, 0},
-       .audiomux       = { 0 },
-       .needs_tvaudio  = 1,
-       .tuner_type     = -1,
-       .tuner_addr     = ADDR_UNSET,
-       .muxsel_hook    = PXC200_muxsel,
-
-},{
-       .name           = "Lifeview FlyVideo 98 LR50",
-       .video_inputs   = 4,
-       .audio_inputs   = 1,
-       .tuner          = 0,
-       .svhs           = 2,
-       .gpiomask       = 0x1800,  /* 0x8dfe00 */
-       .muxsel         = { 2, 3, 1, 1},
-       .audiomux       = { 0, 0x0800, 0x1000, 0x1000, 0x1800, 0 },
-       .pll            = PLL_28,
-       .tuner_type     = -1,
-       .tuner_addr     = ADDR_UNSET,
-},{
-       .name           = "Formac iProTV, Formac ProTV I (bt848)",
-       .video_inputs   = 4,
-       .audio_inputs   = 1,
-       .tuner          = 0,
-       .svhs           = 3,
-       .gpiomask       = 1,
-       .muxsel         = { 2, 3, 1, 1},
-       .audiomux       = { 1, 0, 0, 0, 0 },
-       .pll            = PLL_28,
-       .tuner_type     = TUNER_PHILIPS_PAL,
-       .tuner_addr     = ADDR_UNSET,
-},{
-
-/* ---- card 0x20 ---------------------------------- */
-       .name           = "Intel Create and Share PCI/ Smart Video Recorder III",
-       .video_inputs   = 4,
-       .audio_inputs   = 0,
-       .tuner          = -1,
-       .svhs           = 2,
-       .gpiomask       = 0,
-       .muxsel         = { 2, 3, 1, 1},
-       .audiomux       = { 0 },
-       .needs_tvaudio  = 0,
-       .tuner_type     = 4,
-       .tuner_addr     = ADDR_UNSET,
-},{
-       .name           = "Terratec TerraTValue Version Bt878",
-       .video_inputs   = 3,
-       .audio_inputs   = 1,
-       .tuner          = 0,
-       .svhs           = 2,
-       .gpiomask       = 0xffff00,
-       .muxsel         = { 2, 3, 1, 1},
-       .audiomux       = { 0x500, 0, 0x300, 0x900, 0x900},
-       .needs_tvaudio  = 1,
-       .pll            = PLL_28,
-       .tuner_type     = TUNER_PHILIPS_PAL,
-       .tuner_addr     = ADDR_UNSET,
-},{
-       .name           = "Leadtek WinFast 2000/ WinFast 2000 XP",
-       .video_inputs   = 4,
-       .audio_inputs   = 1,
-       .tuner          = 0,
-       .svhs           = 2,
-       .muxsel         = { 2, 3, 1, 1, 0}, /* TV, CVid, SVid, CVid over SVid connector */
-       /* Alexander Varakin <avarakin@hotmail.com> [stereo version] */
-       .gpiomask       = 0xb33000,
-       .audiomux       = { 0x122000,0x1000,0x0000,0x620000,0x800000 },
-       /* Audio Routing for "WinFast 2000 XP" (no tv stereo !)
-               gpio23 -- hef4052:nEnable (0x800000)
-               gpio12 -- hef4052:A1
-               gpio13 -- hef4052:A0
-       0x0000: external audio
-       0x1000: FM
-       0x2000: TV
-       0x3000: n.c.
-       Note: There exists another variant "Winfast 2000" with tv stereo !?
-       Note: eeprom only contains FF and pci subsystem id 107d:6606
-       */
-       .needs_tvaudio  = 0,
-       .pll            = PLL_28,
-       .has_radio      = 1,
-       .tuner_type     = 5, /* default for now, gpio reads BFFF06 for Pal bg+dk */
-       .tuner_addr     = ADDR_UNSET,
-       .audio_hook     = winfast2000_audio,
-       .has_remote     = 1,
-},{
-       .name           = "Lifeview FlyVideo 98 LR50 / Chronos Video Shuttle II",
-       .video_inputs   = 4,
-       .audio_inputs   = 3,
-       .tuner          = 0,
-       .svhs           = 2,
-       .gpiomask       = 0x1800,
-       .muxsel         = { 2, 3, 1, 1},
-       .audiomux       = { 0, 0x800, 0x1000, 0x1000, 0x1800},
-       .pll            = PLL_28,
-       .tuner_type     = -1,
-       .tuner_addr     = ADDR_UNSET,
-},{
-
-/* ---- card 0x24 ---------------------------------- */
-       .name           = "Lifeview FlyVideo 98FM LR50 / Typhoon TView TV/FM Tuner",
-       .video_inputs   = 4,
-       .audio_inputs   = 3,
-       .tuner          = 0,
-       .svhs           = 2,
-       .gpiomask       = 0x1800,
-       .muxsel         = { 2, 3, 1, 1},
-       .audiomux       = { 0, 0x800, 0x1000, 0x1000, 0x1800, 0 },
-       .pll            = PLL_28,
-       .tuner_type     = -1,
-       .tuner_addr     = ADDR_UNSET,
-       .has_radio      = 1,
-},{
-       .name           = "Prolink PixelView PlayTV pro",
-       .video_inputs   = 3,
-       .audio_inputs   = 1,
-       .tuner          = 0,
-       .svhs           = 2,
-       .gpiomask       = 0xff,
-       .muxsel         = { 2, 3, 1, 1 },
-       .audiomux       = { 0x21, 0x20, 0x24, 0x2c, 0x29, 0x29 },
-       .no_msp34xx     = 1,
-       .pll            = PLL_28,
-       .tuner_type     = -1,
-       .tuner_addr     = ADDR_UNSET,
-},{
-       .name           = "Askey CPH06X TView99",
-       .video_inputs   = 4,
-       .audio_inputs   = 1,
-       .tuner          = 0,
-       .svhs           = 2,
-       .gpiomask       = 0x551e00,
-       .muxsel         = { 2, 3, 1, 0},
-       .audiomux       = { 0x551400, 0x551200, 0, 0, 0x551c00, 0x551200 },
-       .needs_tvaudio  = 1,
-       .pll            = PLL_28,
-       .tuner_type     = 1,
-       .tuner_addr     = ADDR_UNSET,
-       .has_remote     = 1,
-},{
-       .name           = "Pinnacle PCTV Studio/Rave",
-       .video_inputs   = 3,
-       .audio_inputs   = 1,
-       .tuner          = 0,
-       .svhs           = 2,
-       .gpiomask       = 0x03000F,
-       .muxsel         = { 2, 3, 1, 1},
-       .audiomux       = { 2, 0xd0001, 0, 0, 1},
-       .needs_tvaudio  = 0,
-       .pll            = PLL_28,
-       .tuner_type     = -1,
-       .tuner_addr     = ADDR_UNSET,
-},{
-
-/* ---- card 0x28 ---------------------------------- */
-       .name           = "STB TV PCI FM, Gateway P/N 6000704 (bt878), 3Dfx VoodooTV 100",
-       .video_inputs   = 3,
-       .audio_inputs   = 1,
-       .tuner          = 0,
-       .svhs           = 2,
-       .gpiomask       = 7,
-       .muxsel         = { 2, 3, 1, 1},
-       .audiomux       = { 4, 0, 2, 3, 1},
-       .no_msp34xx     = 1,
-       .needs_tvaudio  = 1,
-       .tuner_type     = TUNER_PHILIPS_NTSC,
-       .tuner_addr     = ADDR_UNSET,
-       .pll            = PLL_28,
-       .has_radio      = 1,
-},{
-       .name           = "AVerMedia TVPhone 98",
-       .video_inputs   = 3,
-       .audio_inputs   = 4,
-       .tuner          = 0,
-       .svhs           = 2,
-       .gpiomask       = 15,
-       .muxsel         = { 2, 3, 1, 1},
-       .audiomux       = { 13, 4, 11, 7, 0, 0},
-       .needs_tvaudio  = 1,
-       .pll            = PLL_28,
-       .tuner_type     = -1,
-       .tuner_addr     = ADDR_UNSET,
-       .has_radio      = 1,
-       .audio_hook     = avermedia_tvphone_audio,
-},{
-       .name           = "ProVideo PV951", /* pic16c54 */
-       .video_inputs   = 3,
-       .audio_inputs   = 1,
-       .tuner          = 0,
-       .svhs           = 2,
-       .gpiomask       = 0,
-       .muxsel         = { 2, 3, 1, 1},
-       .audiomux       = { 0, 0, 0, 0, 0},
-       .needs_tvaudio  = 1,
-       .no_msp34xx     = 1,
-       .pll            = PLL_28,
-       .tuner_type     = 1,
-       .tuner_addr     = ADDR_UNSET,
-},{
-       .name           = "Little OnAir TV",
-       .video_inputs   = 3,
-       .audio_inputs   = 1,
-       .tuner          = 0,
-       .svhs           = 2,
-       .gpiomask       = 0xe00b,
-       .muxsel         = {2, 3, 1, 1},
-       .audiomux       = {0xff9ff6, 0xff9ff6, 0xff1ff7, 0, 0xff3ffc},
-       .no_msp34xx     = 1,
-       .tuner_type     = -1,
-       .tuner_addr     = ADDR_UNSET,
-},{
-
-/* ---- card 0x2c ---------------------------------- */
-       .name           = "Sigma TVII-FM",
-       .video_inputs   = 2,
-       .audio_inputs   = 1,
-       .tuner          = 0,
-       .svhs           = -1,
-       .gpiomask       = 3,
-       .muxsel         = {2, 3, 1, 1},
-       .audiomux       = {1, 1, 0, 2, 3},
-       .no_msp34xx     = 1,
-       .pll            = PLL_NONE,
-       .tuner_type     = -1,
-       .tuner_addr     = ADDR_UNSET,
-},{
-       .name           = "MATRIX-Vision MV-Delta 2",
-       .video_inputs   = 5,
-       .audio_inputs   = 1,
-       .tuner          = -1,
-       .svhs           = 3,
-       .gpiomask       = 0,
-       .muxsel         = { 2, 3, 1, 0, 0},
-       .audiomux       = {0 },
-       .no_msp34xx     = 1,
-       .pll            = PLL_28,
-       .tuner_type     = -1,
-       .tuner_addr     = ADDR_UNSET,
-},{
-       .name           = "Zoltrix Genie TV/FM",
-       .video_inputs   = 3,
-       .audio_inputs   = 1,
-       .tuner          = 0,
-       .svhs           = 2,
-       .gpiomask       = 0xbcf03f,
-       .muxsel         = { 2, 3, 1, 1},
-       .audiomux       = { 0xbc803f, 0xbc903f, 0xbcb03f, 0, 0xbcb03f},
-       .no_msp34xx     = 1,
-       .pll            = PLL_28,
-       .tuner_type     = 21,
-       .tuner_addr     = ADDR_UNSET,
-},{
-       .name           = "Terratec TV/Radio+",
-       .video_inputs   = 3,
-       .audio_inputs   = 1,
-       .tuner          = 0,
-       .svhs           = 2,
-       .gpiomask       = 0x70000,
-       .muxsel         = { 2, 3, 1, 1},
-       .audiomux       = { 0x20000, 0x30000, 0x10000, 0, 0x40000, 0x20000 },
-       .needs_tvaudio  = 1,
-       .no_msp34xx     = 1,
-       .pll            = PLL_35,
-       .tuner_type     = 1,
-       .tuner_addr     = ADDR_UNSET,
-       .has_radio      = 1,
-},{
-
-/* ---- card 0x30 ---------------------------------- */
-       .name           = "Askey CPH03x/ Dynalink Magic TView",
-       .video_inputs   = 3,
-       .audio_inputs   = 1,
-       .tuner          = 0,
-       .svhs           = 2,
-       .gpiomask       = 15,
-       .muxsel         = { 2, 3, 1, 1},
-       .audiomux       = {2,0,0,0,1},
-       .needs_tvaudio  = 1,
-       .pll            = PLL_28,
-       .tuner_type     = -1,
-       .tuner_addr     = ADDR_UNSET,
-},{
-       .name           = "IODATA GV-BCTV3/PCI",
-       .video_inputs   = 3,
-       .audio_inputs   = 1,
-       .tuner          = 0,
-       .svhs           = 2,
-       .gpiomask       = 0x010f00,
-       .muxsel         = {2, 3, 0, 0},
-       .audiomux       = {0x10000, 0, 0x10000, 0, 0, 0},
-       .no_msp34xx     = 1,
-       .pll            = PLL_28,
-       .tuner_type     = TUNER_ALPS_TSHC6_NTSC,
-       .tuner_addr     = ADDR_UNSET,
-       .audio_hook     = gvbctv3pci_audio,
-},{
-       .name           = "Prolink PV-BT878P+4E / PixelView PlayTV PAK / Lenco MXTV-9578 CP",
-       .video_inputs   = 5,
-       .audio_inputs   = 1,
-       .tuner          = 0,
-       .svhs           = 3,
-       .gpiomask       = 0xAA0000,
-       .muxsel         = { 2,3,1,1,-1 },
-       .digital_mode   = DIGITAL_MODE_CAMERA,
-       .audiomux       = { 0x20000, 0, 0x80000, 0x80000, 0xa8000, 0x46000  },
-       .no_msp34xx     = 1,
-       .pll            = PLL_28,
-       .tuner_type     = TUNER_PHILIPS_PAL_I,
-       .tuner_addr     = ADDR_UNSET,
-       .has_remote     = 1,
-       /* GPIO wiring: (different from Rev.4C !)
-               GPIO17: U4.A0 (first hef4052bt)
-               GPIO19: U4.A1
-               GPIO20: U5.A1 (second hef4052bt)
-               GPIO21: U4.nEN
-               GPIO22: BT832 Reset Line
-               GPIO23: A5,A0, U5,nEN
-       Note: At i2c=0x8a is a Bt832 chip, which changes to 0x88 after being reset via GPIO22
-       */
-},{
-       .name           = "Eagle Wireless Capricorn2 (bt878A)",
-       .video_inputs   = 4,
-       .audio_inputs   = 1,
-       .tuner          = 0,
-       .svhs           = 2,
-       .gpiomask       = 7,
-       .muxsel         = { 2, 0, 1, 1},
-       .audiomux       = { 0, 1, 2, 3, 4},
-       .pll            = PLL_28,
-       .tuner_type     = -1 /* TUNER_ALPS_TMDH2_NTSC */,
-       .tuner_addr     = ADDR_UNSET,
-},{
-
-/* ---- card 0x34 ---------------------------------- */
-       /* David Härdeman <david@2gen.com> */
-       .name           = "Pinnacle PCTV Studio Pro",
-       .video_inputs   = 4,
-       .audio_inputs   = 1,
-       .tuner          = 0,
-       .svhs           = 3,
-       .gpiomask       = 0x03000F,
-       .muxsel         = { 2, 3, 1, 1},
-       .audiomux       = { 1, 0xd0001, 0, 0, 10},
-                       /* sound path (5 sources):
-                       MUX1 (mask 0x03), Enable Pin 0x08 (0=enable, 1=disable)
-                               0= ext. Audio IN
-                               1= from MUX2
-                               2= Mono TV sound from Tuner
-                               3= not connected
-                       MUX2 (mask 0x30000):
-                               0,2,3= from MSP34xx
-                               1= FM stereo Radio from Tuner */
-       .needs_tvaudio  = 0,
-       .pll            = PLL_28,
-       .tuner_type     = -1,
-       .tuner_addr     = ADDR_UNSET,
-},{
-       /* Claas Langbehn <claas@bigfoot.com>,
-       Sven Grothklags <sven@upb.de> */
-       .name           = "Typhoon TView RDS + FM Stereo / KNC1 TV Station RDS",
-       .video_inputs   = 4,
-       .audio_inputs   = 3,
-       .tuner          = 0,
-       .svhs           = 2,
-       .gpiomask       = 0x1c,
-       .muxsel         = { 2, 3, 1, 1},
-       .audiomux       = { 0, 0, 0x10, 8, 4 },
-       .needs_tvaudio  = 1,
-       .pll            = PLL_28,
-       .tuner_type     = TUNER_PHILIPS_PAL,
-       .tuner_addr     = ADDR_UNSET,
-       .has_radio      = 1,
-},{
-       /* Tim Röstermundt <rosterm@uni-muenster.de>
-       in de.comp.os.unix.linux.hardware:
-               options bttv card=0 pll=1 radio=1 gpiomask=0x18e0
-               audiomux=0x44c71f,0x44d71f,0,0x44d71f,0x44dfff
-               options tuner type=5 */
-       .name           = "Lifeview FlyVideo 2000 /FlyVideo A2/ Lifetec LT 9415 TV [LR90]",
-       .video_inputs   = 4,
-       .audio_inputs   = 1,
-       .tuner          = 0,
-       .svhs           = 2,
-       .gpiomask       = 0x18e0,
-       .muxsel         = { 2, 3, 1, 1},
-       .audiomux       = { 0x0000,0x0800,0x1000,0x1000,0x18e0 },
-               /* For cards with tda9820/tda9821:
-                       0x0000: Tuner normal stereo
-                       0x0080: Tuner A2 SAP (second audio program = Zweikanalton)
-                       0x0880: Tuner A2 stereo */
-       .pll            = PLL_28,
-       .tuner_type     = -1,
-       .tuner_addr     = ADDR_UNSET,
-},{
-       /* Miguel Angel Alvarez <maacruz@navegalia.com>
-       old Easy TV BT848 version (model CPH031) */
-       .name           = "Askey CPH031/ BESTBUY Easy TV",
-       .video_inputs   = 4,
-       .audio_inputs   = 1,
-       .tuner          = 0,
-       .svhs           = 2,
-       .gpiomask       = 0xF,
-       .muxsel         = { 2, 3, 1, 0},
-       .audiomux       = { 2, 0, 0, 0, 10},
-       .needs_tvaudio  = 0,
-       .pll            = PLL_28,
-       .tuner_type     = TUNER_TEMIC_PAL,
-       .tuner_addr     = ADDR_UNSET,
-},{
-
-/* ---- card 0x38 ---------------------------------- */
-       /* Gordon Heydon <gjheydon@bigfoot.com ('98) */
-       .name           = "Lifeview FlyVideo 98FM LR50",
-       .video_inputs   = 4,
-       .audio_inputs   = 3,
-       .tuner          = 0,
-       .svhs           = 2,
-       .gpiomask       = 0x1800,
-       .muxsel         = { 2, 3, 1, 1},
-       .audiomux       = { 0, 0x800, 0x1000, 0x1000, 0x1800, 0 },
-       .pll            = PLL_28,
-       .tuner_type     = 5,
-       .tuner_addr     = ADDR_UNSET,
-},{
-       /* This is the ultimate cheapo capture card
-       * just a BT848A on a small PCB!
-       * Steve Hosgood <steve@equiinet.com> */
-       .name           = "GrandTec 'Grand Video Capture' (Bt848)",
-       .video_inputs   = 2,
-       .audio_inputs   = 0,
-       .tuner          = -1,
-       .svhs           = 1,
-       .gpiomask       = 0,
-       .muxsel         = { 3, 1 },
-       .audiomux       = { 0 },
-       .needs_tvaudio  = 0,
-       .no_msp34xx     = 1,
-       .pll            = PLL_35,
-       .tuner_type     = -1,
-       .tuner_addr     = ADDR_UNSET,
-},{
-       /* Daniel Herrington <daniel.herrington@home.com> */
-       .name           = "Askey CPH060/ Phoebe TV Master Only (No FM)",
-       .video_inputs   = 3,
-       .audio_inputs   = 1,
-       .tuner          = 0,
-       .svhs           = 2,
-       .gpiomask       = 0xe00,
-       .muxsel         = { 2, 3, 1, 1},
-       .audiomux       = { 0x400, 0x400, 0x400, 0x400, 0x800, 0x400 },
-       .needs_tvaudio  = 1,
-       .pll            = PLL_28,
-       .tuner_type     = TUNER_TEMIC_4036FY5_NTSC,
-       .tuner_addr     = ADDR_UNSET,
-},{
-       /* Matti Mottus <mottus@physic.ut.ee> */
-       .name           = "Askey CPH03x TV Capturer",
-       .video_inputs   = 4,
-       .audio_inputs   = 1,
-       .tuner          = 0,
-       .svhs           = 2,
-       .gpiomask       = 0x03000F,
-       .muxsel         = { 2, 3, 1, 0},
-       .audiomux       = { 2,0,0,0,1 },
-       .pll            = PLL_28,
-       .tuner_type     = 0,
-       .tuner_addr     = ADDR_UNSET,
-},{
-
-/* ---- card 0x3c ---------------------------------- */
-       /* Philip Blundell <philb@gnu.org> */
-       .name           = "Modular Technology MM100PCTV",
-       .video_inputs   = 2,
-       .audio_inputs   = 2,
-       .tuner          = 0,
-       .svhs           = -1,
-       .gpiomask       = 11,
-       .muxsel         = { 2, 3, 1, 1},
-       .audiomux       = { 2, 0, 0, 1, 8},
-       .pll            = PLL_35,
-       .tuner_type     = TUNER_TEMIC_PAL,
-       .tuner_addr     = ADDR_UNSET,
-},{
-       /* Adrian Cox <adrian@humboldt.co.uk */
-       .name           = "AG Electronics GMV1",
-       .video_inputs   = 2,
-       .audio_inputs   = 0,
-       .tuner          = -1,
-       .svhs           = 1,
-       .gpiomask       = 0xF,
-       .muxsel         = { 2, 2},
-       .audiomux       = { },
-       .no_msp34xx     = 1,
-       .needs_tvaudio  = 0,
-       .pll            = PLL_28,
-       .tuner_type     = -1,
-       .tuner_addr     = ADDR_UNSET,
-},{
-       /* Miguel Angel Alvarez <maacruz@navegalia.com>
-       new Easy TV BT878 version (model CPH061)
-       special thanks to Informatica Mieres for providing the card */
-       .name           = "Askey CPH061/ BESTBUY Easy TV (bt878)",
-       .video_inputs   = 3,
-       .audio_inputs   = 2,
-       .tuner          = 0,
-       .svhs           = 2,
-       .gpiomask       = 0xFF,
-       .muxsel         = { 2, 3, 1, 0},
-       .audiomux       = { 1, 0, 4, 4, 9},
-       .needs_tvaudio  = 0,
-       .pll            = PLL_28,
-       .tuner_type     = TUNER_PHILIPS_PAL,
-       .tuner_addr     = ADDR_UNSET,
-},{
-       /* Lukas Gebauer <geby@volny.cz> */
-       .name           = "ATI TV-Wonder",
-       .video_inputs   = 3,
-       .audio_inputs   = 1,
-       .tuner          = 0,
-       .svhs           = 2,
-       .gpiomask       = 0xf03f,
-       .muxsel         = { 2, 3, 1, 0 },
-       .audiomux       = { 0xbffe, 0, 0xbfff, 0, 0xbffe},
-       .pll            = PLL_28,
-       .tuner_type     = TUNER_TEMIC_4006FN5_MULTI_PAL,
-       .tuner_addr     = ADDR_UNSET,
-},{
-
-/* ---- card 0x40 ---------------------------------- */
-       /* Lukas Gebauer <geby@volny.cz> */
-       .name           = "ATI TV-Wonder VE",
-       .video_inputs   = 2,
-       .audio_inputs   = 1,
-       .tuner          = 0,
-       .svhs           = -1,
-       .gpiomask       = 1,
-       .muxsel         = { 2, 3, 0, 1},
-       .audiomux       = { 0, 0, 1, 0, 0},
-       .no_msp34xx     = 1,
-       .pll            = PLL_28,
-       .tuner_type     = TUNER_TEMIC_4006FN5_MULTI_PAL,
-       .tuner_addr     = ADDR_UNSET,
-},{
-       /* DeeJay <deejay@westel900.net (2000S) */
-       .name           = "Lifeview FlyVideo 2000S LR90",
-       .video_inputs   = 3,
-       .audio_inputs   = 3,
-       .tuner          = 0,
-       .svhs           = 2,
-       .gpiomask       = 0x18e0,
-       .muxsel         = { 2, 3, 0, 1},
-                       /* Radio changed from 1e80 to 0x800 to make
-                       FlyVideo2000S in .hu happy (gm)*/
-                       /* -dk-???: set mute=0x1800 for tda9874h daughterboard */
-       .audiomux       = { 0x0000,0x0800,0x1000,0x1000,0x1800, 0x1080 },
-       .audio_hook     = fv2000s_audio,
-       .no_msp34xx     = 1,
-       .no_tda9875     = 1,
-       .needs_tvaudio  = 1,
-       .pll            = PLL_28,
-       .tuner_type     = 5,
-       .tuner_addr     = ADDR_UNSET,
-},{
-       .name           = "Terratec TValueRadio",
-       .video_inputs   = 3,
-       .audio_inputs   = 1,
-       .tuner          = 0,
-       .svhs           = 2,
-       .gpiomask       = 0xffff00,
-       .muxsel         = { 2, 3, 1, 1},
-       .audiomux       = { 0x500, 0x500, 0x300, 0x900, 0x900},
-       .needs_tvaudio  = 1,
-       .pll            = PLL_28,
-       .tuner_type     = TUNER_PHILIPS_PAL,
-       .tuner_addr     = ADDR_UNSET,
-       .has_radio      = 1,
-},{
-       /* TANAKA Kei <peg00625@nifty.com> */
-       .name           = "IODATA GV-BCTV4/PCI",
-       .video_inputs   = 3,
-       .audio_inputs   = 1,
-       .tuner          = 0,
-       .svhs           = 2,
-       .gpiomask       = 0x010f00,
-       .muxsel         = {2, 3, 0, 0},
-       .audiomux       = {0x10000, 0, 0x10000, 0, 0, 0},
-       .no_msp34xx     = 1,
-       .pll            = PLL_28,
-       .tuner_type     = TUNER_SHARP_2U5JF5540_NTSC,
-       .tuner_addr     = ADDR_UNSET,
-       .audio_hook     = gvbctv3pci_audio,
-},{
-
-/* ---- card 0x44 ---------------------------------- */
-       .name           = "3Dfx VoodooTV FM (Euro), VoodooTV 200 (USA)",
-       /* try "insmod msp3400 simple=0" if you have
-       * sound problems with this card. */
-       .video_inputs   = 4,
-       .audio_inputs   = 1,
-       .tuner          = 0,
-       .svhs           = -1,
-       .gpiomask       = 0x4f8a00,
-       /* 0x100000: 1=MSP enabled (0=disable again)
-       * 0x010000: Connected to "S0" on tda9880 (0=Pal/BG, 1=NTSC) */
-       .audiomux       = {0x947fff, 0x987fff,0x947fff,0x947fff, 0x947fff},
-       /* tvtuner, radio,   external,internal, mute,  stereo
-       * tuner, Composit, SVid, Composit-on-Svid-adapter */
-       .muxsel         = { 2, 3 ,0 ,1},
-       .tuner_type     = TUNER_MT2032,
-       .tuner_addr     = ADDR_UNSET,
-       .pll            = PLL_28,
-       .has_radio      = 1,
-},{
-       /* Philip Blundell <pb@nexus.co.uk> */
-       .name           = "Active Imaging AIMMS",
-       .video_inputs   = 1,
-       .audio_inputs   = 0,
-       .tuner          = -1,
-       .tuner_type     = -1,
-       .tuner_addr     = ADDR_UNSET,
-       .pll            = PLL_28,
-       .muxsel         = { 2 },
-       .gpiomask       = 0
-},{
-       /* Tomasz Pyra <hellfire@sedez.iq.pl> */
-       .name           = "Prolink Pixelview PV-BT878P+ (Rev.4C,8E)",
-       .video_inputs   = 3,
-       .audio_inputs   = 4,
-       .tuner          = 0,
-       .svhs           = 2,
-       .gpiomask       = 15,
-       .muxsel         = { 2, 3, 1, 1},
-       .audiomux       = { 0, 0, 11, 7, 13, 0}, /* TV and Radio with same GPIO ! */
-       .needs_tvaudio  = 1,
-       .pll            = PLL_28,
-       .tuner_type     = 25,
-       .tuner_addr     = ADDR_UNSET,
-       .has_remote     = 1,
-       /* GPIO wiring:
-               GPIO0: U4.A0 (hef4052bt)
-               GPIO1: U4.A1
-               GPIO2: U4.A1 (second hef4052bt)
-               GPIO3: U4.nEN, U5.A0, A5.nEN
-               GPIO8-15: vrd866b ?
+       /* ---- card 0x00 ---------------------------------- */
+       [BTTV_BOARD_UNKNOWN] = {
+               .name           = " *** UNKNOWN/GENERIC *** ",
+               .video_inputs   = 4,
+               .audio_inputs   = 1,
+               .tuner          = 0,
+               .svhs           = 2,
+               .muxsel         = { 2, 3, 1, 0},
+               .tuner_type     = -1,
+               .tuner_addr     = ADDR_UNSET,
+               .radio_addr     = ADDR_UNSET,
+       },
+       [BTTV_BOARD_MIRO] = {
+               .name           = "MIRO PCTV",
+               .video_inputs   = 4,
+               .audio_inputs   = 1,
+               .tuner          = 0,
+               .svhs           = 2,
+               .gpiomask       = 15,
+               .muxsel         = { 2, 3, 1, 1},
+               .audiomux       = { 2, 0, 0, 0, 10},
+               .needs_tvaudio  = 1,
+               .tuner_type     = -1,
+               .tuner_addr     = ADDR_UNSET,
+               .radio_addr     = ADDR_UNSET,
+       },
+       [BTTV_BOARD_HAUPPAUGE] = {
+               .name           = "Hauppauge (bt848)",
+               .video_inputs   = 4,
+               .audio_inputs   = 1,
+               .tuner          = 0,
+               .svhs           = 2,
+               .gpiomask       = 7,
+               .muxsel         = { 2, 3, 1, 1},
+               .audiomux       = { 0, 1, 2, 3, 4},
+               .needs_tvaudio  = 1,
+               .tuner_type     = -1,
+               .tuner_addr     = ADDR_UNSET,
+               .radio_addr     = ADDR_UNSET,
+       },
+       [BTTV_BOARD_STB] = {
+               .name           = "STB, Gateway P/N 6000699 (bt848)",
+               .video_inputs   = 3,
+               .audio_inputs   = 1,
+               .tuner          = 0,
+               .svhs           = 2,
+               .gpiomask       = 7,
+               .muxsel         = { 2, 3, 1, 1},
+               .audiomux       = { 4, 0, 2, 3, 1},
+               .no_msp34xx     = 1,
+               .needs_tvaudio  = 1,
+               .tuner_type     = TUNER_PHILIPS_NTSC,
+               .tuner_addr     = ADDR_UNSET,
+               .radio_addr     = ADDR_UNSET,
+               .pll            = PLL_28,
+               .has_radio      = 1,
+       },
+
+       /* ---- card 0x04 ---------------------------------- */
+       [BTTV_BOARD_INTEL] = {
+               .name           = "Intel Create and Share PCI/ Smart Video Recorder III",
+               .video_inputs   = 4,
+               .audio_inputs   = 0,
+               .tuner          = -1,
+               .svhs           = 2,
+               .gpiomask       = 0,
+               .muxsel         = { 2, 3, 1, 1},
+               .audiomux       = { 0 },
+               .needs_tvaudio  = 0,
+               .tuner_type     = 4,
+               .tuner_addr     = ADDR_UNSET,
+               .radio_addr     = ADDR_UNSET,
+       },
+       [BTTV_BOARD_DIAMOND] = {
+               .name           = "Diamond DTV2000",
+               .video_inputs   = 4,
+               .audio_inputs   = 1,
+               .tuner          = 0,
+               .svhs           = 2,
+               .gpiomask       = 3,
+               .muxsel         = { 2, 3, 1, 0},
+               .audiomux       = { 0, 1, 0, 1, 3},
+               .needs_tvaudio  = 1,
+               .tuner_type     = -1,
+               .tuner_addr     = ADDR_UNSET,
+               .radio_addr     = ADDR_UNSET,
+       },
+       [BTTV_BOARD_AVERMEDIA] = {
+               .name           = "AVerMedia TVPhone",
+               .video_inputs   = 3,
+               .audio_inputs   = 1,
+               .tuner          = 0,
+               .svhs           = 3,
+               .muxsel         = { 2, 3, 1, 1},
+               .gpiomask       = 0x0f,
+               .audiomux       = { 0x0c, 0x04, 0x08, 0x04, 0},
+               /*                0x04 for some cards ?? */
+               .needs_tvaudio  = 1,
+               .tuner_type     = -1,
+               .tuner_addr     = ADDR_UNSET,
+               .radio_addr     = ADDR_UNSET,
+               .audio_hook     = avermedia_tvphone_audio,
+               .has_remote     = 1,
+       },
+       [BTTV_BOARD_MATRIX_VISION] = {
+               .name           = "MATRIX-Vision MV-Delta",
+               .video_inputs   = 5,
+               .audio_inputs   = 1,
+               .tuner          = -1,
+               .svhs           = 3,
+               .gpiomask       = 0,
+               .muxsel         = { 2, 3, 1, 0, 0},
+               .audiomux       = {0 },
+               .needs_tvaudio  = 1,
+               .tuner_type     = -1,
+               .tuner_addr     = ADDR_UNSET,
+               .radio_addr     = ADDR_UNSET,
+       },
+
+       /* ---- card 0x08 ---------------------------------- */
+       [BTTV_BOARD_FLYVIDEO] = {
+               .name           = "Lifeview FlyVideo II (Bt848) LR26 / MAXI TV Video PCI2 LR26",
+               .video_inputs   = 4,
+               .audio_inputs   = 1,
+               .tuner          = 0,
+               .svhs           = 2,
+               .gpiomask       = 0xc00,
+               .muxsel         = { 2, 3, 1, 1},
+               .audiomux       = { 0, 0xc00, 0x800, 0x400, 0xc00, 0},
+               .needs_tvaudio  = 1,
+               .pll            = PLL_28,
+               .tuner_type     = -1,
+               .tuner_addr     = ADDR_UNSET,
+               .radio_addr     = ADDR_UNSET,
+       },
+       [BTTV_BOARD_TURBOTV] = {
+               .name           = "IMS/IXmicro TurboTV",
+               .video_inputs   = 3,
+               .audio_inputs   = 1,
+               .tuner          = 0,
+               .svhs           = 2,
+               .gpiomask       = 3,
+               .muxsel         = { 2, 3, 1, 1},
+               .audiomux       = { 1, 1, 2, 3, 0},
+               .needs_tvaudio  = 0,
+               .pll            = PLL_28,
+               .tuner_type     = TUNER_TEMIC_PAL,
+               .tuner_addr     = ADDR_UNSET,
+               .radio_addr     = ADDR_UNSET,
+       },
+       [BTTV_BOARD_HAUPPAUGE878] = {
+               .name           = "Hauppauge (bt878)",
+               .video_inputs   = 4,
+               .audio_inputs   = 1,
+               .tuner          = 0,
+               .svhs           = 2,
+               .gpiomask       = 0x0f, /* old: 7 */
+               .muxsel         = { 2, 0, 1, 1},
+               .audiomux       = { 0, 1, 2, 3, 4},
+               .needs_tvaudio  = 1,
+               .pll            = PLL_28,
+               .tuner_type     = -1,
+               .tuner_addr     = ADDR_UNSET,
+               .radio_addr     = ADDR_UNSET,
+       },
+       [BTTV_BOARD_MIROPRO] = {
+               .name           = "MIRO PCTV pro",
+               .video_inputs   = 3,
+               .audio_inputs   = 1,
+               .tuner          = 0,
+               .svhs           = 2,
+               .gpiomask       = 0x3014f,
+               .muxsel         = { 2, 3, 1, 1},
+               .audiomux       = { 0x20001,0x10001, 0, 0,10},
+               .needs_tvaudio  = 1,
+               .tuner_type     = -1,
+               .tuner_addr     = ADDR_UNSET,
+               .radio_addr     = ADDR_UNSET,
+       },
+
+       /* ---- card 0x0c ---------------------------------- */
+       [BTTV_BOARD_ADSTECH_TV] = {
+               .name           = "ADS Technologies Channel Surfer TV (bt848)",
+               .video_inputs   = 3,
+               .audio_inputs   = 1,
+               .tuner          = 0,
+               .svhs           = 2,
+               .gpiomask       = 15,
+               .muxsel         = { 2, 3, 1, 1},
+               .audiomux       = { 13, 14, 11, 7, 0, 0},
+               .needs_tvaudio  = 1,
+               .tuner_type     = -1,
+               .tuner_addr     = ADDR_UNSET,
+               .radio_addr     = ADDR_UNSET,
+       },
+       [BTTV_BOARD_AVERMEDIA98] = {
+               .name           = "AVerMedia TVCapture 98",
+               .video_inputs   = 3,
+               .audio_inputs   = 4,
+               .tuner          = 0,
+               .svhs           = 2,
+               .gpiomask       = 15,
+               .muxsel         = { 2, 3, 1, 1},
+               .audiomux       = { 13, 14, 11, 7, 0, 0},
+               .needs_tvaudio  = 1,
+               .msp34xx_alt    = 1,
+               .pll            = PLL_28,
+               .tuner_type     = TUNER_PHILIPS_PAL,
+               .tuner_addr     = ADDR_UNSET,
+               .radio_addr     = ADDR_UNSET,
+               .audio_hook     = avermedia_tv_stereo_audio,
+               .no_gpioirq     = 1,
+       },
+       [BTTV_BOARD_VHX] = {
+               .name           = "Aimslab Video Highway Xtreme (VHX)",
+               .video_inputs   = 3,
+               .audio_inputs   = 1,
+               .tuner          = 0,
+               .svhs           = 2,
+               .gpiomask       = 7,
+               .muxsel         = { 2, 3, 1, 1},
+               .audiomux       = { 0, 2, 1, 3, 4}, /* old: { 0, 1, 2, 3, 4} */
+               .needs_tvaudio  = 1,
+               .pll            = PLL_28,
+               .tuner_type     = -1,
+               .tuner_addr     = ADDR_UNSET,
+               .radio_addr     = ADDR_UNSET,
+       },
+       [BTTV_BOARD_ZOLTRIX] = {
+               .name           = "Zoltrix TV-Max",
+               .video_inputs   = 3,
+               .audio_inputs   = 1,
+               .tuner          = 0,
+               .svhs           = 2,
+               .gpiomask       = 15,
+               .muxsel         = { 2, 3, 1, 1},
+               .audiomux       = {0 , 0, 1 , 0, 10},
+               .needs_tvaudio  = 1,
+               .tuner_type     = -1,
+               .tuner_addr     = ADDR_UNSET,
+               .radio_addr     = ADDR_UNSET,
+       },
+
+       /* ---- card 0x10 ---------------------------------- */
+       [BTTV_BOARD_PIXVIEWPLAYTV] = {
+               .name           = "Prolink Pixelview PlayTV (bt878)",
+               .video_inputs   = 3,
+               .audio_inputs   = 1,
+               .tuner          = 0,
+               .svhs           = 2,
+               .gpiomask       = 0x01fe00,
+               .muxsel         = { 2, 3, 1, 1},
+       #if 0
+               /* old */
+               .audiomux       = { 0x01c000, 0, 0x018000, 0x014000, 0x002000, 0 },
+       #else
+               /* 2003-10-20 by "Anton A. Arapov" <arapov@mail.ru> */
+               .audiomux       = { 0x001e00, 0, 0x018000, 0x014000, 0x002000, 0 },
+       #endif
+               .needs_tvaudio  = 1,
+               .pll            = PLL_28,
+               .tuner_type     = -1,
+       },
+       [BTTV_BOARD_WINVIEW_601] = {
+               .name           = "Leadtek WinView 601",
+               .video_inputs   = 3,
+               .audio_inputs   = 1,
+               .tuner          = 0,
+               .svhs           = 2,
+               .gpiomask       = 0x8300f8,
+               .muxsel         = { 2, 3, 1, 1,0},
+               .audiomux       = { 0x4fa007,0xcfa007,0xcfa007,0xcfa007,0xcfa007,0xcfa007},
+               .needs_tvaudio  = 1,
+               .tuner_type     = -1,
+               .tuner_addr     = ADDR_UNSET,
+               .radio_addr     = ADDR_UNSET,
+               .audio_hook     = winview_audio,
+               .has_radio      = 1,
+       },
+       [BTTV_BOARD_AVEC_INTERCAP] = {
+               .name           = "AVEC Intercapture",
+               .video_inputs   = 3,
+               .audio_inputs   = 2,
+               .tuner          = 0,
+               .svhs           = 2,
+               .gpiomask       = 0,
+               .muxsel         = {2, 3, 1, 1},
+               .audiomux       = {1, 0, 0, 0, 0},
+               .needs_tvaudio  = 1,
+               .tuner_type     = -1,
+               .tuner_addr     = ADDR_UNSET,
+               .radio_addr     = ADDR_UNSET,
+       },
+       [BTTV_BOARD_LIFE_FLYKIT] = {
+               .name           = "Lifeview FlyVideo II EZ /FlyKit LR38 Bt848 (capture only)",
+               .video_inputs   = 4,
+               .audio_inputs   = 1,
+               .tuner          = -1,
+               .svhs           = -1,
+               .gpiomask       = 0x8dff00,
+               .muxsel         = { 2, 3, 1, 1},
+               .audiomux       = { 0 },
+               .no_msp34xx     = 1,
+               .tuner_type     = -1,
+               .tuner_addr     = ADDR_UNSET,
+               .radio_addr     = ADDR_UNSET,
+       },
+
+       /* ---- card 0x14 ---------------------------------- */
+       [BTTV_BOARD_CEI_RAFFLES] = {
+               .name           = "CEI Raffles Card",
+               .video_inputs   = 3,
+               .audio_inputs   = 3,
+               .tuner          = 0,
+               .svhs           = 2,
+               .muxsel         = {2, 3, 1, 1},
+               .tuner_type     = -1,
+               .tuner_addr     = ADDR_UNSET,
+               .radio_addr     = ADDR_UNSET,
+       },
+       [BTTV_BOARD_CONFERENCETV] = {
+               .name           = "Lifeview FlyVideo 98/ Lucky Star Image World ConferenceTV LR50",
+               .video_inputs   = 4,
+               .audio_inputs   = 2,  /* tuner, line in */
+               .tuner          = 0,
+               .svhs           = 2,
+               .gpiomask       = 0x1800,
+               .muxsel         = { 2, 3, 1, 1},
+               .audiomux       = { 0, 0x800, 0x1000, 0x1000, 0x1800},
+               .pll            = PLL_28,
+               .tuner_type     = TUNER_PHILIPS_PAL_I,
+               .tuner_addr     = ADDR_UNSET,
+               .radio_addr     = ADDR_UNSET,
+       },
+       [BTTV_BOARD_PHOEBE_TVMAS] = {
+               .name           = "Askey CPH050/ Phoebe Tv Master + FM",
+               .video_inputs   = 3,
+               .audio_inputs   = 1,
+               .tuner          = 0,
+               .svhs           = 2,
+               .gpiomask       = 0xc00,
+               .muxsel         = { 2, 3, 1, 1},
+               .audiomux       = {0, 1, 0x800, 0x400, 0xc00, 0},
+               .needs_tvaudio  = 1,
+               .pll            = PLL_28,
+               .tuner_type     = -1,
+               .tuner_addr     = ADDR_UNSET,
+               .radio_addr     = ADDR_UNSET,
+       },
+       [BTTV_BOARD_MODTEC_205] = {
+               .name           = "Modular Technology MM201/MM202/MM205/MM210/MM215 PCTV, bt878",
+               .video_inputs   = 3,
+               .audio_inputs   = 1,
+               .tuner          = 0,
+               .svhs           = -1,
+               .gpiomask       = 7,
+               .muxsel         = { 2, 3, -1 },
+               .digital_mode   = DIGITAL_MODE_CAMERA,
+               .audiomux       = { 0, 0, 0, 0, 0 },
+               .no_msp34xx     = 1,
+               .pll            = PLL_28,
+               .tuner_type     = TUNER_ALPS_TSBB5_PAL_I,
+               .tuner_addr     = ADDR_UNSET,
+               .radio_addr     = ADDR_UNSET,
+       },
+
+       /* ---- card 0x18 ---------------------------------- */
+       [BTTV_BOARD_MAGICTVIEW061] = {
+               .name           = "Askey CPH05X/06X (bt878) [many vendors]",
+               .video_inputs   = 3,
+               .audio_inputs   = 1,
+               .tuner          = 0,
+               .svhs           = 2,
+               .gpiomask       = 0xe00,
+               .muxsel         = { 2, 3, 1, 1},
+               .audiomux       = {0x400, 0x400, 0x400, 0x400, 0xc00},
+               .needs_tvaudio  = 1,
+               .pll            = PLL_28,
+               .tuner_type     = -1,
+               .tuner_addr     = ADDR_UNSET,
+               .radio_addr     = ADDR_UNSET,
+               .has_remote     = 1,
+       },
+       [BTTV_BOARD_VOBIS_BOOSTAR] = {
+               .name           = "Terratec TerraTV+ Version 1.0 (Bt848)/ Terra TValue Version 1.0/ Vobis TV-Boostar",
+               .video_inputs   = 3,
+               .audio_inputs   = 1,
+               .tuner          = 0,
+               .svhs           = 2,
+               .gpiomask       = 0x1f0fff,
+               .muxsel         = { 2, 3, 1, 1},
+               .audiomux       = { 0x20000, 0x30000, 0x10000, 0, 0x40000},
+               .needs_tvaudio  = 0,
+               .tuner_type     = TUNER_PHILIPS_PAL,
+               .tuner_addr     = ADDR_UNSET,
+               .radio_addr     = ADDR_UNSET,
+               .audio_hook     = terratv_audio,
+       },
+       [BTTV_BOARD_HAUPPAUG_WCAM] = {
+               .name           = "Hauppauge WinCam newer (bt878)",
+               .video_inputs   = 4,
+               .audio_inputs   = 1,
+               .tuner          = 0,
+               .svhs           = 3,
+               .gpiomask       = 7,
+               .muxsel         = { 2, 0, 1, 1},
+               .audiomux       = { 0, 1, 2, 3, 4},
+               .needs_tvaudio  = 1,
+               .tuner_type     = -1,
+               .tuner_addr     = ADDR_UNSET,
+               .radio_addr     = ADDR_UNSET,
+       },
+       [BTTV_BOARD_MAXI] = {
+               .name           = "Lifeview FlyVideo 98/ MAXI TV Video PCI2 LR50",
+               .video_inputs   = 4,
+               .audio_inputs   = 2,
+               .tuner          = 0,
+               .svhs           = 2,
+               .gpiomask       = 0x1800,
+               .muxsel         = { 2, 3, 1, 1},
+               .audiomux       = { 0, 0x800, 0x1000, 0x1000, 0x1800},
+               .pll            = PLL_28,
+               .tuner_type     = TUNER_PHILIPS_SECAM,
+               .tuner_addr     = ADDR_UNSET,
+               .radio_addr     = ADDR_UNSET,
+       },
+
+       /* ---- card 0x1c ---------------------------------- */
+       [BTTV_BOARD_TERRATV] = {
+               .name           = "Terratec TerraTV+ Version 1.1 (bt878)",
+               .video_inputs   = 3,
+               .audio_inputs   = 1,
+               .tuner          = 0,
+               .svhs           = 2,
+               .gpiomask       = 0x1f0fff,
+               .muxsel         = { 2, 3, 1, 1},
+               .audiomux       = { 0x20000, 0x30000, 0x10000, 0x00000, 0x40000},
+               .needs_tvaudio  = 0,
+               .tuner_type     = TUNER_PHILIPS_PAL,
+               .tuner_addr     = ADDR_UNSET,
+               .radio_addr     = ADDR_UNSET,
+               .audio_hook     = terratv_audio,
+               /* GPIO wiring:
+               External 20 pin connector (for Active Radio Upgrade board)
+               gpio00: i2c-sda
+               gpio01: i2c-scl
+               gpio02: om5610-data
+               gpio03: om5610-clk
+               gpio04: om5610-wre
+               gpio05: om5610-stereo
+               gpio06: rds6588-davn
+               gpio07: Pin 7 n.c.
+               gpio08: nIOW
+               gpio09+10: nIOR, nSEL ?? (bt878)
+                       gpio09: nIOR (bt848)
+                       gpio10: nSEL (bt848)
+               Sound Routing:
+               gpio16: u2-A0 (1st 4052bt)
+               gpio17: u2-A1
+               gpio18: u2-nEN
+               gpio19: u4-A0 (2nd 4052)
+               gpio20: u4-A1
+                       u4-nEN - GND
+               Btspy:
+                       00000 : Cdrom (internal audio input)
+                       10000 : ext. Video audio input
+                       20000 : TV Mono
+                       a0000 : TV Mono/2
+               1a0000 : TV Stereo
+                       30000 : Radio
+                       40000 : Mute
        */
-},{
-       .name           = "Lifeview FlyVideo 98EZ (capture only) LR51",
-       .video_inputs   = 4,
-       .audio_inputs   = 0,
-       .tuner          = -1,
-       .svhs           = 2,
-       .muxsel         = { 2, 3, 1, 1}, /* AV1, AV2, SVHS, CVid adapter on SVHS */
-       .pll            = PLL_28,
-       .no_msp34xx     = 1,
-       .tuner_type     = UNSET,
-       .tuner_addr     = ADDR_UNSET,
-},{
-
-/* ---- card 0x48 ---------------------------------- */
-       /* Dariusz Kowalewski <darekk@automex.pl> */
-       .name           = "Prolink Pixelview PV-BT878P+9B (PlayTV Pro rev.9B FM+NICAM)",
-       .video_inputs   = 4,
-       .audio_inputs   = 1,
-       .tuner          = 0,
-       .svhs           = 2,
-       .gpiomask       = 0x3f,
-       .muxsel         = { 2, 3, 1, 1 },
-       .audiomux       = { 0x01, 0x00, 0x03, 0x03, 0x09, 0x02 },
-       .needs_tvaudio  = 1,
-       .no_msp34xx     = 1,
-       .no_tda9875     = 1,
-       .pll            = PLL_28,
-       .tuner_type     = 5,
-       .tuner_addr     = ADDR_UNSET,
-       .audio_hook     = pvbt878p9b_audio, /* Note: not all cards have stereo */
-       .has_radio      = 1,  /* Note: not all cards have radio */
-       .has_remote     = 1,
-       /* GPIO wiring:
-               GPIO0: A0 hef4052
-               GPIO1: A1 hef4052
-               GPIO3: nEN hef4052
-               GPIO8-15: vrd866b
-               GPIO20,22,23: R30,R29,R28
-       */
-},{
-       /* Clay Kunz <ckunz@mail.arc.nasa.gov> */
-       /* you must jumper JP5 for the card to work */
-       .name           = "Sensoray 311",
-       .video_inputs   = 5,
-       .audio_inputs   = 0,
-       .tuner          = -1,
-       .svhs           = 4,
-       .gpiomask       = 0,
-       .muxsel         = { 2, 3, 1, 0, 0},
-       .audiomux       = { 0 },
-       .needs_tvaudio  = 0,
-       .tuner_type     = -1,
-       .tuner_addr     = ADDR_UNSET,
-},{
-       /* Miguel Freitas <miguel@cetuc.puc-rio.br> */
-       .name           = "RemoteVision MX (RV605)",
-       .video_inputs   = 16,
-       .audio_inputs   = 0,
-       .tuner          = -1,
-       .svhs           = -1,
-       .gpiomask       = 0x00,
-       .gpiomask2      = 0x07ff,
-       .muxsel         = { 0x33, 0x13, 0x23, 0x43, 0xf3, 0x73, 0xe3, 0x03,
-                       0xd3, 0xb3, 0xc3, 0x63, 0x93, 0x53, 0x83, 0xa3 },
-       .no_msp34xx     = 1,
-       .no_tda9875     = 1,
-       .tuner_type     = -1,
-       .tuner_addr     = ADDR_UNSET,
-       .muxsel_hook    = rv605_muxsel,
-},{
-       .name           = "Powercolor MTV878/ MTV878R/ MTV878F",
-       .video_inputs   = 3,
-       .audio_inputs   = 2,
-       .tuner          = 0,
-       .svhs           = 2,
-       .gpiomask       = 0x1C800F,  /* Bit0-2: Audio select, 8-12:remote control 14:remote valid 15:remote reset */
-       .muxsel         = { 2, 1, 1, },
-       .audiomux       = { 0, 1, 2, 2, 4 },
-       .needs_tvaudio  = 0,
-       .tuner_type     = TUNER_PHILIPS_PAL,
-       .tuner_addr     = ADDR_UNSET,
-       .pll            = PLL_28,
-       .has_radio      = 1,
-},{
-
-/* ---- card 0x4c ---------------------------------- */
-       /* Masaki Suzuki <masaki@btree.org> */
-       .name           = "Canopus WinDVR PCI (COMPAQ Presario 3524JP, 5112JP)",
-       .video_inputs   = 3,
-       .audio_inputs   = 1,
-       .tuner          = 0,
-       .svhs           = 2,
-       .gpiomask       = 0x140007,
-       .muxsel         = { 2, 3, 1, 1 },
-       .audiomux       = { 0, 1, 2, 3, 4, 0 },
-       .tuner_type     = TUNER_PHILIPS_NTSC,
-       .tuner_addr     = ADDR_UNSET,
-       .audio_hook     = windvr_audio,
-},{
-       .name           = "GrandTec Multi Capture Card (Bt878)",
-       .video_inputs   = 4,
-       .audio_inputs   = 0,
-       .tuner          = -1,
-       .svhs           = -1,
-       .gpiomask       = 0,
-       .muxsel         = { 2, 3, 1, 0 },
-       .audiomux       = { 0 },
-       .needs_tvaudio  = 0,
-       .no_msp34xx     = 1,
-       .pll            = PLL_28,
-       .tuner_type     = -1,
-       .tuner_addr     = ADDR_UNSET,
-},{
-       .name           = "Jetway TV/Capture JW-TV878-FBK, Kworld KW-TV878RF",
-       .video_inputs   = 4,
-       .audio_inputs   = 3,
-       .tuner          = 0,
-       .svhs           = 2,
-       .gpiomask       = 7,
-       .muxsel         = { 2, 3, 1, 1 },   /* Tuner, SVid, SVHS, SVid to SVHS connector */
-       .audiomux       = { 0 ,0 ,4, 4,4,4},/* Yes, this tuner uses the same audio output for TV and FM radio!
-                                       * This card lacks external Audio In, so we mute it on Ext. & Int.
-                                       * The PCB can take a sbx1637/sbx1673, wiring unknown.
-                                       * This card lacks PCI subsystem ID, sigh.
-                                       * audiomux=1: lower volume, 2+3: mute
-                                       * btwincap uses 0x80000/0x80003
-                                       */
-       .needs_tvaudio  = 0,
-       .no_msp34xx     = 1,
-       .pll            = PLL_28,
-       .tuner_type     = 5,
-       .tuner_addr     = ADDR_UNSET,
-       /* Samsung TCPA9095PC27A (BG+DK), philips compatible, w/FM, stereo and
-       radio signal strength indicators work fine. */
-       .has_radio      = 1,
-       /* GPIO Info:
-               GPIO0,1:   HEF4052 A0,A1
-               GPIO2:     HEF4052 nENABLE
-               GPIO3-7:   n.c.
-               GPIO8-13:  IRDC357 data0-5 (data6 n.c. ?) [chip not present on my card]
-               GPIO14,15: ??
-               GPIO16-21: n.c.
-               GPIO22,23: ??
-               ??       : mtu8b56ep microcontroller for IR (GPIO wiring unknown)*/
-},{
-       /* Arthur Tetzlaff-Deas, DSP Design Ltd <software@dspdesign.com> */
-       .name           = "DSP Design TCVIDEO",
-       .video_inputs   = 4,
-       .svhs           = -1,
-       .muxsel         = { 2, 3, 1, 0},
-       .pll            = PLL_28,
-       .tuner_type     = -1,
-       .tuner_addr     = ADDR_UNSET,
-},{
-
-       /* ---- card 0x50 ---------------------------------- */
-       .name           = "Hauppauge WinTV PVR",
-       .video_inputs   = 4,
-       .audio_inputs   = 1,
-       .tuner          = 0,
-       .svhs           = 2,
-       .muxsel         = { 2, 0, 1, 1},
-       .needs_tvaudio  = 1,
-       .pll            = PLL_28,
-       .tuner_type     = -1,
-       .tuner_addr     = ADDR_UNSET,
-
-       .gpiomask       = 7,
-       .audiomux       = {7},
-},{
-       .name           = "IODATA GV-BCTV5/PCI",
-       .video_inputs   = 3,
-       .audio_inputs   = 1,
-       .tuner          = 0,
-       .svhs           = 2,
-       .gpiomask       = 0x0f0f80,
-       .muxsel         = {2, 3, 1, 0},
-       .audiomux       = {0x030000, 0x010000, 0, 0, 0x020000, 0},
-       .no_msp34xx     = 1,
-       .pll            = PLL_28,
-       .tuner_type     = TUNER_PHILIPS_NTSC_M,
-       .tuner_addr     = ADDR_UNSET,
-       .audio_hook     = gvbctv5pci_audio,
-       .has_radio      = 1,
-},{
-       .name           = "Osprey 100/150 (878)", /* 0x1(2|3)-45C6-C1 */
-       .video_inputs   = 4,                  /* id-inputs-clock */
-       .audio_inputs   = 0,
-       .tuner          = -1,
-       .svhs           = 3,
-       .muxsel         = { 3, 2, 0, 1 },
-       .pll            = PLL_28,
-       .tuner_type     = -1,
-       .tuner_addr     = ADDR_UNSET,
-       .no_msp34xx     = 1,
-       .no_tda9875     = 1,
-       .no_tda7432     = 1,
-},{
-       .name           = "Osprey 100/150 (848)", /* 0x04-54C0-C1 & older boards */
-       .video_inputs   = 3,
-       .audio_inputs   = 0,
-       .tuner          = -1,
-       .svhs           = 2,
-       .muxsel         = { 2, 3, 1 },
-       .pll            = PLL_28,
-       .tuner_type     = -1,
-       .tuner_addr     = ADDR_UNSET,
-       .no_msp34xx     = 1,
-       .no_tda9875     = 1,
-       .no_tda7432     = 1,
-},{
-
-       /* ---- card 0x54 ---------------------------------- */
-       .name           = "Osprey 101 (848)", /* 0x05-40C0-C1 */
-       .video_inputs   = 2,
-       .audio_inputs   = 0,
-       .tuner          = -1,
-       .svhs           = 1,
-       .muxsel         = { 3, 1 },
-       .pll            = PLL_28,
-       .tuner_type     = -1,
-       .tuner_addr     = ADDR_UNSET,
-       .no_msp34xx     = 1,
-       .no_tda9875     = 1,
-       .no_tda7432     = 1,
-},{
-       .name           = "Osprey 101/151",       /* 0x1(4|5)-0004-C4 */
-       .video_inputs   = 1,
-       .audio_inputs   = 0,
-       .tuner          = -1,
-       .svhs           = -1,
-       .muxsel         = { 0 },
-       .pll            = PLL_28,
-       .tuner_type     = -1,
-       .tuner_addr     = ADDR_UNSET,
-       .no_msp34xx     = 1,
-       .no_tda9875     = 1,
-       .no_tda7432     = 1,
-},{
-       .name           = "Osprey 101/151 w/ svid",  /* 0x(16|17|20)-00C4-C1 */
-       .video_inputs   = 2,
-       .audio_inputs   = 0,
-       .tuner          = -1,
-       .svhs           = 1,
-       .muxsel         = { 0, 1 },
-       .pll            = PLL_28,
-       .tuner_type     = -1,
-       .tuner_addr     = ADDR_UNSET,
-       .no_msp34xx     = 1,
-       .no_tda9875     = 1,
-       .no_tda7432     = 1,
-},{
-       .name           = "Osprey 200/201/250/251",  /* 0x1(8|9|E|F)-0004-C4 */
-       .video_inputs   = 1,
-       .audio_inputs   = 1,
-       .tuner          = -1,
-       .svhs           = -1,
-       .muxsel         = { 0 },
-       .pll            = PLL_28,
-       .tuner_type     = UNSET,
-       .tuner_addr     = ADDR_UNSET,
-       .no_msp34xx     = 1,
-       .no_tda9875     = 1,
-       .no_tda7432     = 1,
-},{
-
-       /* ---- card 0x58 ---------------------------------- */
-       .name           = "Osprey 200/250",   /* 0x1(A|B)-00C4-C1 */
-       .video_inputs   = 2,
-       .audio_inputs   = 1,
-       .tuner          = -1,
-       .svhs           = 1,
-       .muxsel         = { 0, 1 },
-       .pll            = PLL_28,
-       .tuner_type     = UNSET,
-       .tuner_addr     = ADDR_UNSET,
-       .no_msp34xx     = 1,
-       .no_tda9875     = 1,
-       .no_tda7432     = 1,
-},{
-       .name           = "Osprey 210/220",   /* 0x1(A|B)-04C0-C1 */
-       .video_inputs   = 2,
-       .audio_inputs   = 1,
-       .tuner          = -1,
-       .svhs           = 1,
-       .muxsel         = { 2, 3 },
-       .pll            = PLL_28,
-       .tuner_type     = UNSET,
-       .tuner_addr     = ADDR_UNSET,
-       .no_msp34xx     = 1,
-       .no_tda9875     = 1,
-       .no_tda7432     = 1,
-},{
-       .name           = "Osprey 500",   /* 500 */
-       .video_inputs   = 2,
-       .audio_inputs   = 1,
-       .tuner          = -1,
-       .svhs           = 1,
-       .muxsel         = { 2, 3 },
-       .pll            = PLL_28,
-       .tuner_type     = -1,
-       .tuner_addr     = ADDR_UNSET,
-       .no_msp34xx     = 1,
-       .no_tda9875     = 1,
-       .no_tda7432     = 1,
-},{
-       .name           = "Osprey 540",   /* 540 */
-       .video_inputs   = 4,
-       .audio_inputs   = 1,
-       .tuner          = -1,
-       .pll            = PLL_28,
-       .tuner_type     = -1,
-       .tuner_addr     = ADDR_UNSET,
-       .no_msp34xx     = 1,
-       .no_tda9875     = 1,
-       .no_tda7432     = 1,
-},{
-
-       /* ---- card 0x5C ---------------------------------- */
-       .name           = "Osprey 2000",  /* 2000 */
-       .video_inputs   = 2,
-       .audio_inputs   = 1,
-       .tuner          = -1,
-       .svhs           = 1,
-       .muxsel         = { 2, 3 },
-       .pll            = PLL_28,
-       .tuner_type     = UNSET,
-       .tuner_addr     = ADDR_UNSET,
-       .no_msp34xx     = 1,
-       .no_tda9875     = 1,
-       .no_tda7432     = 1,      /* must avoid, conflicts with the bt860 */
-},{
-       /* M G Berberich <berberic@forwiss.uni-passau.de> */
-       .name           = "IDS Eagle",
-       .video_inputs   = 4,
-       .audio_inputs   = 0,
-       .tuner          = -1,
-       .tuner_type     = -1,
-       .tuner_addr     = ADDR_UNSET,
-       .svhs           = -1,
-       .gpiomask       = 0,
-       .muxsel         = { 0, 1, 2, 3 },
-       .muxsel_hook    = eagle_muxsel,
-       .no_msp34xx     = 1,
-       .no_tda9875     = 1,
-       .pll            = PLL_28,
-},{
-       .name           = "Pinnacle PCTV Sat",
-       .video_inputs   = 2,
-       .audio_inputs   = 0,
-       .svhs           = 1,
-       .tuner          = -1,
-       .tuner_type     = -1,
-       .tuner_addr     = ADDR_UNSET,
-       .no_msp34xx     = 1,
-       .no_tda9875     = 1,
-       .no_tda7432     = 1,
-       .gpiomask       = 0x01,
-       .audiomux       = { 0, 0, 0, 0, 1 },
-       .muxsel         = { 3, 0, 1, 2},
-       .needs_tvaudio  = 0,
-       .pll            = PLL_28,
-       .no_gpioirq     = 1,
-       .has_dvb        = 1,
-},{
-       .name           = "Formac ProTV II (bt878)",
-       .video_inputs   = 4,
-       .audio_inputs   = 1,
-       .tuner          = 0,
-       .svhs           = 3,
-       .gpiomask       = 2,
-       /* TV, Comp1, Composite over SVID con, SVID */
-       .muxsel         = { 2, 3, 1, 1},
-       .audiomux       = { 2, 2, 0, 0, 0 },
-       .pll            = PLL_28,
-       .has_radio      = 1,
-       .tuner_type     = TUNER_PHILIPS_PAL,
-       .tuner_addr     = ADDR_UNSET,
-/* sound routing:
-       GPIO=0x00,0x01,0x03: mute (?)
-       0x02: both TV and radio (tuner: FM1216/I)
-       The card has onboard audio connectors labeled "cdrom" and "board",
-       not soldered here, though unknown wiring.
-       Card lacks: external audio in, pci subsystem id.
-*/
-},{
-
-       /* ---- card 0x60 ---------------------------------- */
-       .name           = "MachTV",
-       .video_inputs   = 3,
-       .audio_inputs   = 1,
-       .tuner          = 0,
-       .svhs           = -1,
-       .gpiomask       = 7,
-       .muxsel         = { 2, 3, 1, 1},
-       .audiomux       = { 0, 1, 2, 3, 4},
-       .needs_tvaudio  = 1,
-       .tuner_type     = 5,
-       .tuner_addr     = ADDR_UNSET,
-       .pll            = 1,
-},{
-       .name           = "Euresys Picolo",
-       .video_inputs   = 3,
-       .audio_inputs   = 0,
-       .tuner          = -1,
-       .svhs           = 2,
-       .gpiomask       = 0,
-       .no_msp34xx     = 1,
-       .no_tda9875     = 1,
-       .no_tda7432     = 1,
-       .muxsel         = { 2, 0, 1},
-       .pll            = PLL_28,
-       .tuner_type     = UNSET,
-       .tuner_addr     = ADDR_UNSET,
-},{
-       /* Luc Van Hoeylandt <luc@e-magic.be> */
-       .name           = "ProVideo PV150", /* 0x4f */
-       .video_inputs   = 2,
-       .audio_inputs   = 0,
-       .tuner          = -1,
-       .svhs           = -1,
-       .gpiomask       = 0,
-       .muxsel         = { 2, 3 },
-       .audiomux       = { 0 },
-       .needs_tvaudio  = 0,
-       .no_msp34xx     = 1,
-       .pll            = PLL_28,
-       .tuner_type     = UNSET,
-       .tuner_addr     = ADDR_UNSET,
-},{
-       /* Hiroshi Takekawa <sian@big.or.jp> */
-       /* This card lacks subsystem ID */
-       .name           = "AD-TVK503", /* 0x63 */
-       .video_inputs   = 4,
-       .audio_inputs   = 1,
-       .tuner          = 0,
-       .svhs           = 2,
-       .gpiomask       = 0x001e8007,
-       .muxsel         = { 2, 3, 1, 0 },
-       /*                  Tuner, Radio, external, internal, off,  on */
-       .audiomux       = { 0x08,  0x0f,  0x0a,     0x08,     0x0f, 0x08 },
-       .needs_tvaudio  = 0,
-       .no_msp34xx     = 1,
-       .pll            = PLL_28,
-       .tuner_type     = 2,
-       .tuner_addr     = ADDR_UNSET,
-       .audio_hook     = adtvk503_audio,
-},{
-
-       /* ---- card 0x64 ---------------------------------- */
-       .name           = "Hercules Smart TV Stereo",
-       .video_inputs   = 4,
-       .audio_inputs   = 1,
-       .tuner          = 0,
-       .svhs           = 2,
-       .gpiomask       = 0x00,
-       .muxsel         = { 2, 3, 1, 1 },
-       .needs_tvaudio  = 1,
-       .no_msp34xx     = 1,
-       .pll            = PLL_28,
-       .tuner_type     = 5,
-       .tuner_addr     = ADDR_UNSET,
-       /* Notes:
-       - card lacks subsystem ID
-       - stereo variant w/ daughter board with tda9874a @0xb0
-       - Audio Routing:
-               always from tda9874 independent of GPIO (?)
-               external line in: unknown
-       - Other chips: em78p156elp @ 0x96 (probably IR remote control)
-               hef4053 (instead 4052) for unknown function
-       */
-},{
-       .name           = "Pace TV & Radio Card",
-       .video_inputs   = 4,
-       .audio_inputs   = 1,
-       .tuner          = 0,
-       .svhs           = 2,
-       .muxsel         = { 2, 3, 1, 1}, /* Tuner, CVid, SVid, CVid over SVid connector */
-       .gpiomask       = 0,
-       .no_tda9875     = 1,
-       .no_tda7432     = 1,
-       .tuner_type     = 1,
-       .tuner_addr     = ADDR_UNSET,
-       .has_radio      = 1,
-       .pll            = PLL_28,
-       /* Bt878, Bt832, FI1246 tuner; no pci subsystem id
-       only internal line out: (4pin header) RGGL
-       Radio must be decoded by msp3410d (not routed through)*/
-       /*
-       .digital_mode   = DIGITAL_MODE_CAMERA,  todo!
-       */
-},{
-       /* Chris Willing <chris@vislab.usyd.edu.au> */
-       .name           = "IVC-200",
-       .video_inputs   = 1,
-       .audio_inputs   = 0,
-       .tuner          = -1,
-       .tuner_type     = -1,
-       .tuner_addr     = ADDR_UNSET,
-       .svhs           = -1,
-       .gpiomask       = 0xdf,
-       .muxsel         = { 2 },
-       .pll            = PLL_28,
-},{
-       .name           = "Grand X-Guard / Trust 814PCI",
-       .video_inputs   = 16,
-       .audio_inputs   = 0,
-       .tuner          = -1,
-       .svhs           = -1,
-       .tuner_type     = 4,
-       .tuner_addr     = ADDR_UNSET,
-       .gpiomask2      = 0xff,
-       .muxsel         = { 2,2,2,2, 3,3,3,3, 1,1,1,1, 0,0,0,0 },
-       .muxsel_hook    = xguard_muxsel,
-       .no_msp34xx     = 1,
-       .no_tda9875     = 1,
-       .no_tda7432     = 1,
-       .pll            = PLL_28,
-},{
-
-       /* ---- card 0x68 ---------------------------------- */
-       .name           = "Nebula Electronics DigiTV",
-       .video_inputs   = 1,
-       .tuner          = -1,
-       .svhs           = -1,
-       .muxsel         = { 2, 3, 1, 0},
-       .no_msp34xx     = 1,
-       .no_tda9875     = 1,
-       .no_tda7432     = 1,
-       .pll            = PLL_28,
-       .tuner_type     = -1,
-       .tuner_addr     = ADDR_UNSET,
-       .has_dvb        = 1,
-       .no_gpioirq     = 1,
-},{
-       /* Jorge Boncompte - DTI2 <jorge@dti2.net> */
-       .name           = "ProVideo PV143",
-       .video_inputs   = 4,
-       .audio_inputs   = 0,
-       .tuner          = -1,
-       .svhs           = -1,
-       .gpiomask       = 0,
-       .muxsel         = { 2, 3, 1, 0 },
-       .audiomux       = { 0 },
-       .needs_tvaudio  = 0,
-       .no_msp34xx     = 1,
-       .pll            = PLL_28,
-       .tuner_type     = -1,
-       .tuner_addr     = ADDR_UNSET,
-},{
-       /* M.Klahr@phytec.de */
-       .name           = "PHYTEC VD-009-X1 MiniDIN (bt878)",
-       .video_inputs   = 4,
-       .audio_inputs   = 0,
-       .tuner          = -1, /* card has no tuner */
-       .svhs           = 3,
-       .gpiomask       = 0x00,
-       .muxsel         = { 2, 3, 1, 0},
-       .audiomux       = { 0, 0, 0, 0, 0, 0 }, /* card has no audio */
-       .needs_tvaudio  = 1,
-       .pll            = PLL_28,
-       .tuner_type     = -1,
-       .tuner_addr     = ADDR_UNSET,
-},{
-       .name           = "PHYTEC VD-009-X1 Combi (bt878)",
-       .video_inputs   = 4,
-       .audio_inputs   = 0,
-       .tuner          = -1, /* card has no tuner */
-       .svhs           = 3,
-       .gpiomask       = 0x00,
-       .muxsel         = { 2, 3, 1, 1},
-       .audiomux       = { 0, 0, 0, 0, 0, 0 }, /* card has no audio */
-       .needs_tvaudio  = 1,
-       .pll            = PLL_28,
-       .tuner_type     = -1,
-       .tuner_addr     = ADDR_UNSET,
-},{
-
-       /* ---- card 0x6c ---------------------------------- */
-       .name           = "PHYTEC VD-009 MiniDIN (bt878)",
-       .video_inputs   = 10,
-       .audio_inputs   = 0,
-       .tuner          = -1, /* card has no tuner */
-       .svhs           = 9,
-       .gpiomask       = 0x00,
-       .gpiomask2      = 0x03, /* gpiomask2 defines the bits used to switch audio
-                               via the upper nibble of muxsel. here: used for
-                               xternal video-mux */
-       .muxsel         = { 0x02, 0x12, 0x22, 0x32, 0x03, 0x13, 0x23, 0x33, 0x01, 0x00 },
-       .audiomux       = { 0, 0, 0, 0, 0, 0 }, /* card has no audio */
-       .needs_tvaudio  = 1,
-       .pll            = PLL_28,
-       .tuner_type     = -1,
-       .tuner_addr     = ADDR_UNSET,
-},{
-       .name           = "PHYTEC VD-009 Combi (bt878)",
-       .video_inputs   = 10,
-       .audio_inputs   = 0,
-       .tuner          = -1, /* card has no tuner */
-       .svhs           = 9,
-       .gpiomask       = 0x00,
-       .gpiomask2      = 0x03, /* gpiomask2 defines the bits used to switch audio
-                               via the upper nibble of muxsel. here: used for
-                               xternal video-mux */
-       .muxsel         = { 0x02, 0x12, 0x22, 0x32, 0x03, 0x13, 0x23, 0x33, 0x01, 0x01 },
-       .audiomux       = { 0, 0, 0, 0, 0, 0 }, /* card has no audio */
-       .needs_tvaudio  = 1,
-       .pll            = PLL_28,
-       .tuner_type     = -1,
-       .tuner_addr     = ADDR_UNSET,
-},{
-       .name           = "IVC-100",
-       .video_inputs   = 4,
-       .audio_inputs   = 0,
-       .tuner          = -1,
-       .tuner_type     = -1,
-       .tuner_addr     = ADDR_UNSET,
-       .svhs           = -1,
-       .gpiomask       = 0xdf,
-       .muxsel         = { 2, 3, 1, 0 },
-       .pll            = PLL_28,
-},{
-       /* IVC-120G - Alan Garfield <alan@fromorbit.com> */
-       .name           = "IVC-120G",
-       .video_inputs   = 16,
-       .audio_inputs   = 0,    /* card has no audio */
-       .tuner          = -1,   /* card has no tuner */
-       .tuner_type     = -1,
-       .tuner_addr     = ADDR_UNSET,
-       .svhs           = -1,   /* card has no svhs */
-       .needs_tvaudio  = 0,
-       .no_msp34xx     = 1,
-       .no_tda9875     = 1,
-       .no_tda7432     = 1,
-       .gpiomask       = 0x00,
-       .muxsel         = { 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08,
-                       0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10 },
-       .muxsel_hook    = ivc120_muxsel,
-       .pll            = PLL_28,
-},{
-
-       /* ---- card 0x70 ---------------------------------- */
-       .name           = "pcHDTV HD-2000 TV",
-       .video_inputs   = 4,
-       .audio_inputs   = 1,
-       .tuner          = 0,
-       .svhs           = 2,
-       .muxsel         = { 2, 3, 1, 0},
-       .tuner_type     = TUNER_PHILIPS_ATSC,
-       .tuner_addr     = ADDR_UNSET,
-       .has_dvb        = 1,
-},{
-       .name           = "Twinhan DST + clones",
-       .no_msp34xx     = 1,
-       .no_tda9875     = 1,
-       .no_tda7432     = 1,
-       .tuner_type     = TUNER_ABSENT,
-       .tuner_addr     = ADDR_UNSET,
-       .no_video       = 1,
-       .has_dvb        = 1,
-},{
-       .name           = "Winfast VC100",
-       .video_inputs   = 3,
-       .audio_inputs   = 0,
-       .svhs           = 1,
-       .tuner          = -1,
-       .muxsel         = { 3, 1, 1, 3}, /* Vid In, SVid In, Vid over SVid in connector */
-       .no_msp34xx     = 1,
-       .no_tda9875     = 1,
-       .no_tda7432     = 1,
-       .tuner_type     = TUNER_ABSENT,
-       .tuner_addr     = ADDR_UNSET,
-       .pll            = PLL_28,
-},{
-       .name           = "Teppro TEV-560/InterVision IV-560",
-       .video_inputs   = 3,
-       .audio_inputs   = 1,
-       .tuner          = 0,
-       .svhs           = 2,
-       .gpiomask       = 3,
-       .muxsel         = { 2, 3, 1, 1},
-       .audiomux       = { 1, 1, 1, 1, 0},
-       .needs_tvaudio  = 1,
-       .tuner_type     = TUNER_PHILIPS_PAL,
-       .tuner_addr     = ADDR_UNSET,
-       .pll            = PLL_35,
-},{
-
-       /* ---- card 0x74 ---------------------------------- */
-       .name           = "SIMUS GVC1100",
-       .video_inputs   = 4,
-       .audio_inputs   = 0,
-       .tuner          = -1,
-       .svhs           = -1,
-       .tuner_type     = -1,
-       .tuner_addr     = ADDR_UNSET,
-       .pll            = PLL_28,
-       .muxsel         = { 2, 2, 2, 2},
-       .gpiomask       = 0x3F,
-       .muxsel_hook    = gvc1100_muxsel,
-},{
-       /* Carlos Silva r3pek@r3pek.homelinux.org || card 0x75 */
-       .name           = "NGS NGSTV+",
-       .video_inputs   = 3,
-       .tuner          = 0,
-       .svhs           = 2,
-       .gpiomask       = 0x008007,
-       .muxsel         = {2, 3, 0, 0},
-       .audiomux       = {0, 0, 0, 0, 0x000003, 0},
-       .pll            = PLL_28,
-       .tuner_type     = TUNER_PHILIPS_PAL,
-       .tuner_addr     = ADDR_UNSET,
-       .has_remote     = 1,
-},{
-       /* http://linuxmedialabs.com */
-       .name           = "LMLBT4",
-       .video_inputs   = 4, /* IN1,IN2,IN3,IN4 */
-       .audio_inputs   = 0,
-       .tuner          = -1,
-       .svhs           = -1,
-       .muxsel         = { 2, 3, 1, 0 },
-       .no_msp34xx     = 1,
-       .no_tda9875     = 1,
-       .no_tda7432     = 1,
-       .needs_tvaudio  = 0,
-       .tuner_type     = -1,
-       .tuner_addr     = ADDR_UNSET,
-},{
-       /* Helmroos Harri <harri.helmroos@pp.inet.fi> */
-       .name           = "Tekram M205 PRO",
-       .video_inputs   = 3,
-       .audio_inputs   = 1,
-       .tuner          = 0,
-       .tuner_type     = TUNER_PHILIPS_PAL,
-       .tuner_addr     = ADDR_UNSET,
-       .svhs           = 2,
-       .needs_tvaudio  = 0,
-       .gpiomask       = 0x68,
-       .muxsel         = { 2, 3, 1},
-       .audiomux       = { 0x68, 0x68, 0x61, 0x61, 0x00 },
-       .pll            = PLL_28,
-},{
-
-       /* ---- card 0x78 ---------------------------------- */
-       /* Javier Cendan Ares <jcendan@lycos.es> */
-       /* bt878 TV + FM without subsystem ID */
-       .name           = "Conceptronic CONTVFMi",
-       .video_inputs   = 3,
-       .audio_inputs   = 1,
-       .tuner          = 0,
-       .svhs           = 2,
-       .gpiomask       = 0x008007,
-       .muxsel         = { 2, 3, 1, 1 },
-       .audiomux       = { 0, 1, 2, 2, 3 },
-       .needs_tvaudio  = 0,
-       .pll            = PLL_28,
-       .tuner_type     = TUNER_PHILIPS_PAL,
-       .tuner_addr     = ADDR_UNSET,
-       .has_remote     = 1,
-       .has_radio      = 1,
-},{
-       /*Eric DEBIEF <debief@telemsa.com>*/
-       /*EURESYS Picolo Tetra : 4 Conexant Fusion 878A, no audio, video input set with analog multiplexers GPIO controled*/
-       /* adds picolo_tetra_muxsel(), picolo_tetra_init(), the folowing declaration strucure, and #define BTTV_PICOLO_TETRA_CHIP*/
-       /*0x79 in bttv.h*/
-       .name           = "Euresys Picolo Tetra",
-       .video_inputs   = 4,
-       .audio_inputs   = 0,
-       .tuner          = -1,
-       .svhs           = -1,
-       .gpiomask       = 0,
-       .gpiomask2      = 0x3C<<16,/*Set the GPIO[18]->GPIO[21] as output pin.==> drive the video inputs through analog multiplexers*/
-       .no_msp34xx     = 1,
-       .no_tda9875     = 1,
-       .no_tda7432     = 1,
-       .muxsel         = {2,2,2,2},/*878A input is always MUX0, see above.*/
-       .audiomux       = { 0, 0, 0, 0, 0, 0 }, /* card has no audio */
-       .pll            = PLL_28,
-       .needs_tvaudio  = 0,
-       .muxsel_hook    = picolo_tetra_muxsel,/*Required as it doesn't follow the classic input selection policy*/
-       .tuner_type     = -1,
-       .tuner_addr     = ADDR_UNSET,
-},{
-       /* Spirit TV Tuner from http://spiritmodems.com.au */
-       /* Stafford Goodsell <surge@goliath.homeunix.org> */
-       .name           = "Spirit TV Tuner",
-       .video_inputs   = 3,
-       .audio_inputs   = 1,
-       .tuner          = 0,
-       .svhs           = 2,
-       .gpiomask       = 0x0000000f,
-       .muxsel         = { 2, 1, 1 },
-       .audiomux       = { 0x02, 0x00, 0x00, 0x00, 0x00},
-       .tuner_type     = TUNER_TEMIC_PAL,
-       .tuner_addr     = ADDR_UNSET,
-       .no_msp34xx     = 1,
-       .no_tda9875     = 1,
-},{
-       /* Wolfram Joost <wojo@frokaschwei.de> */
-       .name           = "AVerMedia AVerTV DVB-T 771",
-       .video_inputs   = 2,
-       .svhs           = 1,
-       .tuner          = -1,
-       .tuner_type     = TUNER_ABSENT,
-       .tuner_addr     = ADDR_UNSET,
-       .muxsel         = { 3 , 3 },
-       .no_msp34xx     = 1,
-       .no_tda9875     = 1,
-       .no_tda7432     = 1,
-       .pll            = PLL_28,
-       .has_dvb        = 1,
-       .no_gpioirq     = 1,
-       .has_remote     = 1,
-},{
-       /* ---- card 0x7c ---------------------------------- */
-       /* Matt Jesson <dvb@jesson.eclipse.co.uk> */
-       /* Based on the Nebula card data - added remote and new card number - BTTV_AVDVBT_761, see also ir-kbd-gpio.c */
-       .name           = "AverMedia AverTV DVB-T 761",
-       .video_inputs   = 2,
-       .tuner          = -1,
-       .svhs           = 1,
-       .muxsel         = { 3, 1, 2, 0}, /* Comp0, S-Video, ?, ? */
-       .no_msp34xx     = 1,
-       .no_tda9875     = 1,
-       .no_tda7432     = 1,
-       .pll            = PLL_28,
-       .tuner_type     = -1,
-       .tuner_addr     = ADDR_UNSET,
-       .has_dvb        = 1,
-       .no_gpioirq     = 1,
-       .has_remote     = 1,
-},{
-       /* andre.schwarz@matrix-vision.de */
-       .name             = "MATRIX Vision Sigma-SQ",
-       .video_inputs     = 16,
-       .audio_inputs     = 0,
-       .tuner            = -1,
-       .svhs             = -1,
-       .gpiomask         = 0x0,
-       .muxsel           = { 2, 2, 2, 2, 2, 2, 2, 2,
-                       3, 3, 3, 3, 3, 3, 3, 3 },
-       .muxsel_hook      = sigmaSQ_muxsel,
-       .audiomux         = { 0 },
-       .no_msp34xx       = 1,
-       .pll              = PLL_28,
-       .tuner_type       = -1,
-       .tuner_addr       = ADDR_UNSET,
-},{
-       /* andre.schwarz@matrix-vision.de */
-       .name             = "MATRIX Vision Sigma-SLC",
-       .video_inputs     = 4,
-       .audio_inputs     = 0,
-       .tuner            = -1,
-       .svhs             = -1,
-       .gpiomask         = 0x0,
-       .muxsel           = { 2, 2, 2, 2 },
-       .muxsel_hook      = sigmaSLC_muxsel,
-       .audiomux         = { 0 },
-       .no_msp34xx       = 1,
-       .pll              = PLL_28,
-       .tuner_type       = -1,
-       .tuner_addr       = ADDR_UNSET,
-},{
-       /* BTTV_APAC_VIEWCOMP */
-       /* Attila Kondoros <attila.kondoros@chello.hu> */
-       /* bt878 TV + FM 0x00000000 subsystem ID */
-       .name           = "APAC Viewcomp 878(AMAX)",
-       .video_inputs   = 2,
-       .audio_inputs   = 1,
-       .tuner          = 0,
-       .svhs           = -1,
-       .gpiomask       = 0xFF,
-       .muxsel         = { 2, 3, 1, 1},
-       .audiomux       = { 2, 0, 0, 0, 10},
-       .needs_tvaudio  = 0,
-       .pll            = PLL_28,
-       .tuner_type     = TUNER_PHILIPS_PAL,
-       .tuner_addr     = ADDR_UNSET,
-       .has_remote     = 1,   /* miniremote works, see ir-kbd-gpio.c */
-       .has_radio      = 1,   /* not every card has radio */
-},{
-
-       /* ---- card 0x80 ---------------------------------- */
-       /* Chris Pascoe <c.pascoe@itee.uq.edu.au> */
-       .name           = "DViCO FusionHDTV DVB-T Lite",
-       .tuner          = -1,
-       .no_msp34xx     = 1,
-       .no_tda9875     = 1,
-       .no_tda7432     = 1,
-       .pll            = PLL_28,
-       .no_video       = 1,
-       .has_dvb        = 1,
-       .tuner_type     = -1,
-       .tuner_addr     = ADDR_UNSET,
-},{
-       /* Steven <photon38@pchome.com.tw> */
-       .name           = "V-Gear MyVCD",
-       .video_inputs   = 3,
-       .audio_inputs   = 1,
-       .tuner          = 0,
-       .svhs           = 2,
-       .gpiomask       = 0x3f,
-       .muxsel         = {2, 3, 1, 0},
-       .audiomux       = {0x31, 0x31, 0x31, 0x31, 0x31, 0x31},
-       .no_msp34xx     = 1,
-       .pll            = PLL_28,
-       .tuner_type     = TUNER_PHILIPS_NTSC_M,
-       .tuner_addr     = ADDR_UNSET,
-       .has_radio      = 0,
-},{
-       /* Rick C <cryptdragoon@gmail.com> */
-       .name           = "Super TV Tuner",
-       .video_inputs   = 4,
-       .audio_inputs   = 1,
-       .tuner          = 0,
-       .svhs           = 2,
-       .muxsel         = { 2, 3, 1, 0},
-       .tuner_type     = TUNER_PHILIPS_NTSC,
-       .tuner_addr     = ADDR_UNSET,
-       .gpiomask       = 0x008007,
-       .audiomux       = { 0, 0x000001,0,0, 0},
-       .needs_tvaudio  = 1,
-       .has_radio      = 1,
-},{
-       /* Chris Fanning <video4linux@haydon.net> */
-       .name           = "Tibet Systems 'Progress DVR' CS16",
-       .video_inputs   = 16,
-       .audio_inputs   = 0,
-       .tuner          = -1,
-       .svhs           = -1,
-       .muxsel         = { 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2 },
-       .pll            = PLL_28,
-       .no_msp34xx     = 1,
-       .no_tda9875     = 1,
-       .no_tda7432     = 1,
-       .tuner_type     = -1,
-       .tuner_addr     = ADDR_UNSET,
-       .muxsel_hook    = tibetCS16_muxsel,
-},
-{
-       /* Bill Brack <wbrack@mmm.com.hk> */
-       /*
-       * Note that, because of the card's wiring, the "master"
-       * BT878A chip (i.e. the one which controls the analog switch
-       * and must use this card type) is the 2nd one detected.  The
-       * other 3 chips should use card type 0x85, whose description
-       * follows this one.  There is a EEPROM on the card (which is
-       * connected to the I2C of one of those other chips), but is
-       * not currently handled.  There is also a facility for a
-       * "monitor", which is also not currently implemented.
-       */
-       .name           = "Kodicom 4400R (master)",
-       .video_inputs   = 16,
-       .audio_inputs   = 0,
-       .tuner          = -1,
-       .tuner_type     = -1,
-       .tuner_addr     = ADDR_UNSET,
-       .svhs           = -1,
-       /* GPIO bits 0-9 used for analog switch:
-       *   00 - 03:    camera selector
-       *   04 - 06:    channel (controller) selector
-       *   07: data (1->on, 0->off)
-       *   08: strobe
-       *   09: reset
-       * bit 16 is input from sync separator for the channel
-       */
-       .gpiomask       = 0x0003ff,
-       .no_gpioirq     = 1,
-       .muxsel         = { 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3 },
-       .pll            = PLL_28,
-       .no_msp34xx     = 1,
-       .no_tda7432     = 1,
-       .no_tda9875     = 1,
-       .muxsel_hook    = kodicom4400r_muxsel,
-},
-{
-       /* Bill Brack <wbrack@mmm.com.hk> */
-       /* Note that, for reasons unknown, the "master" BT878A chip (i.e. the
-       * one which controls the analog switch, and must use the card type)
-       * is the 2nd one detected.  The other 3 chips should use this card
-       * type
+
+       },
+       [BTTV_BOARD_PXC200] = {
+               /* Jannik Fritsch <jannik@techfak.uni-bielefeld.de> */
+               .name           = "Imagenation PXC200",
+               .video_inputs   = 5,
+               .audio_inputs   = 1,
+               .tuner          = -1,
+               .svhs           = 1, /* was: 4 */
+               .gpiomask       = 0,
+               .muxsel         = { 2, 3, 1, 0, 0},
+               .audiomux       = { 0 },
+               .needs_tvaudio  = 1,
+               .tuner_type     = -1,
+               .tuner_addr     = ADDR_UNSET,
+               .radio_addr     = ADDR_UNSET,
+               .muxsel_hook    = PXC200_muxsel,
+
+       },
+       [BTTV_BOARD_FLYVIDEO_98] = {
+               .name           = "Lifeview FlyVideo 98 LR50",
+               .video_inputs   = 4,
+               .audio_inputs   = 1,
+               .tuner          = 0,
+               .svhs           = 2,
+               .gpiomask       = 0x1800,  /* 0x8dfe00 */
+               .muxsel         = { 2, 3, 1, 1},
+               .audiomux       = { 0, 0x0800, 0x1000, 0x1000, 0x1800, 0 },
+               .pll            = PLL_28,
+               .tuner_type     = -1,
+               .tuner_addr     = ADDR_UNSET,
+               .radio_addr     = ADDR_UNSET,
+       },
+       [BTTV_BOARD_IPROTV] = {
+               .name           = "Formac iProTV, Formac ProTV I (bt848)",
+               .video_inputs   = 4,
+               .audio_inputs   = 1,
+               .tuner          = 0,
+               .svhs           = 3,
+               .gpiomask       = 1,
+               .muxsel         = { 2, 3, 1, 1},
+               .audiomux       = { 1, 0, 0, 0, 0 },
+               .pll            = PLL_28,
+               .tuner_type     = TUNER_PHILIPS_PAL,
+               .tuner_addr     = ADDR_UNSET,
+               .radio_addr     = ADDR_UNSET,
+       },
+
+       /* ---- card 0x20 ---------------------------------- */
+       [BTTV_BOARD_INTEL_C_S_PCI] = {
+               .name           = "Intel Create and Share PCI/ Smart Video Recorder III",
+               .video_inputs   = 4,
+               .audio_inputs   = 0,
+               .tuner          = -1,
+               .svhs           = 2,
+               .gpiomask       = 0,
+               .muxsel         = { 2, 3, 1, 1},
+               .audiomux       = { 0 },
+               .needs_tvaudio  = 0,
+               .tuner_type     = 4,
+               .tuner_addr     = ADDR_UNSET,
+               .radio_addr     = ADDR_UNSET,
+       },
+       [BTTV_BOARD_TERRATVALUE] = {
+               .name           = "Terratec TerraTValue Version Bt878",
+               .video_inputs   = 3,
+               .audio_inputs   = 1,
+               .tuner          = 0,
+               .svhs           = 2,
+               .gpiomask       = 0xffff00,
+               .muxsel         = { 2, 3, 1, 1},
+               .audiomux       = { 0x500, 0, 0x300, 0x900, 0x900},
+               .needs_tvaudio  = 1,
+               .pll            = PLL_28,
+               .tuner_type     = TUNER_PHILIPS_PAL,
+               .tuner_addr     = ADDR_UNSET,
+               .radio_addr     = ADDR_UNSET,
+       },
+       [BTTV_BOARD_WINFAST2000] = {
+               .name           = "Leadtek WinFast 2000/ WinFast 2000 XP",
+               .video_inputs   = 4,
+               .audio_inputs   = 1,
+               .tuner          = 0,
+               .svhs           = 2,
+               .muxsel         = { 2, 3, 1, 1, 0}, /* TV, CVid, SVid, CVid over SVid connector */
+       #if 0
+               .gpiomask       = 0xc33000,
+               .audiomux       = { 0x422000,0x1000,0x0000,0x620000,0x800000 },
+       #else
+               /* Alexander Varakin <avarakin@hotmail.com> [stereo version] */
+               .gpiomask       = 0xb33000,
+               .audiomux       = { 0x122000,0x1000,0x0000,0x620000,0x800000 },
+       #endif
+               /* Audio Routing for "WinFast 2000 XP" (no tv stereo !)
+                       gpio23 -- hef4052:nEnable (0x800000)
+                       gpio12 -- hef4052:A1
+                       gpio13 -- hef4052:A0
+               0x0000: external audio
+               0x1000: FM
+               0x2000: TV
+               0x3000: n.c.
+               Note: There exists another variant "Winfast 2000" with tv stereo !?
+               Note: eeprom only contains FF and pci subsystem id 107d:6606
+               */
+               .needs_tvaudio  = 0,
+               .pll            = PLL_28,
+               .has_radio      = 1,
+               .tuner_type     = 5, /* default for now, gpio reads BFFF06 for Pal bg+dk */
+               .tuner_addr     = ADDR_UNSET,
+               .radio_addr     = ADDR_UNSET,
+               .audio_hook     = winfast2000_audio,
+               .has_remote     = 1,
+       },
+       [BTTV_BOARD_CHRONOS_VS2] = {
+               .name           = "Lifeview FlyVideo 98 LR50 / Chronos Video Shuttle II",
+               .video_inputs   = 4,
+               .audio_inputs   = 3,
+               .tuner          = 0,
+               .svhs           = 2,
+               .gpiomask       = 0x1800,
+               .muxsel         = { 2, 3, 1, 1},
+               .audiomux       = { 0, 0x800, 0x1000, 0x1000, 0x1800},
+               .pll            = PLL_28,
+               .tuner_type     = -1,
+               .tuner_addr     = ADDR_UNSET,
+               .radio_addr     = ADDR_UNSET,
+       },
+
+       /* ---- card 0x24 ---------------------------------- */
+       [BTTV_BOARD_TYPHOON_TVIEW] = {
+               .name           = "Lifeview FlyVideo 98FM LR50 / Typhoon TView TV/FM Tuner",
+               .video_inputs   = 4,
+               .audio_inputs   = 3,
+               .tuner          = 0,
+               .svhs           = 2,
+               .gpiomask       = 0x1800,
+               .muxsel         = { 2, 3, 1, 1},
+               .audiomux       = { 0, 0x800, 0x1000, 0x1000, 0x1800, 0 },
+               .pll            = PLL_28,
+               .tuner_type     = -1,
+               .tuner_addr     = ADDR_UNSET,
+               .radio_addr     = ADDR_UNSET,
+               .has_radio      = 1,
+       },
+       [BTTV_BOARD_PXELVWPLTVPRO] = {
+               .name           = "Prolink PixelView PlayTV pro",
+               .video_inputs   = 3,
+               .audio_inputs   = 1,
+               .tuner          = 0,
+               .svhs           = 2,
+               .gpiomask       = 0xff,
+               .muxsel         = { 2, 3, 1, 1 },
+               .audiomux       = { 0x21, 0x20, 0x24, 0x2c, 0x29, 0x29 },
+               .no_msp34xx     = 1,
+               .pll            = PLL_28,
+               .tuner_type     = -1,
+               .tuner_addr     = ADDR_UNSET,
+               .radio_addr     = ADDR_UNSET,
+       },
+       [BTTV_BOARD_MAGICTVIEW063] = {
+               .name           = "Askey CPH06X TView99",
+               .video_inputs   = 4,
+               .audio_inputs   = 1,
+               .tuner          = 0,
+               .svhs           = 2,
+               .gpiomask       = 0x551e00,
+               .muxsel         = { 2, 3, 1, 0},
+               .audiomux       = { 0x551400, 0x551200, 0, 0, 0x551c00, 0x551200 },
+               .needs_tvaudio  = 1,
+               .pll            = PLL_28,
+               .tuner_type     = 1,
+               .tuner_addr     = ADDR_UNSET,
+               .radio_addr     = ADDR_UNSET,
+               .has_remote     = 1,
+       },
+       [BTTV_BOARD_PINNACLE] = {
+               .name           = "Pinnacle PCTV Studio/Rave",
+               .video_inputs   = 3,
+               .audio_inputs   = 1,
+               .tuner          = 0,
+               .svhs           = 2,
+               .gpiomask       = 0x03000F,
+               .muxsel         = { 2, 3, 1, 1},
+               .audiomux       = { 2, 0xd0001, 0, 0, 1},
+               .needs_tvaudio  = 0,
+               .pll            = PLL_28,
+               .tuner_type     = -1,
+               .tuner_addr     = ADDR_UNSET,
+               .radio_addr     = ADDR_UNSET,
+       },
+
+       /* ---- card 0x28 ---------------------------------- */
+       [BTTV_BOARD_STB2] = {
+               .name           = "STB TV PCI FM, Gateway P/N 6000704 (bt878), 3Dfx VoodooTV 100",
+               .video_inputs   = 3,
+               .audio_inputs   = 1,
+               .tuner          = 0,
+               .svhs           = 2,
+               .gpiomask       = 7,
+               .muxsel         = { 2, 3, 1, 1},
+               .audiomux       = { 4, 0, 2, 3, 1},
+               .no_msp34xx     = 1,
+               .needs_tvaudio  = 1,
+               .tuner_type     = TUNER_PHILIPS_NTSC,
+               .tuner_addr     = ADDR_UNSET,
+               .radio_addr     = ADDR_UNSET,
+               .pll            = PLL_28,
+               .has_radio      = 1,
+       },
+       [BTTV_BOARD_AVPHONE98] = {
+               .name           = "AVerMedia TVPhone 98",
+               .video_inputs   = 3,
+               .audio_inputs   = 4,
+               .tuner          = 0,
+               .svhs           = 2,
+               .gpiomask       = 15,
+               .muxsel         = { 2, 3, 1, 1},
+               .audiomux       = { 13, 4, 11, 7, 0, 0},
+               .needs_tvaudio  = 1,
+               .pll            = PLL_28,
+               .tuner_type     = -1,
+               .tuner_addr     = ADDR_UNSET,
+               .radio_addr     = ADDR_UNSET,
+               .has_radio      = 1,
+               .audio_hook     = avermedia_tvphone_audio,
+       },
+       [BTTV_BOARD_PV951] = {
+               .name           = "ProVideo PV951", /* pic16c54 */
+               .video_inputs   = 3,
+               .audio_inputs   = 1,
+               .tuner          = 0,
+               .svhs           = 2,
+               .gpiomask       = 0,
+               .muxsel         = { 2, 3, 1, 1},
+               .audiomux       = { 0, 0, 0, 0, 0},
+               .needs_tvaudio  = 1,
+               .no_msp34xx     = 1,
+               .pll            = PLL_28,
+               .tuner_type     = 1,
+               .tuner_addr     = ADDR_UNSET,
+               .radio_addr     = ADDR_UNSET,
+       },
+       [BTTV_BOARD_ONAIR_TV] = {
+               .name           = "Little OnAir TV",
+               .video_inputs   = 3,
+               .audio_inputs   = 1,
+               .tuner          = 0,
+               .svhs           = 2,
+               .gpiomask       = 0xe00b,
+               .muxsel         = {2, 3, 1, 1},
+               .audiomux       = {0xff9ff6, 0xff9ff6, 0xff1ff7, 0, 0xff3ffc},
+               .no_msp34xx     = 1,
+               .tuner_type     = -1,
+               .tuner_addr     = ADDR_UNSET,
+               .radio_addr     = ADDR_UNSET,
+       },
+
+       /* ---- card 0x2c ---------------------------------- */
+       [BTTV_BOARD_SIGMA_TVII_FM] = {
+               .name           = "Sigma TVII-FM",
+               .video_inputs   = 2,
+               .audio_inputs   = 1,
+               .tuner          = 0,
+               .svhs           = -1,
+               .gpiomask       = 3,
+               .muxsel         = {2, 3, 1, 1},
+               .audiomux       = {1, 1, 0, 2, 3},
+               .no_msp34xx     = 1,
+               .pll            = PLL_NONE,
+               .tuner_type     = -1,
+               .tuner_addr     = ADDR_UNSET,
+               .radio_addr     = ADDR_UNSET,
+       },
+       [BTTV_BOARD_MATRIX_VISION2] = {
+               .name           = "MATRIX-Vision MV-Delta 2",
+               .video_inputs   = 5,
+               .audio_inputs   = 1,
+               .tuner          = -1,
+               .svhs           = 3,
+               .gpiomask       = 0,
+               .muxsel         = { 2, 3, 1, 0, 0},
+               .audiomux       = {0 },
+               .no_msp34xx     = 1,
+               .pll            = PLL_28,
+               .tuner_type     = -1,
+               .tuner_addr     = ADDR_UNSET,
+               .radio_addr     = ADDR_UNSET,
+       },
+       [BTTV_BOARD_ZOLTRIX_GENIE] = {
+               .name           = "Zoltrix Genie TV/FM",
+               .video_inputs   = 3,
+               .audio_inputs   = 1,
+               .tuner          = 0,
+               .svhs           = 2,
+               .gpiomask       = 0xbcf03f,
+               .muxsel         = { 2, 3, 1, 1},
+               .audiomux       = { 0xbc803f, 0xbc903f, 0xbcb03f, 0, 0xbcb03f},
+               .no_msp34xx     = 1,
+               .pll            = PLL_28,
+               .tuner_type     = 21,
+               .tuner_addr     = ADDR_UNSET,
+               .radio_addr     = ADDR_UNSET,
+       },
+       [BTTV_BOARD_TERRATVRADIO] = {
+               .name           = "Terratec TV/Radio+",
+               .video_inputs   = 3,
+               .audio_inputs   = 1,
+               .tuner          = 0,
+               .svhs           = 2,
+               .gpiomask       = 0x70000,
+               .muxsel         = { 2, 3, 1, 1},
+               .audiomux       = { 0x20000, 0x30000, 0x10000, 0, 0x40000, 0x20000 },
+               .needs_tvaudio  = 1,
+               .no_msp34xx     = 1,
+               .pll            = PLL_35,
+               .tuner_type     = 1,
+               .tuner_addr     = ADDR_UNSET,
+               .radio_addr     = ADDR_UNSET,
+               .has_radio      = 1,
+       },
+
+       /* ---- card 0x30 ---------------------------------- */
+       [BTTV_BOARD_DYNALINK] = {
+               .name           = "Askey CPH03x/ Dynalink Magic TView",
+               .video_inputs   = 3,
+               .audio_inputs   = 1,
+               .tuner          = 0,
+               .svhs           = 2,
+               .gpiomask       = 15,
+               .muxsel         = { 2, 3, 1, 1},
+               .audiomux       = {2,0,0,0,1},
+               .needs_tvaudio  = 1,
+               .pll            = PLL_28,
+               .tuner_type     = -1,
+               .tuner_addr     = ADDR_UNSET,
+               .radio_addr     = ADDR_UNSET,
+       },
+       [BTTV_BOARD_GVBCTV3PCI] = {
+               .name           = "IODATA GV-BCTV3/PCI",
+               .video_inputs   = 3,
+               .audio_inputs   = 1,
+               .tuner          = 0,
+               .svhs           = 2,
+               .gpiomask       = 0x010f00,
+               .muxsel         = {2, 3, 0, 0},
+               .audiomux       = {0x10000, 0, 0x10000, 0, 0, 0},
+               .no_msp34xx     = 1,
+               .pll            = PLL_28,
+               .tuner_type     = TUNER_ALPS_TSHC6_NTSC,
+               .tuner_addr     = ADDR_UNSET,
+               .radio_addr     = ADDR_UNSET,
+               .audio_hook     = gvbctv3pci_audio,
+       },
+       [BTTV_BOARD_PXELVWPLTVPAK] = {
+               .name           = "Prolink PV-BT878P+4E / PixelView PlayTV PAK / Lenco MXTV-9578 CP",
+               .video_inputs   = 5,
+               .audio_inputs   = 1,
+               .tuner          = 0,
+               .svhs           = 3,
+               .gpiomask       = 0xAA0000,
+               .muxsel         = { 2,3,1,1,-1 },
+               .digital_mode   = DIGITAL_MODE_CAMERA,
+               .audiomux       = { 0x20000, 0, 0x80000, 0x80000, 0xa8000, 0x46000  },
+               .no_msp34xx     = 1,
+               .pll            = PLL_28,
+               .tuner_type     = TUNER_PHILIPS_PAL_I,
+               .tuner_addr     = ADDR_UNSET,
+               .radio_addr     = ADDR_UNSET,
+               .has_remote     = 1,
+               /* GPIO wiring: (different from Rev.4C !)
+                       GPIO17: U4.A0 (first hef4052bt)
+                       GPIO19: U4.A1
+                       GPIO20: U5.A1 (second hef4052bt)
+                       GPIO21: U4.nEN
+                       GPIO22: BT832 Reset Line
+                       GPIO23: A5,A0, U5,nEN
+               Note: At i2c=0x8a is a Bt832 chip, which changes to 0x88 after being reset via GPIO22
+               */
+       },
+       [BTTV_BOARD_EAGLE] = {
+               .name           = "Eagle Wireless Capricorn2 (bt878A)",
+               .video_inputs   = 4,
+               .audio_inputs   = 1,
+               .tuner          = 0,
+               .svhs           = 2,
+               .gpiomask       = 7,
+               .muxsel         = { 2, 0, 1, 1},
+               .audiomux       = { 0, 1, 2, 3, 4},
+               .pll            = PLL_28,
+               .tuner_type     = -1 /* TUNER_ALPS_TMDH2_NTSC */,
+               .tuner_addr     = ADDR_UNSET,
+               .radio_addr     = ADDR_UNSET,
+       },
+
+       /* ---- card 0x34 ---------------------------------- */
+       [BTTV_BOARD_PINNACLEPRO] = {
+               /* David Härdeman <david@2gen.com> */
+               .name           = "Pinnacle PCTV Studio Pro",
+               .video_inputs   = 4,
+               .audio_inputs   = 1,
+               .tuner          = 0,
+               .svhs           = 3,
+               .gpiomask       = 0x03000F,
+               .muxsel         = { 2, 3, 1, 1},
+               .audiomux       = { 1, 0xd0001, 0, 0, 10},
+                               /* sound path (5 sources):
+                               MUX1 (mask 0x03), Enable Pin 0x08 (0=enable, 1=disable)
+                                       0= ext. Audio IN
+                                       1= from MUX2
+                                       2= Mono TV sound from Tuner
+                                       3= not connected
+                               MUX2 (mask 0x30000):
+                                       0,2,3= from MSP34xx
+                                       1= FM stereo Radio from Tuner */
+               .needs_tvaudio  = 0,
+               .pll            = PLL_28,
+               .tuner_type     = -1,
+               .tuner_addr     = ADDR_UNSET,
+               .radio_addr     = ADDR_UNSET,
+       },
+       [BTTV_BOARD_TVIEW_RDS_FM] = {
+               /* Claas Langbehn <claas@bigfoot.com>,
+               Sven Grothklags <sven@upb.de> */
+               .name           = "Typhoon TView RDS + FM Stereo / KNC1 TV Station RDS",
+               .video_inputs   = 4,
+               .audio_inputs   = 3,
+               .tuner          = 0,
+               .svhs           = 2,
+               .gpiomask       = 0x1c,
+               .muxsel         = { 2, 3, 1, 1},
+               .audiomux       = { 0, 0, 0x10, 8, 4 },
+               .needs_tvaudio  = 1,
+               .pll            = PLL_28,
+               .tuner_type     = TUNER_PHILIPS_PAL,
+               .tuner_addr     = ADDR_UNSET,
+               .radio_addr     = ADDR_UNSET,
+               .has_radio      = 1,
+       },
+       [BTTV_BOARD_LIFETEC_9415] = {
+               /* Tim Röstermundt <rosterm@uni-muenster.de>
+               in de.comp.os.unix.linux.hardware:
+                       options bttv card=0 pll=1 radio=1 gpiomask=0x18e0
+                       audiomux=0x44c71f,0x44d71f,0,0x44d71f,0x44dfff
+                       options tuner type=5 */
+               .name           = "Lifeview FlyVideo 2000 /FlyVideo A2/ Lifetec LT 9415 TV [LR90]",
+               .video_inputs   = 4,
+               .audio_inputs   = 1,
+               .tuner          = 0,
+               .svhs           = 2,
+               .gpiomask       = 0x18e0,
+               .muxsel         = { 2, 3, 1, 1},
+               .audiomux       = { 0x0000,0x0800,0x1000,0x1000,0x18e0 },
+                       /* For cards with tda9820/tda9821:
+                               0x0000: Tuner normal stereo
+                               0x0080: Tuner A2 SAP (second audio program = Zweikanalton)
+                               0x0880: Tuner A2 stereo */
+               .pll            = PLL_28,
+               .tuner_type     = -1,
+               .tuner_addr     = ADDR_UNSET,
+               .radio_addr     = ADDR_UNSET,
+       },
+       [BTTV_BOARD_BESTBUY_EASYTV] = {
+               /* Miguel Angel Alvarez <maacruz@navegalia.com>
+               old Easy TV BT848 version (model CPH031) */
+               .name           = "Askey CPH031/ BESTBUY Easy TV",
+               .video_inputs   = 4,
+               .audio_inputs   = 1,
+               .tuner          = 0,
+               .svhs           = 2,
+               .gpiomask       = 0xF,
+               .muxsel         = { 2, 3, 1, 0},
+               .audiomux       = { 2, 0, 0, 0, 10},
+               .needs_tvaudio  = 0,
+               .pll            = PLL_28,
+               .tuner_type     = TUNER_TEMIC_PAL,
+               .tuner_addr     = ADDR_UNSET,
+               .radio_addr     = ADDR_UNSET,
+       },
+
+       /* ---- card 0x38 ---------------------------------- */
+       [BTTV_BOARD_FLYVIDEO_98FM] = {
+               /* Gordon Heydon <gjheydon@bigfoot.com ('98) */
+               .name           = "Lifeview FlyVideo 98FM LR50",
+               .video_inputs   = 4,
+               .audio_inputs   = 3,
+               .tuner          = 0,
+               .svhs           = 2,
+               .gpiomask       = 0x1800,
+               .muxsel         = { 2, 3, 1, 1},
+               .audiomux       = { 0, 0x800, 0x1000, 0x1000, 0x1800, 0 },
+               .pll            = PLL_28,
+               .tuner_type     = 5,
+               .tuner_addr     = ADDR_UNSET,
+               .radio_addr     = ADDR_UNSET,
+       },
+               /* This is the ultimate cheapo capture card
+               * just a BT848A on a small PCB!
+               * Steve Hosgood <steve@equiinet.com> */
+       [BTTV_BOARD_GRANDTEC] = {
+               .name           = "GrandTec 'Grand Video Capture' (Bt848)",
+               .video_inputs   = 2,
+               .audio_inputs   = 0,
+               .tuner          = -1,
+               .svhs           = 1,
+               .gpiomask       = 0,
+               .muxsel         = { 3, 1 },
+               .audiomux       = { 0 },
+               .needs_tvaudio  = 0,
+               .no_msp34xx     = 1,
+               .pll            = PLL_35,
+               .tuner_type     = -1,
+               .tuner_addr     = ADDR_UNSET,
+               .radio_addr     = ADDR_UNSET,
+       },
+       [BTTV_BOARD_ASKEY_CPH060] = {
+               /* Daniel Herrington <daniel.herrington@home.com> */
+               .name           = "Askey CPH060/ Phoebe TV Master Only (No FM)",
+               .video_inputs   = 3,
+               .audio_inputs   = 1,
+               .tuner          = 0,
+               .svhs           = 2,
+               .gpiomask       = 0xe00,
+               .muxsel         = { 2, 3, 1, 1},
+               .audiomux       = { 0x400, 0x400, 0x400, 0x400, 0x800, 0x400 },
+               .needs_tvaudio  = 1,
+               .pll            = PLL_28,
+               .tuner_type     = TUNER_TEMIC_4036FY5_NTSC,
+               .tuner_addr     = ADDR_UNSET,
+               .radio_addr     = ADDR_UNSET,
+       },
+       [BTTV_BOARD_ASKEY_CPH03X] = {
+               /* Matti Mottus <mottus@physic.ut.ee> */
+               .name           = "Askey CPH03x TV Capturer",
+               .video_inputs   = 4,
+               .audio_inputs   = 1,
+               .tuner          = 0,
+               .svhs           = 2,
+               .gpiomask       = 0x03000F,
+               .muxsel         = { 2, 3, 1, 0},
+               .audiomux       = { 2,0,0,0,1 },
+               .pll            = PLL_28,
+               .tuner_type     = 0,
+               .tuner_addr     = ADDR_UNSET,
+               .radio_addr     = ADDR_UNSET,
+       },
+
+       /* ---- card 0x3c ---------------------------------- */
+       [BTTV_BOARD_MM100PCTV] = {
+               /* Philip Blundell <philb@gnu.org> */
+               .name           = "Modular Technology MM100PCTV",
+               .video_inputs   = 2,
+               .audio_inputs   = 2,
+               .tuner          = 0,
+               .svhs           = -1,
+               .gpiomask       = 11,
+               .muxsel         = { 2, 3, 1, 1},
+               .audiomux       = { 2, 0, 0, 1, 8},
+               .pll            = PLL_35,
+               .tuner_type     = TUNER_TEMIC_PAL,
+               .tuner_addr     = ADDR_UNSET,
+               .radio_addr     = ADDR_UNSET,
+       },
+       [BTTV_BOARD_GMV1] = {
+               /* Adrian Cox <adrian@humboldt.co.uk */
+               .name           = "AG Electronics GMV1",
+               .video_inputs   = 2,
+               .audio_inputs   = 0,
+               .tuner          = -1,
+               .svhs           = 1,
+               .gpiomask       = 0xF,
+               .muxsel         = { 2, 2},
+               .audiomux       = { },
+               .no_msp34xx     = 1,
+               .needs_tvaudio  = 0,
+               .pll            = PLL_28,
+               .tuner_type     = -1,
+               .tuner_addr     = ADDR_UNSET,
+               .radio_addr     = ADDR_UNSET,
+       },
+       [BTTV_BOARD_BESTBUY_EASYTV2] = {
+               /* Miguel Angel Alvarez <maacruz@navegalia.com>
+               new Easy TV BT878 version (model CPH061)
+               special thanks to Informatica Mieres for providing the card */
+               .name           = "Askey CPH061/ BESTBUY Easy TV (bt878)",
+               .video_inputs   = 3,
+               .audio_inputs   = 2,
+               .tuner          = 0,
+               .svhs           = 2,
+               .gpiomask       = 0xFF,
+               .muxsel         = { 2, 3, 1, 0},
+               .audiomux       = { 1, 0, 4, 4, 9},
+               .needs_tvaudio  = 0,
+               .pll            = PLL_28,
+               .tuner_type     = TUNER_PHILIPS_PAL,
+               .tuner_addr     = ADDR_UNSET,
+               .radio_addr     = ADDR_UNSET,
+       },
+       [BTTV_BOARD_ATI_TVWONDER] = {
+               /* Lukas Gebauer <geby@volny.cz> */
+               .name           = "ATI TV-Wonder",
+               .video_inputs   = 3,
+               .audio_inputs   = 1,
+               .tuner          = 0,
+               .svhs           = 2,
+               .gpiomask       = 0xf03f,
+               .muxsel         = { 2, 3, 1, 0 },
+               .audiomux       = { 0xbffe, 0, 0xbfff, 0, 0xbffe},
+               .pll            = PLL_28,
+               .tuner_type     = TUNER_TEMIC_4006FN5_MULTI_PAL,
+               .tuner_addr     = ADDR_UNSET,
+               .radio_addr     = ADDR_UNSET,
+       },
+
+       /* ---- card 0x40 ---------------------------------- */
+       [BTTV_BOARD_ATI_TVWONDERVE] = {
+               /* Lukas Gebauer <geby@volny.cz> */
+               .name           = "ATI TV-Wonder VE",
+               .video_inputs   = 2,
+               .audio_inputs   = 1,
+               .tuner          = 0,
+               .svhs           = -1,
+               .gpiomask       = 1,
+               .muxsel         = { 2, 3, 0, 1},
+               .audiomux       = { 0, 0, 1, 0, 0},
+               .no_msp34xx     = 1,
+               .pll            = PLL_28,
+               .tuner_type     = TUNER_TEMIC_4006FN5_MULTI_PAL,
+               .tuner_addr     = ADDR_UNSET,
+               .radio_addr     = ADDR_UNSET,
+       },
+       [BTTV_BOARD_FLYVIDEO2000] = {
+               /* DeeJay <deejay@westel900.net (2000S) */
+               .name           = "Lifeview FlyVideo 2000S LR90",
+               .video_inputs   = 3,
+               .audio_inputs   = 3,
+               .tuner          = 0,
+               .svhs           = 2,
+               .gpiomask       = 0x18e0,
+               .muxsel         = { 2, 3, 0, 1},
+                               /* Radio changed from 1e80 to 0x800 to make
+                               FlyVideo2000S in .hu happy (gm)*/
+                               /* -dk-???: set mute=0x1800 for tda9874h daughterboard */
+               .audiomux       = { 0x0000,0x0800,0x1000,0x1000,0x1800, 0x1080 },
+               .audio_hook     = fv2000s_audio,
+               .no_msp34xx     = 1,
+               .no_tda9875     = 1,
+               .needs_tvaudio  = 1,
+               .pll            = PLL_28,
+               .tuner_type     = 5,
+               .tuner_addr     = ADDR_UNSET,
+               .radio_addr     = ADDR_UNSET,
+       },
+       [BTTV_BOARD_TERRATVALUER] = {
+               .name           = "Terratec TValueRadio",
+               .video_inputs   = 3,
+               .audio_inputs   = 1,
+               .tuner          = 0,
+               .svhs           = 2,
+               .gpiomask       = 0xffff00,
+               .muxsel         = { 2, 3, 1, 1},
+               .audiomux       = { 0x500, 0x500, 0x300, 0x900, 0x900},
+               .needs_tvaudio  = 1,
+               .pll            = PLL_28,
+               .tuner_type     = TUNER_PHILIPS_PAL,
+               .tuner_addr     = ADDR_UNSET,
+               .radio_addr     = ADDR_UNSET,
+               .has_radio      = 1,
+       },
+       [BTTV_BOARD_GVBCTV4PCI] = {
+               /* TANAKA Kei <peg00625@nifty.com> */
+               .name           = "IODATA GV-BCTV4/PCI",
+               .video_inputs   = 3,
+               .audio_inputs   = 1,
+               .tuner          = 0,
+               .svhs           = 2,
+               .gpiomask       = 0x010f00,
+               .muxsel         = {2, 3, 0, 0},
+               .audiomux       = {0x10000, 0, 0x10000, 0, 0, 0},
+               .no_msp34xx     = 1,
+               .pll            = PLL_28,
+               .tuner_type     = TUNER_SHARP_2U5JF5540_NTSC,
+               .tuner_addr     = ADDR_UNSET,
+               .radio_addr     = ADDR_UNSET,
+               .audio_hook     = gvbctv3pci_audio,
+       },
+
+       /* ---- card 0x44 ---------------------------------- */
+       [BTTV_BOARD_VOODOOTV_FM] = {
+               .name           = "3Dfx VoodooTV FM (Euro), VoodooTV 200 (USA)",
+               /* try "insmod msp3400 simple=0" if you have
+               * sound problems with this card. */
+               .video_inputs   = 4,
+               .audio_inputs   = 1,
+               .tuner          = 0,
+               .svhs           = -1,
+               .gpiomask       = 0x4f8a00,
+               /* 0x100000: 1=MSP enabled (0=disable again)
+               * 0x010000: Connected to "S0" on tda9880 (0=Pal/BG, 1=NTSC) */
+               .audiomux       = {0x947fff, 0x987fff,0x947fff,0x947fff, 0x947fff},
+               /* tvtuner, radio,   external,internal, mute,  stereo
+               * tuner, Composit, SVid, Composit-on-Svid-adapter */
+               .muxsel         = { 2, 3 ,0 ,1},
+               .tuner_type     = TUNER_MT2032,
+               .tuner_addr     = ADDR_UNSET,
+               .radio_addr     = ADDR_UNSET,
+               .pll            = PLL_28,
+               .has_radio      = 1,
+       },
+       [BTTV_BOARD_AIMMS] = {
+               /* Philip Blundell <pb@nexus.co.uk> */
+               .name           = "Active Imaging AIMMS",
+               .video_inputs   = 1,
+               .audio_inputs   = 0,
+               .tuner          = -1,
+               .tuner_type     = -1,
+               .tuner_addr     = ADDR_UNSET,
+               .radio_addr     = ADDR_UNSET,
+               .pll            = PLL_28,
+               .muxsel         = { 2 },
+               .gpiomask       = 0
+       },
+       [BTTV_BOARD_PV_BT878P_PLUS] = {
+               /* Tomasz Pyra <hellfire@sedez.iq.pl> */
+               .name           = "Prolink Pixelview PV-BT878P+ (Rev.4C,8E)",
+               .video_inputs   = 3,
+               .audio_inputs   = 4,
+               .tuner          = 0,
+               .svhs           = 2,
+               .gpiomask       = 15,
+               .muxsel         = { 2, 3, 1, 1},
+               .audiomux       = { 0, 0, 11, 7, 13, 0}, /* TV and Radio with same GPIO ! */
+               .needs_tvaudio  = 1,
+               .pll            = PLL_28,
+               .tuner_type     = 25,
+               .tuner_addr     = ADDR_UNSET,
+               .radio_addr     = ADDR_UNSET,
+               .has_remote     = 1,
+               /* GPIO wiring:
+                       GPIO0: U4.A0 (hef4052bt)
+                       GPIO1: U4.A1
+                       GPIO2: U4.A1 (second hef4052bt)
+                       GPIO3: U4.nEN, U5.A0, A5.nEN
+                       GPIO8-15: vrd866b ?
+               */
+       },
+       [BTTV_BOARD_FLYVIDEO98EZ] = {
+               .name           = "Lifeview FlyVideo 98EZ (capture only) LR51",
+               .video_inputs   = 4,
+               .audio_inputs   = 0,
+               .tuner          = -1,
+               .svhs           = 2,
+               .muxsel         = { 2, 3, 1, 1}, /* AV1, AV2, SVHS, CVid adapter on SVHS */
+               .pll            = PLL_28,
+               .no_msp34xx     = 1,
+               .tuner_type     = UNSET,
+               .tuner_addr     = ADDR_UNSET,
+               .radio_addr     = ADDR_UNSET,
+       },
+
+       /* ---- card 0x48 ---------------------------------- */
+       [BTTV_BOARD_PV_BT878P_9B] = {
+               /* Dariusz Kowalewski <darekk@automex.pl> */
+               .name           = "Prolink Pixelview PV-BT878P+9B (PlayTV Pro rev.9B FM+NICAM)",
+               .video_inputs   = 4,
+               .audio_inputs   = 1,
+               .tuner          = 0,
+               .svhs           = 2,
+               .gpiomask       = 0x3f,
+               .muxsel         = { 2, 3, 1, 1 },
+               .audiomux       = { 0x01, 0x00, 0x03, 0x03, 0x09, 0x02 },
+               .needs_tvaudio  = 1,
+               .no_msp34xx     = 1,
+               .no_tda9875     = 1,
+               .pll            = PLL_28,
+               .tuner_type     = 5,
+               .tuner_addr     = ADDR_UNSET,
+               .radio_addr     = ADDR_UNSET,
+               .audio_hook     = pvbt878p9b_audio, /* Note: not all cards have stereo */
+               .has_radio      = 1,  /* Note: not all cards have radio */
+               .has_remote     = 1,
+               /* GPIO wiring:
+                       GPIO0: A0 hef4052
+                       GPIO1: A1 hef4052
+                       GPIO3: nEN hef4052
+                       GPIO8-15: vrd866b
+                       GPIO20,22,23: R30,R29,R28
+               */
+       },
+       [BTTV_BOARD_SENSORAY311] = {
+               /* Clay Kunz <ckunz@mail.arc.nasa.gov> */
+               /* you must jumper JP5 for the card to work */
+               .name           = "Sensoray 311",
+               .video_inputs   = 5,
+               .audio_inputs   = 0,
+               .tuner          = -1,
+               .svhs           = 4,
+               .gpiomask       = 0,
+               .muxsel         = { 2, 3, 1, 0, 0},
+               .audiomux       = { 0 },
+               .needs_tvaudio  = 0,
+               .tuner_type     = -1,
+               .tuner_addr     = ADDR_UNSET,
+               .radio_addr     = ADDR_UNSET,
+       },
+       [BTTV_BOARD_RV605] = {
+               /* Miguel Freitas <miguel@cetuc.puc-rio.br> */
+               .name           = "RemoteVision MX (RV605)",
+               .video_inputs   = 16,
+               .audio_inputs   = 0,
+               .tuner          = -1,
+               .svhs           = -1,
+               .gpiomask       = 0x00,
+               .gpiomask2      = 0x07ff,
+               .muxsel         = { 0x33, 0x13, 0x23, 0x43, 0xf3, 0x73, 0xe3, 0x03,
+                               0xd3, 0xb3, 0xc3, 0x63, 0x93, 0x53, 0x83, 0xa3 },
+               .no_msp34xx     = 1,
+               .no_tda9875     = 1,
+               .tuner_type     = -1,
+               .tuner_addr     = ADDR_UNSET,
+               .radio_addr     = ADDR_UNSET,
+               .muxsel_hook    = rv605_muxsel,
+       },
+       [BTTV_BOARD_POWERCLR_MTV878] = {
+               .name           = "Powercolor MTV878/ MTV878R/ MTV878F",
+               .video_inputs   = 3,
+               .audio_inputs   = 2,
+               .tuner          = 0,
+               .svhs           = 2,
+               .gpiomask       = 0x1C800F,  /* Bit0-2: Audio select, 8-12:remote control 14:remote valid 15:remote reset */
+               .muxsel         = { 2, 1, 1, },
+               .audiomux       = { 0, 1, 2, 2, 4 },
+               .needs_tvaudio  = 0,
+               .tuner_type     = TUNER_PHILIPS_PAL,
+               .tuner_addr     = ADDR_UNSET,
+               .radio_addr     = ADDR_UNSET,
+               .pll            = PLL_28,
+               .has_radio      = 1,
+       },
+
+       /* ---- card 0x4c ---------------------------------- */
+       [BTTV_BOARD_WINDVR] = {
+               /* Masaki Suzuki <masaki@btree.org> */
+               .name           = "Canopus WinDVR PCI (COMPAQ Presario 3524JP, 5112JP)",
+               .video_inputs   = 3,
+               .audio_inputs   = 1,
+               .tuner          = 0,
+               .svhs           = 2,
+               .gpiomask       = 0x140007,
+               .muxsel         = { 2, 3, 1, 1 },
+               .audiomux       = { 0, 1, 2, 3, 4, 0 },
+               .tuner_type     = TUNER_PHILIPS_NTSC,
+               .tuner_addr     = ADDR_UNSET,
+               .radio_addr     = ADDR_UNSET,
+               .audio_hook     = windvr_audio,
+       },
+       [BTTV_BOARD_GRANDTEC_MULTI] = {
+               .name           = "GrandTec Multi Capture Card (Bt878)",
+               .video_inputs   = 4,
+               .audio_inputs   = 0,
+               .tuner          = -1,
+               .svhs           = -1,
+               .gpiomask       = 0,
+               .muxsel         = { 2, 3, 1, 0 },
+               .audiomux       = { 0 },
+               .needs_tvaudio  = 0,
+               .no_msp34xx     = 1,
+               .pll            = PLL_28,
+               .tuner_type     = -1,
+               .tuner_addr     = ADDR_UNSET,
+               .radio_addr     = ADDR_UNSET,
+       },
+       [BTTV_BOARD_KWORLD] = {
+               .name           = "Jetway TV/Capture JW-TV878-FBK, Kworld KW-TV878RF",
+               .video_inputs   = 4,
+               .audio_inputs   = 3,
+               .tuner          = 0,
+               .svhs           = 2,
+               .gpiomask       = 7,
+               .muxsel         = { 2, 3, 1, 1 },   /* Tuner, SVid, SVHS, SVid to SVHS connector */
+               .audiomux       = { 0 ,0 ,4, 4,4,4},/* Yes, this tuner uses the same audio output for TV and FM radio!
+                                               * This card lacks external Audio In, so we mute it on Ext. & Int.
+                                               * The PCB can take a sbx1637/sbx1673, wiring unknown.
+                                               * This card lacks PCI subsystem ID, sigh.
+                                               * audiomux=1: lower volume, 2+3: mute
+                                               * btwincap uses 0x80000/0x80003
+                                               */
+               .needs_tvaudio  = 0,
+               .no_msp34xx     = 1,
+               .pll            = PLL_28,
+               .tuner_type     = 5,
+               .tuner_addr     = ADDR_UNSET,
+               .radio_addr     = ADDR_UNSET,
+               /* Samsung TCPA9095PC27A (BG+DK), philips compatible, w/FM, stereo and
+               radio signal strength indicators work fine. */
+               .has_radio      = 1,
+               /* GPIO Info:
+                       GPIO0,1:   HEF4052 A0,A1
+                       GPIO2:     HEF4052 nENABLE
+                       GPIO3-7:   n.c.
+                       GPIO8-13:  IRDC357 data0-5 (data6 n.c. ?) [chip not present on my card]
+                       GPIO14,15: ??
+                       GPIO16-21: n.c.
+                       GPIO22,23: ??
+                       ??       : mtu8b56ep microcontroller for IR (GPIO wiring unknown)*/
+       },
+       [BTTV_BOARD_DSP_TCVIDEO] = {
+               /* Arthur Tetzlaff-Deas, DSP Design Ltd <software@dspdesign.com> */
+               .name           = "DSP Design TCVIDEO",
+               .video_inputs   = 4,
+               .svhs           = -1,
+               .muxsel         = { 2, 3, 1, 0},
+               .pll            = PLL_28,
+               .tuner_type     = -1,
+               .tuner_addr     = ADDR_UNSET,
+               .radio_addr     = ADDR_UNSET,
+       },
+
+               /* ---- card 0x50 ---------------------------------- */
+       [BTTV_BOARD_HAUPPAUGEPVR] = {
+               .name           = "Hauppauge WinTV PVR",
+               .video_inputs   = 4,
+               .audio_inputs   = 1,
+               .tuner          = 0,
+               .svhs           = 2,
+               .muxsel         = { 2, 0, 1, 1},
+               .needs_tvaudio  = 1,
+               .pll            = PLL_28,
+               .tuner_type     = -1,
+               .tuner_addr     = ADDR_UNSET,
+               .radio_addr     = ADDR_UNSET,
+
+               .gpiomask       = 7,
+               .audiomux       = {7},
+       },
+       [BTTV_BOARD_GVBCTV5PCI] = {
+               .name           = "IODATA GV-BCTV5/PCI",
+               .video_inputs   = 3,
+               .audio_inputs   = 1,
+               .tuner          = 0,
+               .svhs           = 2,
+               .gpiomask       = 0x0f0f80,
+               .muxsel         = {2, 3, 1, 0},
+               .audiomux       = {0x030000, 0x010000, 0, 0, 0x020000, 0},
+               .no_msp34xx     = 1,
+               .pll            = PLL_28,
+               .tuner_type     = TUNER_PHILIPS_NTSC_M,
+               .tuner_addr     = ADDR_UNSET,
+               .radio_addr     = ADDR_UNSET,
+               .audio_hook     = gvbctv5pci_audio,
+               .has_radio      = 1,
+       },
+       [BTTV_BOARD_OSPREY1x0] = {
+               .name           = "Osprey 100/150 (878)", /* 0x1(2|3)-45C6-C1 */
+               .video_inputs   = 4,                  /* id-inputs-clock */
+               .audio_inputs   = 0,
+               .tuner          = -1,
+               .svhs           = 3,
+               .muxsel         = { 3, 2, 0, 1 },
+               .pll            = PLL_28,
+               .tuner_type     = -1,
+               .tuner_addr     = ADDR_UNSET,
+               .radio_addr     = ADDR_UNSET,
+               .no_msp34xx     = 1,
+               .no_tda9875     = 1,
+               .no_tda7432     = 1,
+       },
+       [BTTV_BOARD_OSPREY1x0_848] = {
+               .name           = "Osprey 100/150 (848)", /* 0x04-54C0-C1 & older boards */
+               .video_inputs   = 3,
+               .audio_inputs   = 0,
+               .tuner          = -1,
+               .svhs           = 2,
+               .muxsel         = { 2, 3, 1 },
+               .pll            = PLL_28,
+               .tuner_type     = -1,
+               .tuner_addr     = ADDR_UNSET,
+               .radio_addr     = ADDR_UNSET,
+               .no_msp34xx     = 1,
+               .no_tda9875     = 1,
+               .no_tda7432     = 1,
+       },
+
+               /* ---- card 0x54 ---------------------------------- */
+       [BTTV_BOARD_OSPREY101_848] = {
+               .name           = "Osprey 101 (848)", /* 0x05-40C0-C1 */
+               .video_inputs   = 2,
+               .audio_inputs   = 0,
+               .tuner          = -1,
+               .svhs           = 1,
+               .muxsel         = { 3, 1 },
+               .pll            = PLL_28,
+               .tuner_type     = -1,
+               .tuner_addr     = ADDR_UNSET,
+               .radio_addr     = ADDR_UNSET,
+               .no_msp34xx     = 1,
+               .no_tda9875     = 1,
+               .no_tda7432     = 1,
+       },
+       [BTTV_BOARD_OSPREY1x1] = {
+               .name           = "Osprey 101/151",       /* 0x1(4|5)-0004-C4 */
+               .video_inputs   = 1,
+               .audio_inputs   = 0,
+               .tuner          = -1,
+               .svhs           = -1,
+               .muxsel         = { 0 },
+               .pll            = PLL_28,
+               .tuner_type     = -1,
+               .tuner_addr     = ADDR_UNSET,
+               .radio_addr     = ADDR_UNSET,
+               .no_msp34xx     = 1,
+               .no_tda9875     = 1,
+               .no_tda7432     = 1,
+       },
+       [BTTV_BOARD_OSPREY1x1_SVID] = {
+               .name           = "Osprey 101/151 w/ svid",  /* 0x(16|17|20)-00C4-C1 */
+               .video_inputs   = 2,
+               .audio_inputs   = 0,
+               .tuner          = -1,
+               .svhs           = 1,
+               .muxsel         = { 0, 1 },
+               .pll            = PLL_28,
+               .tuner_type     = -1,
+               .tuner_addr     = ADDR_UNSET,
+               .radio_addr     = ADDR_UNSET,
+               .no_msp34xx     = 1,
+               .no_tda9875     = 1,
+               .no_tda7432     = 1,
+       },
+       [BTTV_BOARD_OSPREY2xx] = {
+               .name           = "Osprey 200/201/250/251",  /* 0x1(8|9|E|F)-0004-C4 */
+               .video_inputs   = 1,
+               .audio_inputs   = 1,
+               .tuner          = -1,
+               .svhs           = -1,
+               .muxsel         = { 0 },
+               .pll            = PLL_28,
+               .tuner_type     = UNSET,
+               .tuner_addr     = ADDR_UNSET,
+               .radio_addr     = ADDR_UNSET,
+               .no_msp34xx     = 1,
+               .no_tda9875     = 1,
+               .no_tda7432     = 1,
+       },
+
+               /* ---- card 0x58 ---------------------------------- */
+       [BTTV_BOARD_OSPREY2x0_SVID] = {
+               .name           = "Osprey 200/250",   /* 0x1(A|B)-00C4-C1 */
+               .video_inputs   = 2,
+               .audio_inputs   = 1,
+               .tuner          = -1,
+               .svhs           = 1,
+               .muxsel         = { 0, 1 },
+               .pll            = PLL_28,
+               .tuner_type     = UNSET,
+               .tuner_addr     = ADDR_UNSET,
+               .radio_addr     = ADDR_UNSET,
+               .no_msp34xx     = 1,
+               .no_tda9875     = 1,
+               .no_tda7432     = 1,
+       },
+       [BTTV_BOARD_OSPREY2x0] = {
+               .name           = "Osprey 210/220",   /* 0x1(A|B)-04C0-C1 */
+               .video_inputs   = 2,
+               .audio_inputs   = 1,
+               .tuner          = -1,
+               .svhs           = 1,
+               .muxsel         = { 2, 3 },
+               .pll            = PLL_28,
+               .tuner_type     = UNSET,
+               .tuner_addr     = ADDR_UNSET,
+               .radio_addr     = ADDR_UNSET,
+               .no_msp34xx     = 1,
+               .no_tda9875     = 1,
+               .no_tda7432     = 1,
+       },
+       [BTTV_BOARD_OSPREY500] = {
+               .name           = "Osprey 500",   /* 500 */
+               .video_inputs   = 2,
+               .audio_inputs   = 1,
+               .tuner          = -1,
+               .svhs           = 1,
+               .muxsel         = { 2, 3 },
+               .pll            = PLL_28,
+               .tuner_type     = -1,
+               .tuner_addr     = ADDR_UNSET,
+               .radio_addr     = ADDR_UNSET,
+               .no_msp34xx     = 1,
+               .no_tda9875     = 1,
+               .no_tda7432     = 1,
+       },
+       [BTTV_BOARD_OSPREY540] = {
+               .name           = "Osprey 540",   /* 540 */
+               .video_inputs   = 4,
+               .audio_inputs   = 1,
+               .tuner          = -1,
+       #if 0 /* TODO ... */
+               .svhs           = OSPREY540_SVID_ANALOG,
+               .muxsel         = {       [OSPREY540_COMP_ANALOG] = 2,
+                                       [OSPREY540_SVID_ANALOG] = 3, },
+       #endif
+               .pll            = PLL_28,
+               .tuner_type     = -1,
+               .tuner_addr     = ADDR_UNSET,
+               .radio_addr     = ADDR_UNSET,
+               .no_msp34xx     = 1,
+               .no_tda9875     = 1,
+               .no_tda7432     = 1,
+       #if 0 /* TODO ... */
+               .muxsel_hook    = osprey_540_muxsel,
+               .picture_hook   = osprey_540_set_picture,
+       #endif
+       },
+
+               /* ---- card 0x5C ---------------------------------- */
+       [BTTV_BOARD_OSPREY2000] = {
+               .name           = "Osprey 2000",  /* 2000 */
+               .video_inputs   = 2,
+               .audio_inputs   = 1,
+               .tuner          = -1,
+               .svhs           = 1,
+               .muxsel         = { 2, 3 },
+               .pll            = PLL_28,
+               .tuner_type     = UNSET,
+               .tuner_addr     = ADDR_UNSET,
+               .radio_addr     = ADDR_UNSET,
+               .no_msp34xx     = 1,
+               .no_tda9875     = 1,
+               .no_tda7432     = 1,      /* must avoid, conflicts with the bt860 */
+       },
+       [BTTV_BOARD_IDS_EAGLE] = {
+               /* M G Berberich <berberic@forwiss.uni-passau.de> */
+               .name           = "IDS Eagle",
+               .video_inputs   = 4,
+               .audio_inputs   = 0,
+               .tuner          = -1,
+               .tuner_type     = -1,
+               .tuner_addr     = ADDR_UNSET,
+               .radio_addr     = ADDR_UNSET,
+               .svhs           = -1,
+               .gpiomask       = 0,
+               .muxsel         = { 0, 1, 2, 3 },
+               .muxsel_hook    = eagle_muxsel,
+               .no_msp34xx     = 1,
+               .no_tda9875     = 1,
+               .pll            = PLL_28,
+       },
+       [BTTV_BOARD_PINNACLESAT] = {
+               .name           = "Pinnacle PCTV Sat",
+               .video_inputs   = 2,
+               .audio_inputs   = 0,
+               .svhs           = 1,
+               .tuner          = -1,
+               .tuner_type     = -1,
+               .tuner_addr     = ADDR_UNSET,
+               .radio_addr     = ADDR_UNSET,
+               .no_msp34xx     = 1,
+               .no_tda9875     = 1,
+               .no_tda7432     = 1,
+               .muxsel         = { 3, 0, 1, 2},
+               .pll            = PLL_28,
+               .no_gpioirq     = 1,
+               .has_dvb        = 1,
+       },
+       [BTTV_BOARD_FORMAC_PROTV] = {
+               .name           = "Formac ProTV II (bt878)",
+               .video_inputs   = 4,
+               .audio_inputs   = 1,
+               .tuner          = 0,
+               .svhs           = 3,
+               .gpiomask       = 2,
+               /* TV, Comp1, Composite over SVID con, SVID */
+               .muxsel         = { 2, 3, 1, 1},
+               .audiomux       = { 2, 2, 0, 0, 0 },
+               .pll            = PLL_28,
+               .has_radio      = 1,
+               .tuner_type     = TUNER_PHILIPS_PAL,
+               .tuner_addr     = ADDR_UNSET,
+               .radio_addr     = ADDR_UNSET,
+       /* sound routing:
+               GPIO=0x00,0x01,0x03: mute (?)
+               0x02: both TV and radio (tuner: FM1216/I)
+               The card has onboard audio connectors labeled "cdrom" and "board",
+               not soldered here, though unknown wiring.
+               Card lacks: external audio in, pci subsystem id.
        */
-       .name           = "Kodicom 4400R (slave)",
-       .video_inputs   = 16,
-       .audio_inputs   = 0,
-       .tuner          = -1,
-       .tuner_type     = -1,
-       .tuner_addr     = ADDR_UNSET,
-       .svhs           = -1,
-       .gpiomask       = 0x010000,
-       .no_gpioirq     = 1,
-       .muxsel         = { 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3 },
-       .pll            = PLL_28,
-       .no_msp34xx     = 1,
-       .no_tda7432     = 1,
-       .no_tda9875     = 1,
-       .muxsel_hook    = kodicom4400r_muxsel,
-},
-{
-       /* ---- card 0x86---------------------------------- */
-       /* Michael Henson <mhenson@clarityvi.com> */
-       /* Adlink RTV24 with special unlock codes */
-       .name           = "Adlink RTV24",
-       .video_inputs   = 4,
-       .audio_inputs   = 1,
-       .tuner          = 0,
-       .svhs           = 2,
-       .muxsel         = { 2, 3, 1, 0},
-       .tuner_type     = -1,
-       .tuner_addr     = ADDR_UNSET,
-       .pll            = PLL_28,
-},
-{
-       /* ---- card 0x87---------------------------------- */
-       /* Michael Krufky <mkrufky@m1k.net> */
-       .name           = "DViCO FusionHDTV 5 Lite",
-       .tuner          = 0,
-       .tuner_type     = TUNER_LG_TDVS_H062F,
-       .tuner_addr     = ADDR_UNSET,
-       .video_inputs   = 3,
-       .audio_inputs   = 1,
-       .svhs           = 2,
-       .muxsel         = { 2, 3, 1 },
-       .gpiomask       = 0x00e00007,
-       .audiomux       = { 0x00400005, 0, 0x00000001, 0, 0x00c00007, 0 },
-       .no_msp34xx     = 1,
-       .no_tda9875     = 1,
-       .no_tda7432     = 1,
-},{
-       /* ---- card 0x88---------------------------------- */
-       /* Mauro Carvalho Chehab <mchehab@brturbo.com.br> */
-       .name           = "Acorp Y878F",
-       .video_inputs   = 3,
-       .audio_inputs   = 1,
-       .tuner          = 0,
-       .svhs           = 2,
-       .gpiomask       = 0x01fe00,
-       .muxsel         = { 2, 3, 1, 1},
-       .audiomux       = { 0x001e00, 0, 0x018000, 0x014000, 0x002000, 0 },
-       .needs_tvaudio  = 1,
-       .pll            = PLL_28,
-       .tuner_type     = TUNER_YMEC_TVF66T5_B_DFF,
-       .tuner_addr     = 0xc1 >>1,
-       .has_radio      = 1,
-}};
+       },
+
+               /* ---- card 0x60 ---------------------------------- */
+       [BTTV_BOARD_MACHTV] = {
+               .name           = "MachTV",
+               .video_inputs   = 3,
+               .audio_inputs   = 1,
+               .tuner          = 0,
+               .svhs           = -1,
+               .gpiomask       = 7,
+               .muxsel         = { 2, 3, 1, 1},
+               .audiomux       = { 0, 1, 2, 3, 4},
+               .needs_tvaudio  = 1,
+               .tuner_type     = 5,
+               .tuner_addr     = ADDR_UNSET,
+               .radio_addr     = ADDR_UNSET,
+               .pll            = PLL_28,
+       },
+       [BTTV_BOARD_EURESYS_PICOLO] = {
+               .name           = "Euresys Picolo",
+               .video_inputs   = 3,
+               .audio_inputs   = 0,
+               .tuner          = -1,
+               .svhs           = 2,
+               .gpiomask       = 0,
+               .no_msp34xx     = 1,
+               .no_tda9875     = 1,
+               .no_tda7432     = 1,
+               .muxsel         = { 2, 0, 1},
+               .pll            = PLL_28,
+               .tuner_type     = UNSET,
+               .tuner_addr     = ADDR_UNSET,
+               .radio_addr     = ADDR_UNSET,
+       },
+       [BTTV_BOARD_PV150] = {
+               /* Luc Van Hoeylandt <luc@e-magic.be> */
+               .name           = "ProVideo PV150", /* 0x4f */
+               .video_inputs   = 2,
+               .audio_inputs   = 0,
+               .tuner          = -1,
+               .svhs           = -1,
+               .gpiomask       = 0,
+               .muxsel         = { 2, 3 },
+               .audiomux       = { 0 },
+               .needs_tvaudio  = 0,
+               .no_msp34xx     = 1,
+               .pll            = PLL_28,
+               .tuner_type     = UNSET,
+               .tuner_addr     = ADDR_UNSET,
+               .radio_addr     = ADDR_UNSET,
+       },
+       [BTTV_BOARD_AD_TVK503] = {
+               /* Hiroshi Takekawa <sian@big.or.jp> */
+               /* This card lacks subsystem ID */
+               .name           = "AD-TVK503", /* 0x63 */
+               .video_inputs   = 4,
+               .audio_inputs   = 1,
+               .tuner          = 0,
+               .svhs           = 2,
+               .gpiomask       = 0x001e8007,
+               .muxsel         = { 2, 3, 1, 0 },
+               /*                  Tuner, Radio, external, internal, off,  on */
+               .audiomux       = { 0x08,  0x0f,  0x0a,     0x08,     0x0f, 0x08 },
+               .needs_tvaudio  = 0,
+               .no_msp34xx     = 1,
+               .pll            = PLL_28,
+               .tuner_type     = 2,
+               .tuner_addr     = ADDR_UNSET,
+               .radio_addr     = ADDR_UNSET,
+               .audio_hook     = adtvk503_audio,
+       },
+
+               /* ---- card 0x64 ---------------------------------- */
+       [BTTV_BOARD_HERCULES_SM_TV] = {
+               .name           = "Hercules Smart TV Stereo",
+               .video_inputs   = 4,
+               .audio_inputs   = 1,
+               .tuner          = 0,
+               .svhs           = 2,
+               .gpiomask       = 0x00,
+               .muxsel         = { 2, 3, 1, 1 },
+               .needs_tvaudio  = 1,
+               .no_msp34xx     = 1,
+               .pll            = PLL_28,
+               .tuner_type     = 5,
+               .tuner_addr     = ADDR_UNSET,
+               .radio_addr     = ADDR_UNSET,
+               /* Notes:
+               - card lacks subsystem ID
+               - stereo variant w/ daughter board with tda9874a @0xb0
+               - Audio Routing:
+                       always from tda9874 independent of GPIO (?)
+                       external line in: unknown
+               - Other chips: em78p156elp @ 0x96 (probably IR remote control)
+                       hef4053 (instead 4052) for unknown function
+               */
+       },
+       [BTTV_BOARD_PACETV] = {
+               .name           = "Pace TV & Radio Card",
+               .video_inputs   = 4,
+               .audio_inputs   = 1,
+               .tuner          = 0,
+               .svhs           = 2,
+               .muxsel         = { 2, 3, 1, 1}, /* Tuner, CVid, SVid, CVid over SVid connector */
+               .gpiomask       = 0,
+               .no_tda9875     = 1,
+               .no_tda7432     = 1,
+               .tuner_type     = 1,
+               .tuner_addr     = ADDR_UNSET,
+               .radio_addr     = ADDR_UNSET,
+               .has_radio      = 1,
+               .pll            = PLL_28,
+               /* Bt878, Bt832, FI1246 tuner; no pci subsystem id
+               only internal line out: (4pin header) RGGL
+               Radio must be decoded by msp3410d (not routed through)*/
+               /*
+               .digital_mode   = DIGITAL_MODE_CAMERA,  todo!
+               */
+       },
+       [BTTV_BOARD_IVC200] = {
+               /* Chris Willing <chris@vislab.usyd.edu.au> */
+               .name           = "IVC-200",
+               .video_inputs   = 1,
+               .audio_inputs   = 0,
+               .tuner          = -1,
+               .tuner_type     = -1,
+               .tuner_addr     = ADDR_UNSET,
+               .radio_addr     = ADDR_UNSET,
+               .svhs           = -1,
+               .gpiomask       = 0xdf,
+               .muxsel         = { 2 },
+               .pll            = PLL_28,
+       },
+       [BTTV_BOARD_XGUARD] = {
+               .name           = "Grand X-Guard / Trust 814PCI",
+               .video_inputs   = 16,
+               .audio_inputs   = 0,
+               .tuner          = -1,
+               .svhs           = -1,
+               .tuner_type     = 4,
+               .tuner_addr     = ADDR_UNSET,
+               .radio_addr     = ADDR_UNSET,
+               .gpiomask2      = 0xff,
+               .muxsel         = { 2,2,2,2, 3,3,3,3, 1,1,1,1, 0,0,0,0 },
+               .muxsel_hook    = xguard_muxsel,
+               .no_msp34xx     = 1,
+               .no_tda9875     = 1,
+               .no_tda7432     = 1,
+               .pll            = PLL_28,
+       },
+
+               /* ---- card 0x68 ---------------------------------- */
+       [BTTV_BOARD_NEBULA_DIGITV] = {
+               .name           = "Nebula Electronics DigiTV",
+               .video_inputs   = 1,
+               .tuner          = -1,
+               .svhs           = -1,
+               .muxsel         = { 2, 3, 1, 0},
+               .no_msp34xx     = 1,
+               .no_tda9875     = 1,
+               .no_tda7432     = 1,
+               .pll            = PLL_28,
+               .tuner_type     = -1,
+               .tuner_addr     = ADDR_UNSET,
+               .radio_addr     = ADDR_UNSET,
+               .has_dvb        = 1,
+               .no_gpioirq     = 1,
+       },
+       [BTTV_BOARD_PV143] = {
+               /* Jorge Boncompte - DTI2 <jorge@dti2.net> */
+               .name           = "ProVideo PV143",
+               .video_inputs   = 4,
+               .audio_inputs   = 0,
+               .tuner          = -1,
+               .svhs           = -1,
+               .gpiomask       = 0,
+               .muxsel         = { 2, 3, 1, 0 },
+               .audiomux       = { 0 },
+               .needs_tvaudio  = 0,
+               .no_msp34xx     = 1,
+               .pll            = PLL_28,
+               .tuner_type     = -1,
+               .tuner_addr     = ADDR_UNSET,
+               .radio_addr     = ADDR_UNSET,
+       },
+       [BTTV_BOARD_VD009X1_MINIDIN] = {
+               /* M.Klahr@phytec.de */
+               .name           = "PHYTEC VD-009-X1 MiniDIN (bt878)",
+               .video_inputs   = 4,
+               .audio_inputs   = 0,
+               .tuner          = -1, /* card has no tuner */
+               .svhs           = 3,
+               .gpiomask       = 0x00,
+               .muxsel         = { 2, 3, 1, 0},
+               .audiomux       = { 0, 0, 0, 0, 0, 0 }, /* card has no audio */
+               .needs_tvaudio  = 1,
+               .pll            = PLL_28,
+               .tuner_type     = -1,
+               .tuner_addr     = ADDR_UNSET,
+               .radio_addr     = ADDR_UNSET,
+       },
+       [BTTV_BOARD_VD009X1_COMBI] = {
+               .name           = "PHYTEC VD-009-X1 Combi (bt878)",
+               .video_inputs   = 4,
+               .audio_inputs   = 0,
+               .tuner          = -1, /* card has no tuner */
+               .svhs           = 3,
+               .gpiomask       = 0x00,
+               .muxsel         = { 2, 3, 1, 1},
+               .audiomux       = { 0, 0, 0, 0, 0, 0 }, /* card has no audio */
+               .needs_tvaudio  = 1,
+               .pll            = PLL_28,
+               .tuner_type     = -1,
+               .tuner_addr     = ADDR_UNSET,
+               .radio_addr     = ADDR_UNSET,
+       },
+
+               /* ---- card 0x6c ---------------------------------- */
+       [BTTV_BOARD_VD009_MINIDIN] = {
+               .name           = "PHYTEC VD-009 MiniDIN (bt878)",
+               .video_inputs   = 10,
+               .audio_inputs   = 0,
+               .tuner          = -1, /* card has no tuner */
+               .svhs           = 9,
+               .gpiomask       = 0x00,
+               .gpiomask2      = 0x03, /* gpiomask2 defines the bits used to switch audio
+                                       via the upper nibble of muxsel. here: used for
+                                       xternal video-mux */
+               .muxsel         = { 0x02, 0x12, 0x22, 0x32, 0x03, 0x13, 0x23, 0x33, 0x01, 0x00 },
+               .audiomux       = { 0, 0, 0, 0, 0, 0 }, /* card has no audio */
+               .needs_tvaudio  = 1,
+               .pll            = PLL_28,
+               .tuner_type     = -1,
+               .tuner_addr     = ADDR_UNSET,
+               .radio_addr     = ADDR_UNSET,
+       },
+       [BTTV_BOARD_VD009_COMBI] = {
+               .name           = "PHYTEC VD-009 Combi (bt878)",
+               .video_inputs   = 10,
+               .audio_inputs   = 0,
+               .tuner          = -1, /* card has no tuner */
+               .svhs           = 9,
+               .gpiomask       = 0x00,
+               .gpiomask2      = 0x03, /* gpiomask2 defines the bits used to switch audio
+                                       via the upper nibble of muxsel. here: used for
+                                       xternal video-mux */
+               .muxsel         = { 0x02, 0x12, 0x22, 0x32, 0x03, 0x13, 0x23, 0x33, 0x01, 0x01 },
+               .audiomux       = { 0, 0, 0, 0, 0, 0 }, /* card has no audio */
+               .needs_tvaudio  = 1,
+               .pll            = PLL_28,
+               .tuner_type     = -1,
+               .tuner_addr     = ADDR_UNSET,
+               .radio_addr     = ADDR_UNSET,
+       },
+       [BTTV_BOARD_IVC100] = {
+               .name           = "IVC-100",
+               .video_inputs   = 4,
+               .audio_inputs   = 0,
+               .tuner          = -1,
+               .tuner_type     = -1,
+               .tuner_addr     = ADDR_UNSET,
+               .radio_addr     = ADDR_UNSET,
+               .svhs           = -1,
+               .gpiomask       = 0xdf,
+               .muxsel         = { 2, 3, 1, 0 },
+               .pll            = PLL_28,
+       },
+       [BTTV_BOARD_IVC120] = {
+               /* IVC-120G - Alan Garfield <alan@fromorbit.com> */
+               .name           = "IVC-120G",
+               .video_inputs   = 16,
+               .audio_inputs   = 0,    /* card has no audio */
+               .tuner          = -1,   /* card has no tuner */
+               .tuner_type     = -1,
+               .tuner_addr     = ADDR_UNSET,
+               .radio_addr     = ADDR_UNSET,
+               .svhs           = -1,   /* card has no svhs */
+               .needs_tvaudio  = 0,
+               .no_msp34xx     = 1,
+               .no_tda9875     = 1,
+               .no_tda7432     = 1,
+               .gpiomask       = 0x00,
+               .muxsel         = { 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08,
+                               0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10 },
+               .muxsel_hook    = ivc120_muxsel,
+               .pll            = PLL_28,
+       },
+
+               /* ---- card 0x70 ---------------------------------- */
+       [BTTV_BOARD_PC_HDTV] = {
+               .name           = "pcHDTV HD-2000 TV",
+               .video_inputs   = 4,
+               .audio_inputs   = 1,
+               .tuner          = 0,
+               .svhs           = 2,
+               .muxsel         = { 2, 3, 1, 0},
+               .tuner_type     = TUNER_PHILIPS_ATSC,
+               .tuner_addr     = ADDR_UNSET,
+               .radio_addr     = ADDR_UNSET,
+               .has_dvb        = 1,
+       },
+       [BTTV_BOARD_TWINHAN_DST] = {
+               .name           = "Twinhan DST + clones",
+               .no_msp34xx     = 1,
+               .no_tda9875     = 1,
+               .no_tda7432     = 1,
+               .tuner_type     = TUNER_ABSENT,
+               .tuner_addr     = ADDR_UNSET,
+               .radio_addr     = ADDR_UNSET,
+               .no_video       = 1,
+               .has_dvb        = 1,
+       },
+       [BTTV_BOARD_WINFASTVC100] = {
+               .name           = "Winfast VC100",
+               .video_inputs   = 3,
+               .audio_inputs   = 0,
+               .svhs           = 1,
+               .tuner          = -1,
+               .muxsel         = { 3, 1, 1, 3}, /* Vid In, SVid In, Vid over SVid in connector */
+               .no_msp34xx     = 1,
+               .no_tda9875     = 1,
+               .no_tda7432     = 1,
+               .tuner_type     = TUNER_ABSENT,
+               .tuner_addr     = ADDR_UNSET,
+               .radio_addr     = ADDR_UNSET,
+               .pll            = PLL_28,
+       },
+       [BTTV_BOARD_TEV560] = {
+               .name           = "Teppro TEV-560/InterVision IV-560",
+               .video_inputs   = 3,
+               .audio_inputs   = 1,
+               .tuner          = 0,
+               .svhs           = 2,
+               .gpiomask       = 3,
+               .muxsel         = { 2, 3, 1, 1},
+               .audiomux       = { 1, 1, 1, 1, 0},
+               .needs_tvaudio  = 1,
+               .tuner_type     = TUNER_PHILIPS_PAL,
+               .tuner_addr     = ADDR_UNSET,
+               .radio_addr     = ADDR_UNSET,
+               .pll            = PLL_35,
+       },
+
+               /* ---- card 0x74 ---------------------------------- */
+       [BTTV_BOARD_SIMUS_GVC1100] = {
+               .name           = "SIMUS GVC1100",
+               .video_inputs   = 4,
+               .audio_inputs   = 0,
+               .tuner          = -1,
+               .svhs           = -1,
+               .tuner_type     = -1,
+               .tuner_addr     = ADDR_UNSET,
+               .radio_addr     = ADDR_UNSET,
+               .pll            = PLL_28,
+               .muxsel         = { 2, 2, 2, 2},
+               .gpiomask       = 0x3F,
+               .muxsel_hook    = gvc1100_muxsel,
+       },
+       [BTTV_BOARD_NGSTV_PLUS] = {
+               /* Carlos Silva r3pek@r3pek.homelinux.org || card 0x75 */
+               .name           = "NGS NGSTV+",
+               .video_inputs   = 3,
+               .tuner          = 0,
+               .svhs           = 2,
+               .gpiomask       = 0x008007,
+               .muxsel         = {2, 3, 0, 0},
+               .audiomux       = {0, 0, 0, 0, 0x000003, 0},
+               .pll            = PLL_28,
+               .tuner_type     = TUNER_PHILIPS_PAL,
+               .tuner_addr     = ADDR_UNSET,
+               .radio_addr     = ADDR_UNSET,
+               .has_remote     = 1,
+       },
+       [BTTV_BOARD_LMLBT4] = {
+               /* http://linuxmedialabs.com */
+               .name           = "LMLBT4",
+               .video_inputs   = 4, /* IN1,IN2,IN3,IN4 */
+               .audio_inputs   = 0,
+               .tuner          = -1,
+               .svhs           = -1,
+               .muxsel         = { 2, 3, 1, 0 },
+               .no_msp34xx     = 1,
+               .no_tda9875     = 1,
+               .no_tda7432     = 1,
+               .needs_tvaudio  = 0,
+               .tuner_type     = -1,
+               .tuner_addr     = ADDR_UNSET,
+               .radio_addr     = ADDR_UNSET,
+       },
+       [BTTV_BOARD_TEKRAM_M205] = {
+               /* Helmroos Harri <harri.helmroos@pp.inet.fi> */
+               .name           = "Tekram M205 PRO",
+               .video_inputs   = 3,
+               .audio_inputs   = 1,
+               .tuner          = 0,
+               .tuner_type     = TUNER_PHILIPS_PAL,
+               .tuner_addr     = ADDR_UNSET,
+               .radio_addr     = ADDR_UNSET,
+               .svhs           = 2,
+               .needs_tvaudio  = 0,
+               .gpiomask       = 0x68,
+               .muxsel         = { 2, 3, 1},
+               .audiomux       = { 0x68, 0x68, 0x61, 0x61, 0x00 },
+               .pll            = PLL_28,
+       },
+
+               /* ---- card 0x78 ---------------------------------- */
+       [BTTV_BOARD_CONTVFMI] = {
+               /* Javier Cendan Ares <jcendan@lycos.es> */
+               /* bt878 TV + FM without subsystem ID */
+               .name           = "Conceptronic CONTVFMi",
+               .video_inputs   = 3,
+               .audio_inputs   = 1,
+               .tuner          = 0,
+               .svhs           = 2,
+               .gpiomask       = 0x008007,
+               .muxsel         = { 2, 3, 1, 1 },
+               .audiomux       = { 0, 1, 2, 2, 3 },
+               .needs_tvaudio  = 0,
+               .pll            = PLL_28,
+               .tuner_type     = TUNER_PHILIPS_PAL,
+               .tuner_addr     = ADDR_UNSET,
+               .radio_addr     = ADDR_UNSET,
+               .has_remote     = 1,
+               .has_radio      = 1,
+       },
+       [BTTV_BOARD_PICOLO_TETRA_CHIP] = {
+               /*Eric DEBIEF <debief@telemsa.com>*/
+               /*EURESYS Picolo Tetra : 4 Conexant Fusion 878A, no audio, video input set with analog multiplexers GPIO controled*/
+               /* adds picolo_tetra_muxsel(), picolo_tetra_init(), the folowing declaration strucure, and #define BTTV_BOARD_PICOLO_TETRA_CHIP*/
+               /*0x79 in bttv.h*/
+               .name           = "Euresys Picolo Tetra",
+               .video_inputs   = 4,
+               .audio_inputs   = 0,
+               .tuner          = -1,
+               .svhs           = -1,
+               .gpiomask       = 0,
+               .gpiomask2      = 0x3C<<16,/*Set the GPIO[18]->GPIO[21] as output pin.==> drive the video inputs through analog multiplexers*/
+               .no_msp34xx     = 1,
+               .no_tda9875     = 1,
+               .no_tda7432     = 1,
+               .muxsel         = {2,2,2,2},/*878A input is always MUX0, see above.*/
+               .audiomux       = { 0, 0, 0, 0, 0, 0 }, /* card has no audio */
+               .pll            = PLL_28,
+               .needs_tvaudio  = 0,
+               .muxsel_hook    = picolo_tetra_muxsel,/*Required as it doesn't follow the classic input selection policy*/
+               .tuner_type     = -1,
+               .tuner_addr     = ADDR_UNSET,
+               .radio_addr     = ADDR_UNSET,
+       },
+       [BTTV_BOARD_SPIRIT_TV] = {
+               /* Spirit TV Tuner from http://spiritmodems.com.au */
+               /* Stafford Goodsell <surge@goliath.homeunix.org> */
+               .name           = "Spirit TV Tuner",
+               .video_inputs   = 3,
+               .audio_inputs   = 1,
+               .tuner          = 0,
+               .svhs           = 2,
+               .gpiomask       = 0x0000000f,
+               .muxsel         = { 2, 1, 1 },
+               .audiomux       = { 0x02, 0x00, 0x00, 0x00, 0x00},
+               .tuner_type     = TUNER_TEMIC_PAL,
+               .tuner_addr     = ADDR_UNSET,
+               .radio_addr     = ADDR_UNSET,
+               .no_msp34xx     = 1,
+               .no_tda9875     = 1,
+       },
+       [BTTV_BOARD_AVDVBT_771] = {
+               /* Wolfram Joost <wojo@frokaschwei.de> */
+               .name           = "AVerMedia AVerTV DVB-T 771",
+               .video_inputs   = 2,
+               .svhs           = 1,
+               .tuner          = -1,
+               .tuner_type     = TUNER_ABSENT,
+               .tuner_addr     = ADDR_UNSET,
+               .radio_addr     = ADDR_UNSET,
+               .muxsel         = { 3 , 3 },
+               .no_msp34xx     = 1,
+               .no_tda9875     = 1,
+               .no_tda7432     = 1,
+               .pll            = PLL_28,
+               .has_dvb        = 1,
+               .no_gpioirq     = 1,
+               .has_remote     = 1,
+       },
+               /* ---- card 0x7c ---------------------------------- */
+       [BTTV_BOARD_AVDVBT_761] = {
+               /* Matt Jesson <dvb@jesson.eclipse.co.uk> */
+               /* Based on the Nebula card data - added remote and new card number - BTTV_BOARD_AVDVBT_761, see also ir-kbd-gpio.c */
+               .name           = "AverMedia AverTV DVB-T 761",
+               .video_inputs   = 2,
+               .tuner          = -1,
+               .svhs           = 1,
+               .muxsel         = { 3, 1, 2, 0}, /* Comp0, S-Video, ?, ? */
+               .no_msp34xx     = 1,
+               .no_tda9875     = 1,
+               .no_tda7432     = 1,
+               .pll            = PLL_28,
+               .tuner_type     = -1,
+               .tuner_addr     = ADDR_UNSET,
+               .radio_addr     = ADDR_UNSET,
+               .has_dvb        = 1,
+               .no_gpioirq     = 1,
+               .has_remote     = 1,
+       },
+       [BTTV_BOARD_MATRIX_VISIONSQ] = {
+               /* andre.schwarz@matrix-vision.de */
+               .name             = "MATRIX Vision Sigma-SQ",
+               .video_inputs     = 16,
+               .audio_inputs     = 0,
+               .tuner            = -1,
+               .svhs             = -1,
+               .gpiomask         = 0x0,
+               .muxsel           = { 2, 2, 2, 2, 2, 2, 2, 2,
+                               3, 3, 3, 3, 3, 3, 3, 3 },
+               .muxsel_hook      = sigmaSQ_muxsel,
+               .audiomux         = { 0 },
+               .no_msp34xx       = 1,
+               .pll              = PLL_28,
+               .tuner_type       = -1,
+               .tuner_addr       = ADDR_UNSET,
+               .radio_addr     = ADDR_UNSET,
+       },
+       [BTTV_BOARD_MATRIX_VISIONSLC] = {
+               /* andre.schwarz@matrix-vision.de */
+               .name             = "MATRIX Vision Sigma-SLC",
+               .video_inputs     = 4,
+               .audio_inputs     = 0,
+               .tuner            = -1,
+               .svhs             = -1,
+               .gpiomask         = 0x0,
+               .muxsel           = { 2, 2, 2, 2 },
+               .muxsel_hook      = sigmaSLC_muxsel,
+               .audiomux         = { 0 },
+               .no_msp34xx       = 1,
+               .pll              = PLL_28,
+               .tuner_type       = -1,
+               .tuner_addr       = ADDR_UNSET,
+               .radio_addr     = ADDR_UNSET,
+       },
+               /* BTTV_BOARD_APAC_VIEWCOMP */
+       [BTTV_BOARD_APAC_VIEWCOMP] = {
+               /* Attila Kondoros <attila.kondoros@chello.hu> */
+               /* bt878 TV + FM 0x00000000 subsystem ID */
+               .name           = "APAC Viewcomp 878(AMAX)",
+               .video_inputs   = 2,
+               .audio_inputs   = 1,
+               .tuner          = 0,
+               .svhs           = -1,
+               .gpiomask       = 0xFF,
+               .muxsel         = { 2, 3, 1, 1},
+               .audiomux       = { 2, 0, 0, 0, 10},
+               .needs_tvaudio  = 0,
+               .pll            = PLL_28,
+               .tuner_type     = TUNER_PHILIPS_PAL,
+               .tuner_addr     = ADDR_UNSET,
+               .radio_addr     = ADDR_UNSET,
+               .has_remote     = 1,   /* miniremote works, see ir-kbd-gpio.c */
+               .has_radio      = 1,   /* not every card has radio */
+       },
+
+               /* ---- card 0x80 ---------------------------------- */
+       [BTTV_BOARD_DVICO_DVBT_LITE] = {
+               /* Chris Pascoe <c.pascoe@itee.uq.edu.au> */
+               .name           = "DViCO FusionHDTV DVB-T Lite",
+               .tuner          = -1,
+               .no_msp34xx     = 1,
+               .no_tda9875     = 1,
+               .no_tda7432     = 1,
+               .pll            = PLL_28,
+               .no_video       = 1,
+               .has_dvb        = 1,
+               .tuner_type     = -1,
+               .tuner_addr     = ADDR_UNSET,
+               .radio_addr     = ADDR_UNSET,
+       },
+       [BTTV_BOARD_VGEAR_MYVCD] = {
+               /* Steven <photon38@pchome.com.tw> */
+               .name           = "V-Gear MyVCD",
+               .video_inputs   = 3,
+               .audio_inputs   = 1,
+               .tuner          = 0,
+               .svhs           = 2,
+               .gpiomask       = 0x3f,
+               .muxsel         = {2, 3, 1, 0},
+               .audiomux       = {0x31, 0x31, 0x31, 0x31, 0x31, 0x31},
+               .no_msp34xx     = 1,
+               .pll            = PLL_28,
+               .tuner_type     = TUNER_PHILIPS_NTSC_M,
+               .tuner_addr     = ADDR_UNSET,
+               .radio_addr     = ADDR_UNSET,
+               .has_radio      = 0,
+       #if 0
+               .has_remote     = 1,
+       #endif
+       },
+       [BTTV_BOARD_SUPER_TV] = {
+               /* Rick C <cryptdragoon@gmail.com> */
+               .name           = "Super TV Tuner",
+               .video_inputs   = 4,
+               .audio_inputs   = 1,
+               .tuner          = 0,
+               .svhs           = 2,
+               .muxsel         = { 2, 3, 1, 0},
+               .tuner_type     = TUNER_PHILIPS_NTSC,
+               .tuner_addr     = ADDR_UNSET,
+               .radio_addr     = ADDR_UNSET,
+               .gpiomask       = 0x008007,
+               .audiomux       = { 0, 0x000001,0,0, 0},
+               .needs_tvaudio  = 1,
+               .has_radio      = 1,
+       },
+       [BTTV_BOARD_TIBET_CS16] = {
+               /* Chris Fanning <video4linux@haydon.net> */
+               .name           = "Tibet Systems 'Progress DVR' CS16",
+               .video_inputs   = 16,
+               .audio_inputs   = 0,
+               .tuner          = -1,
+               .svhs           = -1,
+               .muxsel         = { 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2 },
+               .pll            = PLL_28,
+               .no_msp34xx     = 1,
+               .no_tda9875     = 1,
+               .no_tda7432     = 1,
+               .tuner_type     = -1,
+               .tuner_addr     = ADDR_UNSET,
+               .radio_addr     = ADDR_UNSET,
+               .muxsel_hook    = tibetCS16_muxsel,
+       },
+       [BTTV_BOARD_KODICOM_4400R] = {
+               /* Bill Brack <wbrack@mmm.com.hk> */
+               /*
+               * Note that, because of the card's wiring, the "master"
+               * BT878A chip (i.e. the one which controls the analog switch
+               * and must use this card type) is the 2nd one detected.  The
+               * other 3 chips should use card type 0x85, whose description
+               * follows this one.  There is a EEPROM on the card (which is
+               * connected to the I2C of one of those other chips), but is
+               * not currently handled.  There is also a facility for a
+               * "monitor", which is also not currently implemented.
+               */
+               .name           = "Kodicom 4400R (master)",
+               .video_inputs   = 16,
+               .audio_inputs   = 0,
+               .tuner          = -1,
+               .tuner_type     = -1,
+               .tuner_addr     = ADDR_UNSET,
+               .radio_addr     = ADDR_UNSET,
+               .svhs           = -1,
+               /* GPIO bits 0-9 used for analog switch:
+               *   00 - 03:    camera selector
+               *   04 - 06:    channel (controller) selector
+               *   07: data (1->on, 0->off)
+               *   08: strobe
+               *   09: reset
+               * bit 16 is input from sync separator for the channel
+               */
+               .gpiomask       = 0x0003ff,
+               .no_gpioirq     = 1,
+               .muxsel         = { 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3 },
+               .pll            = PLL_28,
+               .no_msp34xx     = 1,
+               .no_tda7432     = 1,
+               .no_tda9875     = 1,
+               .muxsel_hook    = kodicom4400r_muxsel,
+       },
+       [BTTV_BOARD_KODICOM_4400R_SL] = {
+               /* Bill Brack <wbrack@mmm.com.hk> */
+               /* Note that, for reasons unknown, the "master" BT878A chip (i.e. the
+               * one which controls the analog switch, and must use the card type)
+               * is the 2nd one detected.  The other 3 chips should use this card
+               * type
+               */
+               .name           = "Kodicom 4400R (slave)",
+               .video_inputs   = 16,
+               .audio_inputs   = 0,
+               .tuner          = -1,
+               .tuner_type     = -1,
+               .tuner_addr     = ADDR_UNSET,
+               .radio_addr     = ADDR_UNSET,
+               .svhs           = -1,
+               .gpiomask       = 0x010000,
+               .no_gpioirq     = 1,
+               .muxsel         = { 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3 },
+               .pll            = PLL_28,
+               .no_msp34xx     = 1,
+               .no_tda7432     = 1,
+               .no_tda9875     = 1,
+               .muxsel_hook    = kodicom4400r_muxsel,
+       },
+               /* ---- card 0x86---------------------------------- */
+       [BTTV_BOARD_ADLINK_RTV24] = {
+               /* Michael Henson <mhenson@clarityvi.com> */
+               /* Adlink RTV24 with special unlock codes */
+               .name           = "Adlink RTV24",
+               .video_inputs   = 4,
+               .audio_inputs   = 1,
+               .tuner          = 0,
+               .svhs           = 2,
+               .muxsel         = { 2, 3, 1, 0},
+               .tuner_type     = -1,
+               .tuner_addr     = ADDR_UNSET,
+               .radio_addr     = ADDR_UNSET,
+               .pll            = PLL_28,
+       },
+               /* ---- card 0x87---------------------------------- */
+       [BTTV_BOARD_DVICO_FUSIONHDTV_5_LITE] = {
+               /* Michael Krufky <mkrufky@m1k.net> */
+               .name           = "DViCO FusionHDTV 5 Lite",
+               .tuner          = 0,
+               .tuner_type     = TUNER_LG_TDVS_H062F,
+               .tuner_addr     = ADDR_UNSET,
+               .radio_addr     = ADDR_UNSET,
+               .video_inputs   = 3,
+               .audio_inputs   = 1,
+               .svhs           = 2,
+               .muxsel         = { 2, 3, 1 },
+               .gpiomask       = 0x00e00007,
+               .audiomux       = { 0x00400005, 0, 0x00000001, 0, 0x00c00007, 0 },
+               .no_msp34xx     = 1,
+               .no_tda9875     = 1,
+               .no_tda7432     = 1,
+               .has_dvb        = 1,
+       },
+               /* ---- card 0x88---------------------------------- */
+       [BTTV_BOARD_ACORP_Y878F] = {
+               /* Mauro Carvalho Chehab <mchehab@brturbo.com.br> */
+               .name           = "Acorp Y878F",
+               .video_inputs   = 3,
+               .audio_inputs   = 1,
+               .tuner          = 0,
+               .svhs           = 2,
+               .gpiomask       = 0x01fe00,
+               .muxsel         = { 2, 3, 1, 1},
+               .audiomux       = { 0x001e00, 0, 0x018000, 0x014000, 0x002000, 0 },
+               .needs_tvaudio  = 1,
+               .pll            = PLL_28,
+               .tuner_type     = TUNER_YMEC_TVF66T5_B_DFF,
+               .tuner_addr     = 0xc1 >>1,
+               .radio_addr     = 0xc1 >>1,
+               .has_radio      = 1,
+       },
+               /* ---- card 0x89 ---------------------------------- */
+       [BTTV_BOARD_CONCEPTRONIC_CTVFMI2] = {
+               .name           = "Conceptronic CTVFMi v2",
+               .video_inputs   = 3,
+               .audio_inputs   = 1,
+               .tuner          = 0,
+               .svhs           = 2,
+               .gpiomask       = 0x001c0007,
+               .muxsel         = { 2, 3, 1, 1 },
+               .audiomux       = { 0, 1, 2, 2, 3 },
+               .needs_tvaudio  = 0,
+               .pll            = PLL_28,
+               .tuner_type     = TUNER_TENA_9533_DI,
+               .tuner_addr     = ADDR_UNSET,
+               .radio_addr     = ADDR_UNSET,
+               .has_remote     = 1,
+               .has_radio      = 1,
+       },
+               /* ---- card 0x8a ---------------------------------- */
+       [BTTV_BOARD_PV_BT878P_2E] = {
+               .name          = "Prolink Pixelview PV-BT878P+ (Rev.2E)",
+               .video_inputs  = 5,
+               .audio_inputs  = 1,
+               .tuner         = 0,
+               .svhs          = 3,
+               .gpiomask      = 0x01fe00,
+               .muxsel        = { 2,3,1,1,-1 },
+               .digital_mode  = DIGITAL_MODE_CAMERA,
+               .audiomux      = { 0x00400, 0x10400, 0x04400, 0x80000, 0x12400, 0x46000  },
+               .no_msp34xx    = 1,
+               .pll           = PLL_28,
+               .tuner_type    = TUNER_LG_PAL_FM,
+               .tuner_addr     = ADDR_UNSET,
+               .radio_addr     = ADDR_UNSET,
+               .has_remote    = 1,
+       },
+               /* ---- card 0x8b ---------------------------------- */
+       [BTTV_BOARD_PV_M4900] = {
+               /* Sérgio Fortier <sergiofortier@yahoo.com.br> */
+               .name           = "Prolink PixelView PlayTV MPEG2 PV-M4900",
+               .video_inputs   = 3,
+               .audio_inputs   = 1,
+               .tuner          = 0,
+               .svhs           = 2,
+               .gpiomask       = 0x3f,
+               .muxsel         = { 2, 3, 1, 1 },
+               .audiomux       = { 0x21, 0x20, 0x24, 0x2c, 0x29, 0x29 },
+               .no_msp34xx     = 1,
+               .pll            = PLL_28,
+               .tuner_type     = TUNER_YMEC_TVF_5533MF,
+               .tuner_addr     = ADDR_UNSET,
+               .radio_addr     = ADDR_UNSET,
+               .has_radio      = 1,
+               .has_remote     = 1,
+       },
+               /* ---- card 0x8c ---------------------------------- */
+       [BTTV_BOARD_OSPREY440]  = {
+               .name           = "Osprey 440",
+               .video_inputs   = 1,
+               .audio_inputs   = 1,
+               .tuner          = -1,
+               .svhs           = 1,
+               .muxsel         = { 2 },
+               .pll            = PLL_28,
+               .tuner_type     = UNSET,
+               .tuner_addr     = ADDR_UNSET,
+               .radio_addr     = ADDR_UNSET,
+               .no_msp34xx     = 1,
+               .no_tda9875     = 1,
+               .no_tda7432     = 1,
+       },
+               /* ---- card 0x8d ---------------------------------- */
+       [BTTV_BOARD_ASOUND_SKYEYE] = {
+               .name           = "Asound Skyeye PCTV",
+               .video_inputs   = 3,
+               .audio_inputs   = 1,
+               .tuner          = 0,
+               .svhs           = 2,
+               .gpiomask       = 15,
+               .muxsel         = { 2, 3, 1, 1},
+               .audiomux       = {2,0,0,0,1},
+               .needs_tvaudio  = 1,
+               .pll            = PLL_28,
+               .tuner_type     = 2,
+               .tuner_addr     = ADDR_UNSET,
+               .radio_addr     = ADDR_UNSET,
+       },
+
+};
 
 static const unsigned int bttv_num_tvcards = ARRAY_SIZE(bttv_tvcards);
 
@@ -2461,7 +2840,7 @@ void __devinit bttv_idcard(struct bttv *btv)
                               btv->c.nr, btv->cardid & 0xffff,
                               (btv->cardid >> 16) & 0xffff);
                        printk(KERN_DEBUG "please mail id, board name and "
-                              "the correct card= insmod option to kraxel@bytesex.org\n");
+                              "the correct card= insmod option to video4linux-list@redhat.com\n");
                }
        }
 
@@ -2510,11 +2889,11 @@ void identify_by_eeprom(struct bttv *btv, unsigned char eeprom_data[256])
        int type = -1;
 
        if (0 == strncmp(eeprom_data,"GET MM20xPCTV",13))
-               type = BTTV_MODTEC_205;
+               type = BTTV_BOARD_MODTEC_205;
        else if (0 == strncmp(eeprom_data+20,"Picolo",7))
-               type = BTTV_EURESYS_PICOLO;
+               type = BTTV_BOARD_EURESYS_PICOLO;
        else if (eeprom_data[0] == 0x84 && eeprom_data[2]== 0)
-                type = BTTV_HAUPPAUGE; /* old bt848 */
+               type = BTTV_BOARD_HAUPPAUGE; /* old bt848 */
 
        if (-1 != type) {
                btv->c.type = type;
@@ -2548,7 +2927,7 @@ static void flyvideo_gpio(struct bttv *btv)
        switch(ttype) {
        case 0x0: tuner=2; /* NTSC, e.g. TPI8NSR11P */
                break;
-        case 0x2: tuner=39;/* LG NTSC (newer TAPC series) TAPC-H701P */
+       case 0x2: tuner=39;/* LG NTSC (newer TAPC series) TAPC-H701P */
                break;
        case 0x4: tuner=5; /* Philips PAL TPI8PSB02P, TPI8PSB12P, TPI8PSB12D or FI1216, FM1216 */
                break;
@@ -2564,7 +2943,7 @@ static void flyvideo_gpio(struct bttv *btv)
        has_radio           =   gpio & 0x400000;
        /*   unknown                   0x200000;
         *   unknown2                  0x100000; */
-        is_capture_only     = !(gpio & 0x008000); /* GPIO15 */
+       is_capture_only     = !(gpio & 0x008000); /* GPIO15 */
        has_tda9820_tda9821 = !(gpio & 0x004000);
        is_lr90             = !(gpio & 0x002000); /* else LR26/LR50 (LR38/LR51 f. capture only) */
        /*
@@ -2601,7 +2980,7 @@ static void miro_pinnacle_gpio(struct bttv *btv)
        char *info;
 
        gpio_inout(0xffffff, 0);
-        gpio = gpio_read();
+       gpio = gpio_read();
        id   = ((gpio>>10) & 63) -1;
        msp  = bttv_I2CRead(btv, I2C_MSP3400, "MSP34xx");
        if (id < 32) {
@@ -2620,10 +2999,10 @@ static void miro_pinnacle_gpio(struct bttv *btv)
                        btv->has_radio = 0;
                }
                if (-1 != msp) {
-                       if (btv->c.type == BTTV_MIRO)
-                               btv->c.type = BTTV_MIROPRO;
-                       if (btv->c.type == BTTV_PINNACLE)
-                               btv->c.type = BTTV_PINNACLEPRO;
+                       if (btv->c.type == BTTV_BOARD_MIRO)
+                               btv->c.type = BTTV_BOARD_MIROPRO;
+                       if (btv->c.type == BTTV_BOARD_PINNACLE)
+                               btv->c.type = BTTV_BOARD_PINNACLEPRO;
                }
                printk(KERN_INFO
                       "bttv%d: miro: id=%d tuner=%d radio=%s stereo=%s\n",
@@ -2664,7 +3043,7 @@ static void miro_pinnacle_gpio(struct bttv *btv)
                        break;
                }
                if (-1 != msp)
-                       btv->c.type = BTTV_PINNACLEPRO;
+                       btv->c.type = BTTV_BOARD_PINNACLEPRO;
                printk(KERN_INFO
                       "bttv%d: pinnacle/mt: id=%d info=\"%s\" radio=%s\n",
                       btv->c.nr, id, info, btv->has_radio ? "yes" : "no");
@@ -2712,7 +3091,7 @@ static void eagle_muxsel(struct bttv *btv, unsigned int input)
 
 static void gvc1100_muxsel(struct bttv *btv, unsigned int input)
 {
-        static const int masks[] = {0x30, 0x01, 0x12, 0x23};
+       static const int masks[] = {0x30, 0x01, 0x12, 0x23};
        gpio_write(masks[input%4]);
 }
 
@@ -2778,26 +3157,27 @@ static void bttv_reset_audio(struct bttv *btv)
 void __devinit bttv_init_card1(struct bttv *btv)
 {
        switch (btv->c.type) {
-       case BTTV_HAUPPAUGE:
-       case BTTV_HAUPPAUGE878:
-                boot_msp34xx(btv,5);
+       case BTTV_BOARD_HAUPPAUGE:
+       case BTTV_BOARD_HAUPPAUGE878:
+               boot_msp34xx(btv,5);
                break;
-       case BTTV_VOODOOTV_FM:
-                boot_msp34xx(btv,20);
+       case BTTV_BOARD_VOODOOTV_FM:
+               boot_msp34xx(btv,20);
                break;
-       case BTTV_AVERMEDIA98:
+       case BTTV_BOARD_AVERMEDIA98:
                boot_msp34xx(btv,11);
                break;
-       case BTTV_HAUPPAUGEPVR:
+       case BTTV_BOARD_HAUPPAUGEPVR:
                pvr_boot(btv);
                break;
-       case BTTV_TWINHAN_DST:
-       case BTTV_AVDVBT_771:
+       case BTTV_BOARD_TWINHAN_DST:
+       case BTTV_BOARD_AVDVBT_771:
+       case BTTV_BOARD_PINNACLESAT:
                btv->use_i2c_hw = 1;
                break;
-        case BTTV_ADLINK_RTV24:
-                init_RTV24( btv );
-                break;
+       case BTTV_BOARD_ADLINK_RTV24:
+               init_RTV24( btv );
+               break;
 
        }
        if (!bttv_tvcards[btv->c.type].has_dvb)
@@ -2810,53 +3190,53 @@ void __devinit bttv_init_card2(struct bttv *btv)
        int tda9887;
        int addr=ADDR_UNSET;
 
-        btv->tuner_type = -1;
+       btv->tuner_type = -1;
 
-       if (BTTV_UNKNOWN == btv->c.type) {
+       if (BTTV_BOARD_UNKNOWN == btv->c.type) {
                bttv_readee(btv,eeprom_data,0xa0);
                identify_by_eeprom(btv,eeprom_data);
        }
 
        switch (btv->c.type) {
-       case BTTV_MIRO:
-       case BTTV_MIROPRO:
-       case BTTV_PINNACLE:
-       case BTTV_PINNACLEPRO:
+       case BTTV_BOARD_MIRO:
+       case BTTV_BOARD_MIROPRO:
+       case BTTV_BOARD_PINNACLE:
+       case BTTV_BOARD_PINNACLEPRO:
                /* miro/pinnacle */
                miro_pinnacle_gpio(btv);
                break;
-       case BTTV_FLYVIDEO_98:
-       case BTTV_MAXI:
-       case BTTV_LIFE_FLYKIT:
-       case BTTV_FLYVIDEO:
-       case BTTV_TYPHOON_TVIEW:
-       case BTTV_CHRONOS_VS2:
-       case BTTV_FLYVIDEO_98FM:
-       case BTTV_FLYVIDEO2000:
-       case BTTV_FLYVIDEO98EZ:
-       case BTTV_CONFERENCETV:
-       case BTTV_LIFETEC_9415:
+       case BTTV_BOARD_FLYVIDEO_98:
+       case BTTV_BOARD_MAXI:
+       case BTTV_BOARD_LIFE_FLYKIT:
+       case BTTV_BOARD_FLYVIDEO:
+       case BTTV_BOARD_TYPHOON_TVIEW:
+       case BTTV_BOARD_CHRONOS_VS2:
+       case BTTV_BOARD_FLYVIDEO_98FM:
+       case BTTV_BOARD_FLYVIDEO2000:
+       case BTTV_BOARD_FLYVIDEO98EZ:
+       case BTTV_BOARD_CONFERENCETV:
+       case BTTV_BOARD_LIFETEC_9415:
                flyvideo_gpio(btv);
                break;
-       case BTTV_HAUPPAUGE:
-       case BTTV_HAUPPAUGE878:
-       case BTTV_HAUPPAUGEPVR:
+       case BTTV_BOARD_HAUPPAUGE:
+       case BTTV_BOARD_HAUPPAUGE878:
+       case BTTV_BOARD_HAUPPAUGEPVR:
                /* pick up some config infos from the eeprom */
                bttv_readee(btv,eeprom_data,0xa0);
-                hauppauge_eeprom(btv);
+               hauppauge_eeprom(btv);
                break;
-       case BTTV_AVERMEDIA98:
-       case BTTV_AVPHONE98:
+       case BTTV_BOARD_AVERMEDIA98:
+       case BTTV_BOARD_AVPHONE98:
                bttv_readee(btv,eeprom_data,0xa0);
                avermedia_eeprom(btv);
                break;
-       case BTTV_PXC200:
+       case BTTV_BOARD_PXC200:
                init_PXC200(btv);
                break;
-       case BTTV_PICOLO_TETRA_CHIP:
+       case BTTV_BOARD_PICOLO_TETRA_CHIP:
                picolo_tetra_init(btv);
                break;
-       case BTTV_VHX:
+       case BTTV_BOARD_VHX:
                btv->has_radio    = 1;
                btv->has_matchbox = 1;
                btv->mbox_we      = 0x20;
@@ -2865,58 +3245,58 @@ void __devinit bttv_init_card2(struct bttv *btv)
                btv->mbox_data    = 0x10;
                btv->mbox_mask    = 0x38;
                break;
-       case BTTV_VOBIS_BOOSTAR:
-       case BTTV_TERRATV:
+       case BTTV_BOARD_VOBIS_BOOSTAR:
+       case BTTV_BOARD_TERRATV:
                terratec_active_radio_upgrade(btv);
                break;
-       case BTTV_MAGICTVIEW061:
+       case BTTV_BOARD_MAGICTVIEW061:
                if (btv->cardid == 0x3002144f) {
                        btv->has_radio=1;
                        printk("bttv%d: radio detected by subsystem id (CPH05x)\n",btv->c.nr);
                }
                break;
-       case BTTV_STB2:
-                if (btv->cardid == 0x3060121a) {
+       case BTTV_BOARD_STB2:
+               if (btv->cardid == 0x3060121a) {
                        /* Fix up entry for 3DFX VoodooTV 100,
                           which is an OEM STB card variant. */
                        btv->has_radio=0;
                        btv->tuner_type=TUNER_TEMIC_NTSC;
                }
                break;
-       case BTTV_OSPREY1x0:
-       case BTTV_OSPREY1x0_848:
-       case BTTV_OSPREY101_848:
-       case BTTV_OSPREY1x1:
-       case BTTV_OSPREY1x1_SVID:
-       case BTTV_OSPREY2xx:
-       case BTTV_OSPREY2x0_SVID:
-       case BTTV_OSPREY2x0:
-       case BTTV_OSPREY500:
-       case BTTV_OSPREY540:
-       case BTTV_OSPREY2000:
+       case BTTV_BOARD_OSPREY1x0:
+       case BTTV_BOARD_OSPREY1x0_848:
+       case BTTV_BOARD_OSPREY101_848:
+       case BTTV_BOARD_OSPREY1x1:
+       case BTTV_BOARD_OSPREY1x1_SVID:
+       case BTTV_BOARD_OSPREY2xx:
+       case BTTV_BOARD_OSPREY2x0_SVID:
+       case BTTV_BOARD_OSPREY2x0:
+       case BTTV_BOARD_OSPREY500:
+       case BTTV_BOARD_OSPREY540:
+       case BTTV_BOARD_OSPREY2000:
                bttv_readee(btv,eeprom_data,0xa0);
-                osprey_eeprom(btv);
+               osprey_eeprom(btv);
                break;
-       case BTTV_IDS_EAGLE:
+       case BTTV_BOARD_IDS_EAGLE:
                init_ids_eagle(btv);
                break;
-       case BTTV_MODTEC_205:
+       case BTTV_BOARD_MODTEC_205:
                bttv_readee(btv,eeprom_data,0xa0);
                modtec_eeprom(btv);
                break;
-       case BTTV_LMLBT4:
+       case BTTV_BOARD_LMLBT4:
                init_lmlbt4x(btv);
                break;
-       case BTTV_TIBET_CS16:
+       case BTTV_BOARD_TIBET_CS16:
                tibetCS16_init(btv);
                break;
-       case BTTV_KODICOM_4400R:
+       case BTTV_BOARD_KODICOM_4400R:
                kodicom4400r_init(btv);
                break;
        }
 
        /* pll configuration */
-        if (!(btv->id==848 && btv->revision==0x11)) {
+       if (!(btv->id==848 && btv->revision==0x11)) {
                /* defaults from card list */
                if (PLL_28 == bttv_tvcards[btv->c.type].pll) {
                        btv->pll.pll_ifreq=28636363;
@@ -2927,26 +3307,26 @@ void __devinit bttv_init_card2(struct bttv *btv)
                        btv->pll.pll_crystal=BT848_IFORM_XT1;
                }
                /* insmod options can override */
-                switch (pll[btv->c.nr]) {
-                case 0: /* none */
+               switch (pll[btv->c.nr]) {
+               case 0: /* none */
                        btv->pll.pll_crystal = 0;
                        btv->pll.pll_ifreq   = 0;
                        btv->pll.pll_ofreq   = 0;
-                        break;
-                case 1: /* 28 MHz */
+                       break;
+               case 1: /* 28 MHz */
                case 28:
-                        btv->pll.pll_ifreq   = 28636363;
+                       btv->pll.pll_ifreq   = 28636363;
                        btv->pll.pll_ofreq   = 0;
-                        btv->pll.pll_crystal = BT848_IFORM_XT0;
-                        break;
-                case 2: /* 35 MHz */
+                       btv->pll.pll_crystal = BT848_IFORM_XT0;
+                       break;
+               case 2: /* 35 MHz */
                case 35:
-                        btv->pll.pll_ifreq   = 35468950;
+                       btv->pll.pll_ifreq   = 35468950;
                        btv->pll.pll_ofreq   = 0;
-                        btv->pll.pll_crystal = BT848_IFORM_XT1;
-                        break;
-                }
-        }
+                       btv->pll.pll_crystal = BT848_IFORM_XT1;
+                       break;
+               }
+       }
        btv->pll.pll_current = -1;
 
        /* tuner configuration (from card list / autodetect / insmod option) */
@@ -2955,23 +3335,26 @@ void __devinit bttv_init_card2(struct bttv *btv)
 
        if (UNSET != bttv_tvcards[btv->c.type].tuner_type)
                if(UNSET == btv->tuner_type)
-                       btv->tuner_type = bttv_tvcards[btv->c.type].tuner_type;
+                       btv->tuner_type = bttv_tvcards[btv->c.type].tuner_type;
        if (UNSET != tuner[btv->c.nr])
                btv->tuner_type = tuner[btv->c.nr];
        printk("bttv%d: using tuner=%d\n",btv->c.nr,btv->tuner_type);
-       if (btv->pinnacle_id != UNSET)
-               bttv_call_i2c_clients(btv, AUDC_CONFIG_PINNACLE,
-                                     &btv->pinnacle_id);
+
        if (btv->tuner_type != UNSET) {
-               struct tuner_setup tun_setup;
+               struct tuner_setup tun_setup;
 
-               tun_setup.mode_mask = T_RADIO | T_ANALOG_TV | T_DIGITAL_TV;
+               tun_setup.mode_mask = T_ANALOG_TV | T_DIGITAL_TV;
                tun_setup.type = btv->tuner_type;
                tun_setup.addr = addr;
 
                bttv_call_i2c_clients(btv, TUNER_SET_TYPE_ADDR, &tun_setup);
        }
 
+       if (btv->pinnacle_id != UNSET) {
+               bttv_call_i2c_clients(btv, AUDC_CONFIG_PINNACLE,
+                                                       &btv->pinnacle_id);
+       }
+
        btv->svhs = bttv_tvcards[btv->c.type].svhs;
        if (svhs[btv->c.nr] != UNSET)
                btv->svhs = svhs[btv->c.nr];
@@ -2982,8 +3365,8 @@ void __devinit bttv_init_card2(struct bttv *btv)
                btv->has_radio=1;
        if (bttv_tvcards[btv->c.type].has_remote)
                btv->has_remote=1;
-       if (bttv_tvcards[btv->c.type].no_gpioirq)
-               btv->gpioirq=0;
+       if (!bttv_tvcards[btv->c.type].no_gpioirq)
+               btv->gpioirq=1;
        if (bttv_tvcards[btv->c.type].audio_hook)
                btv->audio_hook=bttv_tvcards[btv->c.type].audio_hook;
 
@@ -3024,6 +3407,9 @@ void __devinit bttv_init_card2(struct bttv *btv)
        if (0 == tda9887 && 0 == bttv_tvcards[btv->c.type].has_dvb &&
            bttv_I2CRead(btv, I2C_TDA9887, "TDA9887") >=0)
                tda9887 = 1;
+       /* Hybrid DVB card, DOES have a tda9887 */
+       if (btv->c.type == BTTV_BOARD_DVICO_FUSIONHDTV_5_LITE)
+               tda9887 = 1;
        if((btv->tuner_type == TUNER_PHILIPS_FM1216ME_MK3) ||
           (btv->tuner_type == TUNER_PHILIPS_FM1236_MK3) ||
           (btv->tuner_type == TUNER_PHILIPS_FM1256_IH3) ||
@@ -3045,11 +3431,11 @@ static void modtec_eeprom(struct bttv *btv)
        } else if (strncmp(&(eeprom_data[0x1e]),"Alps TSBB5",10) ==0) {
                btv->tuner_type=TUNER_ALPS_TSBB5_PAL_I;
                printk("bttv%d: Modtec: Tuner autodetected by eeprom: %s\n",
-                       btv->c.nr,&eeprom_data[0x1e]);
-        } else if (strncmp(&(eeprom_data[0x1e]),"Philips FM1246",14) ==0) {
-                btv->tuner_type=TUNER_PHILIPS_NTSC;
-                printk("bttv%d: Modtec: Tuner autodetected by eeprom: %s\n",
-                       btv->c.nr,&eeprom_data[0x1e]);
+                      btv->c.nr,&eeprom_data[0x1e]);
+       } else if (strncmp(&(eeprom_data[0x1e]),"Philips FM1246",14) ==0) {
+               btv->tuner_type=TUNER_PHILIPS_NTSC;
+               printk("bttv%d: Modtec: Tuner autodetected by eeprom: %s\n",
+                      btv->c.nr,&eeprom_data[0x1e]);
        } else {
                printk("bttv%d: Modtec: Unknown TunerString: %s\n",
                       btv->c.nr,&eeprom_data[0x1e]);
@@ -3114,7 +3500,7 @@ static int terratec_active_radio_upgrade(struct bttv *btv)
 static int __devinit pvr_altera_load(struct bttv *btv, u8 *micro, u32 microlen)
 {
        u32 n;
-       u8 bits;
+       u8 bits;
        int i;
 
        gpio_inout(0xffffff,BTTV_ALT_DATA|BTTV_ALT_DCLK|BTTV_ALT_NCONFIG);
@@ -3150,19 +3536,19 @@ static int __devinit pvr_altera_load(struct bttv *btv, u8 *micro, u32 microlen)
 
 static int __devinit pvr_boot(struct bttv *btv)
 {
-        const struct firmware *fw_entry;
+       const struct firmware *fw_entry;
        int rc;
 
        rc = request_firmware(&fw_entry, "hcwamc.rbf", &btv->c.pci->dev);
        if (rc != 0) {
                printk(KERN_WARNING "bttv%d: no altera firmware [via hotplug]\n",
                       btv->c.nr);
-                return rc;
-        }
+               return rc;
+       }
        rc = pvr_altera_load(btv, fw_entry->data, fw_entry->size);
        printk(KERN_INFO "bttv%d: altera firmware upload %s\n",
               btv->c.nr, (rc < 0) ? "failed" : "ok");
-        release_firmware(fw_entry);
+       release_firmware(fw_entry);
        return rc;
 }
 
@@ -3176,33 +3562,33 @@ static void __devinit osprey_eeprom(struct bttv *btv)
        unsigned long serial = 0;
 
        if (btv->c.type == 0) {
-               /* this might be an antique... check for MMAC label in eeprom */
-               if ((ee[0]=='M') && (ee[1]=='M') && (ee[2]=='A') && (ee[3]=='C')) {
-                       unsigned char checksum = 0;
-                       for (i =0; i<21; i++)
+              /* this might be an antique... check for MMAC label in eeprom */
+              if ((ee[0]=='M') && (ee[1]=='M') && (ee[2]=='A') && (ee[3]=='C')) {
+                      unsigned char checksum = 0;
+                      for (i =0; i<21; i++)
                               checksum += ee[i];
-                       if (checksum != ee[21])
+                      if (checksum != ee[21])
                               return;
-                      btv->c.type = BTTV_OSPREY1x0_848;
+                      btv->c.type = BTTV_BOARD_OSPREY1x0_848;
                       for (i = 12; i < 21; i++)
                               serial *= 10, serial += ee[i] - '0';
-               }
+              }
        } else {
               unsigned short type;
-               int offset = 4*16;
-
-               for(; offset < 8*16; offset += 16) {
-                       unsigned short checksum = 0;
-                       /* verify the checksum */
-                       for(i = 0; i<14; i++) checksum += ee[i+offset];
-                               checksum = ~checksum;  /* no idea why */
-                               if ((((checksum>>8)&0x0FF) == ee[offset+14]) &&
-                                   ((checksum & 0x0FF) == ee[offset+15])) {
-                               break;
-                       }
-               }
-
-               if (offset >= 8*16)
+              int offset = 4*16;
+
+              for(; offset < 8*16; offset += 16) {
+                      unsigned short checksum = 0;
+                      /* verify the checksum */
+                      for(i = 0; i<14; i++) checksum += ee[i+offset];
+                              checksum = ~checksum;  /* no idea why */
+                              if ((((checksum>>8)&0x0FF) == ee[offset+14]) &&
+                                  ((checksum & 0x0FF) == ee[offset+15])) {
+                              break;
+                      }
+              }
+
+              if (offset >= 8*16)
                       return;
 
               /* found a valid descriptor */
@@ -3212,47 +3598,47 @@ static void __devinit osprey_eeprom(struct bttv *btv)
 
               /* 848 based */
               case 0x0004:
-                      btv->c.type = BTTV_OSPREY1x0_848;
+                      btv->c.type = BTTV_BOARD_OSPREY1x0_848;
                       break;
               case 0x0005:
-                      btv->c.type = BTTV_OSPREY101_848;
+                      btv->c.type = BTTV_BOARD_OSPREY101_848;
                       break;
 
-               /* 878 based */
+              /* 878 based */
               case 0x0012:
               case 0x0013:
-                      btv->c.type = BTTV_OSPREY1x0;
+                      btv->c.type = BTTV_BOARD_OSPREY1x0;
                       break;
               case 0x0014:
               case 0x0015:
-                      btv->c.type = BTTV_OSPREY1x1;
+                      btv->c.type = BTTV_BOARD_OSPREY1x1;
                       break;
               case 0x0016:
               case 0x0017:
               case 0x0020:
-                      btv->c.type = BTTV_OSPREY1x1_SVID;
+                      btv->c.type = BTTV_BOARD_OSPREY1x1_SVID;
                       break;
               case 0x0018:
               case 0x0019:
               case 0x001E:
               case 0x001F:
-                      btv->c.type = BTTV_OSPREY2xx;
+                      btv->c.type = BTTV_BOARD_OSPREY2xx;
                       break;
               case 0x001A:
               case 0x001B:
-                      btv->c.type = BTTV_OSPREY2x0_SVID;
+                      btv->c.type = BTTV_BOARD_OSPREY2x0_SVID;
                       break;
               case 0x0040:
-                      btv->c.type = BTTV_OSPREY500;
+                      btv->c.type = BTTV_BOARD_OSPREY500;
                       break;
               case 0x0050:
               case 0x0056:
-                      btv->c.type = BTTV_OSPREY540;
+                      btv->c.type = BTTV_BOARD_OSPREY540;
                       /* bttv_osprey_540_init(btv); */
                       break;
               case 0x0060:
               case 0x0070:
-                      btv->c.type = BTTV_OSPREY2x0;
+                      btv->c.type = BTTV_BOARD_OSPREY2x0;
                       /* enable output on select control lines */
                       gpio_inout(0xffffff,0x000303);
                       break;
@@ -3274,27 +3660,27 @@ static void __devinit osprey_eeprom(struct bttv *btv)
 /* AVermedia specific stuff, from  bktr_card.c                             */
 
 static int tuner_0_table[] = {
-        TUNER_PHILIPS_NTSC,  TUNER_PHILIPS_PAL /* PAL-BG*/,
-        TUNER_PHILIPS_PAL,   TUNER_PHILIPS_PAL /* PAL-I*/,
-        TUNER_PHILIPS_PAL,   TUNER_PHILIPS_PAL,
-        TUNER_PHILIPS_SECAM, TUNER_PHILIPS_SECAM,
-        TUNER_PHILIPS_SECAM, TUNER_PHILIPS_PAL,
+       TUNER_PHILIPS_NTSC,  TUNER_PHILIPS_PAL /* PAL-BG*/,
+       TUNER_PHILIPS_PAL,   TUNER_PHILIPS_PAL /* PAL-I*/,
+       TUNER_PHILIPS_PAL,   TUNER_PHILIPS_PAL,
+       TUNER_PHILIPS_SECAM, TUNER_PHILIPS_SECAM,
+       TUNER_PHILIPS_SECAM, TUNER_PHILIPS_PAL,
        TUNER_PHILIPS_FM1216ME_MK3 };
 
 static int tuner_1_table[] = {
-        TUNER_TEMIC_NTSC,  TUNER_TEMIC_PAL,
+       TUNER_TEMIC_NTSC,  TUNER_TEMIC_PAL,
        TUNER_TEMIC_PAL,   TUNER_TEMIC_PAL,
        TUNER_TEMIC_PAL,   TUNER_TEMIC_PAL,
-        TUNER_TEMIC_4012FY5, TUNER_TEMIC_4012FY5, /* TUNER_TEMIC_SECAM */
-        TUNER_TEMIC_4012FY5, TUNER_TEMIC_PAL};
+       TUNER_TEMIC_4012FY5, TUNER_TEMIC_4012FY5, /* TUNER_TEMIC_SECAM */
+       TUNER_TEMIC_4012FY5, TUNER_TEMIC_PAL};
 
 static void __devinit avermedia_eeprom(struct bttv *btv)
 {
-        int tuner_make,tuner_tv_fm,tuner_format,tuner=0;
+       int tuner_make,tuner_tv_fm,tuner_format,tuner=0;
 
        tuner_make      = (eeprom_data[0x41] & 0x7);
-        tuner_tv_fm     = (eeprom_data[0x41] & 0x18) >> 3;
-        tuner_format    = (eeprom_data[0x42] & 0xf0) >> 4;
+       tuner_tv_fm     = (eeprom_data[0x41] & 0x18) >> 3;
+       tuner_format    = (eeprom_data[0x42] & 0xf0) >> 4;
        btv->has_remote = (eeprom_data[0x42] & 0x01);
 
        if (tuner_make == 0 || tuner_make == 2)
@@ -3325,13 +3711,13 @@ void bttv_tda9880_setnorm(struct bttv *btv, int norm)
 {
        /* fix up our card entry */
        if(norm==VIDEO_MODE_NTSC) {
-               bttv_tvcards[BTTV_VOODOOTV_FM].audiomux[0]=0x957fff;
-               bttv_tvcards[BTTV_VOODOOTV_FM].audiomux[4]=0x957fff;
+               bttv_tvcards[BTTV_BOARD_VOODOOTV_FM].audiomux[0]=0x957fff;
+               bttv_tvcards[BTTV_BOARD_VOODOOTV_FM].audiomux[4]=0x957fff;
                dprintk("bttv_tda9880_setnorm to NTSC\n");
        }
        else {
-               bttv_tvcards[BTTV_VOODOOTV_FM].audiomux[0]=0x947fff;
-                bttv_tvcards[BTTV_VOODOOTV_FM].audiomux[4]=0x947fff;
+               bttv_tvcards[BTTV_BOARD_VOODOOTV_FM].audiomux[0]=0x947fff;
+               bttv_tvcards[BTTV_BOARD_VOODOOTV_FM].audiomux[4]=0x947fff;
                dprintk("bttv_tda9880_setnorm to PAL\n");
        }
        /* set GPIO according */
@@ -3342,7 +3728,7 @@ void bttv_tda9880_setnorm(struct bttv *btv, int norm)
 
 /*
  * reset/enable the MSP on some Hauppauge cards
- * Thanks to Kyösti Mälkki (kmalkki@cc.hut.fi)!
+ * Thanks to Kyösti Mälkki (kmalkki@cc.hut.fi)!
  *
  * Hauppauge:  pin  5
  * Voodoo:     pin 20
@@ -3353,7 +3739,7 @@ static void __devinit boot_msp34xx(struct bttv *btv, int pin)
 
        gpio_inout(mask,mask);
        gpio_bits(mask,0);
-        udelay(2500);
+       udelay(2500);
        gpio_bits(mask,mask);
 
        if (bttv_gpio)
@@ -3429,7 +3815,7 @@ static void __devinit init_PXC200(struct bttv *btv)
        udelay(10);
        gpio_write(1<<2);
 
-               for (i = 0; i < ARRAY_SIZE(vals); i++) {
+       for (i = 0; i < ARRAY_SIZE(vals); i++) {
                tmp=bttv_I2CWrite(btv,0x1E,0,vals[i],1);
                if (tmp != -1) {
                        printk(KERN_INFO
@@ -3872,30 +4258,30 @@ avermedia_tv_stereo_audio(struct bttv *btv, struct video_audio *v, int set)
 static void
 lt9415_audio(struct bttv *btv, struct video_audio *v, int set)
 {
-        int val = 0;
+       int val = 0;
 
-        if (gpio_read() & 0x4000) {
+       if (gpio_read() & 0x4000) {
                v->mode = VIDEO_SOUND_MONO;
                return;
        }
 
-        if (set) {
-                if (v->mode & VIDEO_SOUND_LANG2)  /* A2 SAP */
-                        val = 0x0080;
+       if (set) {
+               if (v->mode & VIDEO_SOUND_LANG2)  /* A2 SAP */
+                       val = 0x0080;
                if (v->mode & VIDEO_SOUND_STEREO) /* A2 stereo */
-                        val = 0x0880;
-                if ((v->mode & VIDEO_SOUND_LANG1) ||
+                       val = 0x0880;
+               if ((v->mode & VIDEO_SOUND_LANG1) ||
                    (v->mode & VIDEO_SOUND_MONO))
                        val = 0;
                gpio_bits(0x0880, val);
-                if (bttv_gpio)
-                        bttv_gpio_tracking(btv,"lt9415");
-        } else {
+               if (bttv_gpio)
+                       bttv_gpio_tracking(btv,"lt9415");
+       } else {
                /* autodetect doesn't work with this card :-( */
-                v->mode = VIDEO_SOUND_MONO | VIDEO_SOUND_STEREO |
+               v->mode = VIDEO_SOUND_MONO | VIDEO_SOUND_STEREO |
                        VIDEO_SOUND_LANG1 | VIDEO_SOUND_LANG2;
-                return;
-        }
+               return;
+       }
 }
 
 /* TDA9821 on TerraTV+ Bt848, Bt878 */
@@ -4018,26 +4404,26 @@ fv2000s_audio(struct bttv *btv, struct video_audio *v, int set)
 static void
 windvr_audio(struct bttv *btv, struct video_audio *v, int set)
 {
-        unsigned long val = 0;
-
-        if (set) {
-                if (v->mode & VIDEO_SOUND_MONO)
-                        val = 0x040000;
-                if (v->mode & VIDEO_SOUND_LANG1)
-                        val = 0;
-                if (v->mode & VIDEO_SOUND_LANG2)
-                        val = 0x100000;
-                if (v->mode & VIDEO_SOUND_STEREO)
-                        val = 0;
-                if (val) {
+       unsigned long val = 0;
+
+       if (set) {
+               if (v->mode & VIDEO_SOUND_MONO)
+                       val = 0x040000;
+               if (v->mode & VIDEO_SOUND_LANG1)
+                       val = 0;
+               if (v->mode & VIDEO_SOUND_LANG2)
+                       val = 0x100000;
+               if (v->mode & VIDEO_SOUND_STEREO)
+                       val = 0;
+               if (val) {
                        gpio_bits(0x140000, val);
-                        if (bttv_gpio)
-                                bttv_gpio_tracking(btv,"windvr");
-                }
-        } else {
-                v->mode = VIDEO_SOUND_MONO | VIDEO_SOUND_STEREO |
-                          VIDEO_SOUND_LANG1 | VIDEO_SOUND_LANG2;
-        }
+                       if (bttv_gpio)
+                               bttv_gpio_tracking(btv,"windvr");
+               }
+       } else {
+               v->mode = VIDEO_SOUND_MONO | VIDEO_SOUND_STEREO |
+                         VIDEO_SOUND_LANG1 | VIDEO_SOUND_LANG2;
+       }
 }
 
 /*
@@ -4280,10 +4666,10 @@ static void kodicom4400r_init(struct bttv *btv)
 static void xguard_muxsel(struct bttv *btv, unsigned int input)
 {
        static const int masks[] = {
-                ENB0, ENB0|IN00, ENB0|IN10, ENB0|IN00|IN10,
-                ENA0, ENA0|IN00, ENA0|IN10, ENA0|IN00|IN10,
-                ENB1, ENB1|IN01, ENB1|IN11, ENB1|IN01|IN11,
-                ENA1, ENA1|IN01, ENA1|IN11, ENA1|IN01|IN11,
+               ENB0, ENB0|IN00, ENB0|IN10, ENB0|IN00|IN10,
+               ENA0, ENA0|IN00, ENA0|IN10, ENA0|IN00|IN10,
+               ENB1, ENB1|IN01, ENB1|IN11, ENB1|IN01|IN11,
+               ENA1, ENA1|IN01, ENA1|IN11, ENA1|IN01|IN11,
        };
        gpio_write(masks[input%16]);
 }
@@ -4388,10 +4774,10 @@ static void ivc120_muxsel(struct bttv *btv, unsigned int input)
 
 static void PXC200_muxsel(struct bttv *btv, unsigned int input)
 {
-        int rc;
+       int rc;
        long mux;
        int bitmask;
-        unsigned char buf[2];
+       unsigned char buf[2];
 
        /* Read PIC config to determine if this is a PXC200F */
        /* PX_I2C_CMD_CFG*/
@@ -4421,14 +4807,14 @@ static void PXC200_muxsel(struct bttv *btv, unsigned int input)
        /* bitmask=0x30f; */
        bitmask=0x302;
        /* check whether we have a PXC200A */
-       if (btv->cardid == PX_PXC200A_CARDID)  {
+       if (btv->cardid == PX_PXC200A_CARDID)  {
           bitmask ^= 0x180; /* use 7 and 9, not 8 and 9 */
           bitmask |= 7<<4; /* the DAC */
        }
        btwrite(bitmask, BT848_GPIO_OUT_EN);
 
        bitmask = btread(BT848_GPIO_DATA);
-       if (btv->cardid == PX_PXC200A_CARDID)
+       if (btv->cardid == PX_PXC200A_CARDID)
          bitmask = (bitmask & ~0x280) | ((mux & 2) << 8) | ((mux & 1) << 7);
        else /* older device */
          bitmask = (bitmask & ~0x300) | ((mux & 3) << 8);
@@ -4441,7 +4827,7 @@ static void PXC200_muxsel(struct bttv *btv, unsigned int input)
         *
         * needed because bttv-driver sets mux before calling this function
         */
-       if (btv->cardid == PX_PXC200A_CARDID)
+       if (btv->cardid == PX_PXC200A_CARDID)
          btaor(2<<5, ~BT848_IFORM_MUXSEL, BT848_IFORM);
        else /* older device */
          btand(~BT848_IFORM_MUXSEL,BT848_IFORM);
@@ -4485,10 +4871,9 @@ void __devinit bttv_check_chipset(void)
        }
        if (UNSET != latency)
                printk(KERN_INFO "bttv: pci latency fixup [%d]\n",latency);
-
-       while ((dev = pci_find_device(PCI_VENDOR_ID_INTEL,
+       while ((dev = pci_get_device(PCI_VENDOR_ID_INTEL,
                                      PCI_DEVICE_ID_INTEL_82441, dev))) {
-                unsigned char b;
+               unsigned char b;
                pci_read_config_byte(dev, 0x53, &b);
                if (bttv_debug)
                        printk(KERN_INFO "bttv: Host bridge: 82441FX Natoma, "
@@ -4498,7 +4883,7 @@ void __devinit bttv_check_chipset(void)
 
 int __devinit bttv_handle_chipset(struct bttv *btv)
 {
-       unsigned char command;
+       unsigned char command;
 
        if (!triton1 && !vsfx && UNSET == latency)
                return 0;
@@ -4519,13 +4904,13 @@ int __devinit bttv_handle_chipset(struct bttv *btv)
                        btv->triton1 = BT848_INT_ETBF;
        } else {
                /* bt878 has a bit in the pci config space for it */
-                pci_read_config_byte(btv->c.pci, BT878_DEVCTRL, &command);
+               pci_read_config_byte(btv->c.pci, BT878_DEVCTRL, &command);
                if (triton1)
                        command |= BT878_EN_TBFX;
                if (vsfx)
                        command |= BT878_EN_VSFX;
-                pci_write_config_byte(btv->c.pci, BT878_DEVCTRL, command);
-        }
+               pci_write_config_byte(btv->c.pci, BT878_DEVCTRL, command);
+       }
        if (UNSET != latency)
                pci_write_config_byte(btv->c.pci, PCI_LATENCY_TIMER, latency);
        return 0;
index d538a994ff04da1d68bcfe9ddc5023671c53d1a8..0005741d55141c0b1471cf8932845ac2e44990e9 100644 (file)
@@ -3,7 +3,7 @@
     bttv - Bt848 frame grabber driver
 
     Copyright (C) 1996,97,98 Ralph  Metzler <rjkm@thp.uni-koeln.de>
-                           & Marcus Metzler <mocm@thp.uni-koeln.de>
+                          & Marcus Metzler <mocm@thp.uni-koeln.de>
     (c) 1999-2002 Gerd Knorr <kraxel@bytesex.org>
 
     some v4l2 code lines are taken from Justin's bttv2 driver which is
@@ -192,8 +192,8 @@ static u8 SRAM_Table[][60] =
 
 const struct bttv_tvnorm bttv_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 */
+       /* 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 */
        {
                .v4l2_id        = V4L2_STD_PAL,
                .name           = "PAL",
@@ -806,9 +806,9 @@ static void bt848A_set_timing(struct bttv *btv)
                        btv->c.nr,table_idx);
 
                /* timing change...reset timing generator address */
-                       btwrite(0x00, BT848_TGCTRL);
-                       btwrite(0x02, BT848_TGCTRL);
-                       btwrite(0x00, BT848_TGCTRL);
+               btwrite(0x00, BT848_TGCTRL);
+               btwrite(0x02, BT848_TGCTRL);
+               btwrite(0x00, BT848_TGCTRL);
 
                len=SRAM_Table[table_idx][0];
                for(i = 1; i <= len; i++)
@@ -847,7 +847,7 @@ static void bt848_hue(struct bttv *btv, int hue)
 
        /* -128 to 127 */
        value = (hue >> 8) - 128;
-        btwrite(value & 0xff, BT848_HUE);
+       btwrite(value & 0xff, BT848_HUE);
 }
 
 static void bt848_contrast(struct bttv *btv, int cont)
@@ -859,9 +859,9 @@ static void bt848_contrast(struct bttv *btv, int cont)
        /* 0-511 */
        value = (cont  >> 7);
        hibit = (value >> 6) & 4;
-        btwrite(value & 0xff, BT848_CONTRAST_LO);
-        btaor(hibit, ~4, BT848_E_CONTROL);
-        btaor(hibit, ~4, BT848_O_CONTROL);
+       btwrite(value & 0xff, BT848_CONTRAST_LO);
+       btaor(hibit, ~4, BT848_E_CONTROL);
+       btaor(hibit, ~4, BT848_O_CONTROL);
 }
 
 static void bt848_sat(struct bttv *btv, int color)
@@ -873,12 +873,12 @@ static void bt848_sat(struct bttv *btv, int color)
        /* 0-511 for the color */
        val_u   = ((color * btv->opt_uv_ratio) / 50) >> 7;
        val_v   = (((color * (100 - btv->opt_uv_ratio) / 50) >>7)*180L)/254;
-        hibits  = (val_u >> 7) & 2;
+       hibits  = (val_u >> 7) & 2;
        hibits |= (val_v >> 8) & 1;
-        btwrite(val_u & 0xff, BT848_SAT_U_LO);
-        btwrite(val_v & 0xff, BT848_SAT_V_LO);
-        btaor(hibits, ~3, BT848_E_CONTROL);
-        btaor(hibits, ~3, BT848_O_CONTROL);
+       btwrite(val_u & 0xff, BT848_SAT_U_LO);
+       btwrite(val_v & 0xff, BT848_SAT_V_LO);
+       btaor(hibits, ~3, BT848_E_CONTROL);
+       btaor(hibits, ~3, BT848_O_CONTROL);
 }
 
 /* ----------------------------------------------------------------------- */
@@ -891,7 +891,7 @@ video_mux(struct bttv *btv, unsigned int input)
        if (input >= bttv_tvcards[btv->c.type].video_inputs)
                return -EINVAL;
 
-        /* needed by RemoteVideo MX */
+       /* needed by RemoteVideo MX */
        mask2 = bttv_tvcards[btv->c.type].gpiomask2;
        if (mask2)
                gpio_inout(mask2,mask2);
@@ -964,7 +964,7 @@ i2c_vidiocschan(struct bttv *btv)
        c.norm    = btv->tvnorm;
        c.channel = btv->input;
        bttv_call_i2c_clients(btv,VIDIOCSCHAN,&c);
-       if (btv->c.type == BTTV_VOODOOTV_FM)
+       if (btv->c.type == BTTV_BOARD_VOODOOTV_FM)
                bttv_tda9880_setnorm(btv,c.norm);
 }
 
@@ -988,7 +988,7 @@ set_tvnorm(struct bttv *btv, unsigned int norm)
        bt848A_set_timing(btv);
 
        switch (btv->c.type) {
-       case BTTV_VOODOOTV_FM:
+       case BTTV_BOARD_VOODOOTV_FM:
                bttv_tda9880_setnorm(btv,norm);
                break;
        }
@@ -1055,22 +1055,22 @@ static void init_bt848(struct bttv *btv)
        btwrite(BT848_COLOR_CTL_GAMMA, BT848_COLOR_CTL);
        btwrite(BT848_IFORM_XTAUTO | BT848_IFORM_AUTO, BT848_IFORM);
 
-        /* set planar and packed mode trigger points and         */
-        /* set rising edge of inverted GPINTR pin as irq trigger */
-        btwrite(BT848_GPIO_DMA_CTL_PKTP_32|
-                BT848_GPIO_DMA_CTL_PLTP1_16|
-                BT848_GPIO_DMA_CTL_PLTP23_16|
-                BT848_GPIO_DMA_CTL_GPINTC|
-                BT848_GPIO_DMA_CTL_GPINTI,
-                BT848_GPIO_DMA_CTL);
+       /* set planar and packed mode trigger points and         */
+       /* set rising edge of inverted GPINTR pin as irq trigger */
+       btwrite(BT848_GPIO_DMA_CTL_PKTP_32|
+               BT848_GPIO_DMA_CTL_PLTP1_16|
+               BT848_GPIO_DMA_CTL_PLTP23_16|
+               BT848_GPIO_DMA_CTL_GPINTC|
+               BT848_GPIO_DMA_CTL_GPINTI,
+               BT848_GPIO_DMA_CTL);
 
        val = btv->opt_chroma_agc ? BT848_SCLOOP_CAGC : 0;
-        btwrite(val, BT848_E_SCLOOP);
-        btwrite(val, BT848_O_SCLOOP);
+       btwrite(val, BT848_E_SCLOOP);
+       btwrite(val, BT848_O_SCLOOP);
 
-        btwrite(0x20, BT848_E_VSCALE_HI);
-        btwrite(0x20, BT848_O_VSCALE_HI);
-        btwrite(BT848_ADC_RESERVED | (btv->opt_adc_crush ? BT848_ADC_CRUSH : 0),
+       btwrite(0x20, BT848_E_VSCALE_HI);
+       btwrite(0x20, BT848_O_VSCALE_HI);
+       btwrite(BT848_ADC_RESERVED | (btv->opt_adc_crush ? BT848_ADC_CRUSH : 0),
                BT848_ADC);
 
        btwrite(whitecrush_upper, BT848_WC_UP);
@@ -1089,7 +1089,7 @@ static void init_bt848(struct bttv *btv)
        bt848_contrast(btv, btv->contrast);
        bt848_sat(btv,      btv->saturation);
 
-        /* interrupt */
+       /* interrupt */
        init_irqreg(btv);
 }
 
@@ -1105,7 +1105,7 @@ static void bttv_reinit_bt848(struct bttv *btv)
        spin_unlock_irqrestore(&btv->s_lock,flags);
 
        init_bt848(btv);
-        btv->pll.pll_current = -1;
+       btv->pll.pll_current = -1;
        set_input(btv,btv->input);
 }
 
@@ -1398,7 +1398,7 @@ bttv_switch_overlay(struct bttv *btv, struct bttv_fh *fh,
 /* video4linux (1) interface                                               */
 
 static int bttv_prepare_buffer(struct bttv *btv, struct bttv_buffer *buf,
-                              const struct bttv_format *fmt,
+                              const struct bttv_format *fmt,
                               unsigned int width, unsigned int height,
                               enum v4l2_field field)
 {
@@ -1521,8 +1521,8 @@ static const char *v4l1_ioctls[] = {
 static int bttv_common_ioctls(struct bttv *btv, unsigned int cmd, void *arg)
 {
        switch (cmd) {
-        case BTTV_VERSION:
-                return BTTV_VERSION_CODE;
+       case BTTV_VERSION:
+               return BTTV_VERSION_CODE;
 
        /* ***  v4l1  *** ************************************************ */
        case VIDIOCGFREQ:
@@ -1576,32 +1576,32 @@ static int bttv_common_ioctls(struct bttv *btv, unsigned int cmd, void *arg)
                return 0;
        }
 
-        case VIDIOCGCHAN:
-        {
-                struct video_channel *v = arg;
+       case VIDIOCGCHAN:
+       {
+               struct video_channel *v = arg;
                unsigned int channel = v->channel;
 
-                if (channel >= bttv_tvcards[btv->c.type].video_inputs)
-                        return -EINVAL;
-                v->tuners=0;
-                v->flags = VIDEO_VC_AUDIO;
-                v->type = VIDEO_TYPE_CAMERA;
-                v->norm = btv->tvnorm;
+               if (channel >= bttv_tvcards[btv->c.type].video_inputs)
+                       return -EINVAL;
+               v->tuners=0;
+               v->flags = VIDEO_VC_AUDIO;
+               v->type = VIDEO_TYPE_CAMERA;
+               v->norm = btv->tvnorm;
                if (channel == bttv_tvcards[btv->c.type].tuner)  {
-                        strcpy(v->name,"Television");
-                        v->flags|=VIDEO_VC_TUNER;
-                        v->type=VIDEO_TYPE_TV;
-                        v->tuners=1;
-                } else if (channel == btv->svhs) {
-                        strcpy(v->name,"S-Video");
-                } else {
-                        sprintf(v->name,"Composite%d",channel);
+                       strcpy(v->name,"Television");
+                       v->flags|=VIDEO_VC_TUNER;
+                       v->type=VIDEO_TYPE_TV;
+                       v->tuners=1;
+               } else if (channel == btv->svhs) {
+                       strcpy(v->name,"S-Video");
+               } else {
+                       sprintf(v->name,"Composite%d",channel);
                }
                return 0;
-        }
-        case VIDIOCSCHAN:
-        {
-                struct video_channel *v = arg;
+       }
+       case VIDIOCSCHAN:
+       {
+               struct video_channel *v = arg;
                unsigned int channel = v->channel;
 
                if (channel >= bttv_tvcards[btv->c.type].video_inputs)
@@ -1623,7 +1623,7 @@ static int bttv_common_ioctls(struct bttv *btv, unsigned int cmd, void *arg)
                return 0;
        }
 
-        case VIDIOCGAUDIO:
+       case VIDIOCGAUDIO:
        {
                struct video_audio *v = arg;
 
@@ -1728,7 +1728,7 @@ static int bttv_common_ioctls(struct bttv *btv, unsigned int cmd, void *arg)
                } else if (i->index == btv->svhs) {
                        sprintf(i->name, "S-Video");
                } else {
-                        sprintf(i->name,"Composite%d",i->index);
+                       sprintf(i->name,"Composite%d",i->index);
                }
                if (i->index == btv->input) {
                        __u32 dstatus = btread(BT848_DSTATUS);
@@ -1851,6 +1851,11 @@ static int bttv_common_ioctls(struct bttv *btv, unsigned int cmd, void *arg)
                up(&btv->lock);
                return 0;
        }
+       case VIDIOC_LOG_STATUS:
+       {
+               bttv_call_i2c_clients(btv, VIDIOC_LOG_STATUS, 0);
+               return 0;
+       }
 
        default:
                return -ENOIOCTLCMD;
@@ -2163,7 +2168,7 @@ static int bttv_s_fmt(struct bttv_fh *fh, struct bttv *btv,
                if (0 != retval)
                        return retval;
                if (locked_btres(fh->btv, RESOURCE_VBI))
-                        return -EBUSY;
+                       return -EBUSY;
                bttv_vbi_try_fmt(fh,f);
                bttv_vbi_setlines(fh,btv,f->fmt.vbi.count[0]);
                bttv_vbi_get_fmt(fh,f);
@@ -2201,9 +2206,9 @@ static int bttv_do_ioctl(struct inode *inode, struct file *file,
                bttv_reinit_bt848(btv);
 
        switch (cmd) {
-        case VIDIOCSFREQ:
-        case VIDIOCSTUNER:
-        case VIDIOCSCHAN:
+       case VIDIOCSFREQ:
+       case VIDIOCSTUNER:
+       case VIDIOCSCHAN:
        case VIDIOC_S_CTRL:
        case VIDIOC_S_STD:
        case VIDIOC_S_INPUT:
@@ -2219,10 +2224,10 @@ static int bttv_do_ioctl(struct inode *inode, struct file *file,
        /* ***  v4l1  *** ************************************************ */
        case VIDIOCGCAP:
        {
-                struct video_capability *cap = arg;
+               struct video_capability *cap = arg;
 
                memset(cap,0,sizeof(*cap));
-                strcpy(cap->name,btv->video_dev->name);
+               strcpy(cap->name,btv->video_dev->name);
                if (V4L2_BUF_TYPE_VBI_CAPTURE == fh->type) {
                        /* vbi */
                        cap->type = VID_TYPE_TUNER|VID_TYPE_TELETEXT;
@@ -2242,7 +2247,7 @@ static int bttv_do_ioctl(struct inode *inode, struct file *file,
                }
                cap->channels  = bttv_tvcards[btv->c.type].video_inputs;
                cap->audios    = bttv_tvcards[btv->c.type].audio_inputs;
-                return 0;
+               return 0;
        }
 
        case VIDIOCGPICT:
@@ -2291,7 +2296,7 @@ static int bttv_do_ioctl(struct inode *inode, struct file *file,
                bt848_hue(btv,pic->hue);
                bt848_sat(btv,pic->colour);
                up(&fh->cap.lock);
-                return 0;
+               return 0;
        }
 
        case VIDIOCGWIN:
@@ -2352,8 +2357,8 @@ static int bttv_do_ioctl(struct inode *inode, struct file *file,
                unsigned long end;
 
                if(!capable(CAP_SYS_ADMIN) &&
-                   !capable(CAP_SYS_RAWIO))
-                        return -EPERM;
+                  !capable(CAP_SYS_RAWIO))
+                       return -EPERM;
                end = (unsigned long)fbuf->base +
                        fbuf->height * fbuf->bytesperline;
                down(&fh->cap.lock);
@@ -2427,7 +2432,7 @@ static int bttv_do_ioctl(struct inode *inode, struct file *file,
                }
 
                /* switch over */
-               retval = bttv_switch_overlay(btv,fh,new);
+               retval = bttv_switch_overlay(btv,fh,new);
                up(&fh->cap.lock);
                return retval;
        }
@@ -2566,13 +2571,13 @@ static int bttv_do_ioctl(struct inode *inode, struct file *file,
                return 0;
        }
 
-        case BTTV_VERSION:
-        case VIDIOCGFREQ:
-        case VIDIOCSFREQ:
-        case VIDIOCGTUNER:
-        case VIDIOCSTUNER:
-        case VIDIOCGCHAN:
-        case VIDIOCSCHAN:
+       case BTTV_VERSION:
+       case VIDIOCGFREQ:
+       case VIDIOCSFREQ:
+       case VIDIOCGTUNER:
+       case VIDIOCSTUNER:
+       case VIDIOCGCHAN:
+       case VIDIOCSCHAN:
        case VIDIOCGAUDIO:
        case VIDIOCSAUDIO:
                return bttv_common_ioctls(btv,cmd,arg);
@@ -2584,8 +2589,8 @@ static int bttv_do_ioctl(struct inode *inode, struct file *file,
 
                if (0 == v4l2)
                        return -EINVAL;
-                strcpy(cap->driver,"bttv");
-                strlcpy(cap->card,btv->video_dev->name,sizeof(cap->card));
+               strcpy(cap->driver,"bttv");
+               strlcpy(cap->card,btv->video_dev->name,sizeof(cap->card));
                sprintf(cap->bus_info,"PCI:%s",pci_name(btv->c.pci));
                cap->version = BTTV_VERSION_CODE;
                cap->capabilities =
@@ -2856,6 +2861,7 @@ static int bttv_do_ioctl(struct inode *inode, struct file *file,
        case VIDIOC_S_TUNER:
        case VIDIOC_G_FREQUENCY:
        case VIDIOC_S_FREQUENCY:
+       case VIDIOC_LOG_STATUS:
                return bttv_common_ioctls(btv,cmd,arg);
 
        default:
@@ -3091,7 +3097,7 @@ static struct video_device bttv_video_template =
 {
        .name     = "UNSET",
        .type     = VID_TYPE_CAPTURE|VID_TYPE_TUNER|
-                   VID_TYPE_CLIPPING|VID_TYPE_SCALES,
+                   VID_TYPE_CLIPPING|VID_TYPE_SCALES,
        .hardware = VID_HARDWARE_BT848,
        .fops     = &bttv_fops,
        .minor    = -1,
@@ -3137,7 +3143,7 @@ static int radio_open(struct inode *inode, struct file *file)
        audio_mux(btv,AUDIO_RADIO);
 
        up(&btv->lock);
-        return 0;
+       return 0;
 }
 
 static int radio_release(struct inode *inode, struct file *file)
@@ -3160,34 +3166,34 @@ static int radio_do_ioctl(struct inode *inode, struct file *file,
        switch (cmd) {
        case VIDIOCGCAP:
        {
-                struct video_capability *cap = arg;
+               struct video_capability *cap = arg;
 
                memset(cap,0,sizeof(*cap));
-                strcpy(cap->name,btv->radio_dev->name);
-                cap->type = VID_TYPE_TUNER;
+               strcpy(cap->name,btv->radio_dev->name);
+               cap->type = VID_TYPE_TUNER;
                cap->channels = 1;
                cap->audios = 1;
-                return 0;
+               return 0;
        }
 
-        case VIDIOCGTUNER:
-        {
-                struct video_tuner *v = arg;
+       case VIDIOCGTUNER:
+       {
+               struct video_tuner *v = arg;
 
-                if(v->tuner)
-                        return -EINVAL;
+               if(v->tuner)
+                       return -EINVAL;
                memset(v,0,sizeof(*v));
-                strcpy(v->name, "Radio");
-                bttv_call_i2c_clients(btv,cmd,v);
-                return 0;
-        }
-        case VIDIOCSTUNER:
+               strcpy(v->name, "Radio");
+               bttv_call_i2c_clients(btv,cmd,v);
+               return 0;
+       }
+       case VIDIOCSTUNER:
                /* nothing to do */
                return 0;
 
        case BTTV_VERSION:
-        case VIDIOCGFREQ:
-        case VIDIOCSFREQ:
+       case VIDIOCGFREQ:
+       case VIDIOCSFREQ:
        case VIDIOCGAUDIO:
        case VIDIOCSAUDIO:
                return bttv_common_ioctls(btv,cmd,arg);
@@ -3693,7 +3699,7 @@ static irqreturn_t bttv_irq(int irq, void *dev_id, struct pt_regs * regs)
                }
 
                if (astat&BT848_INT_VSYNC)
-                        btv->field_count++;
+                       btv->field_count++;
 
                if (astat & BT848_INT_GPINT) {
                        wake_up(&btv->gpioq);
@@ -3705,13 +3711,13 @@ static irqreturn_t bttv_irq(int irq, void *dev_id, struct pt_regs * regs)
                        wake_up(&btv->i2c_queue);
                }
 
-                if ((astat & BT848_INT_RISCI)  &&  (stat & (4<<28)))
+               if ((astat & BT848_INT_RISCI)  &&  (stat & (4<<28)))
                        bttv_irq_switch_vbi(btv);
 
-                if ((astat & BT848_INT_RISCI)  &&  (stat & (2<<28)))
+               if ((astat & BT848_INT_RISCI)  &&  (stat & (2<<28)))
                        bttv_irq_wakeup_top(btv);
 
-                if ((astat & BT848_INT_RISCI)  &&  (stat & (1<<28)))
+               if ((astat & BT848_INT_RISCI)  &&  (stat & (1<<28)))
                        bttv_irq_switch_video(btv);
 
                if ((astat & BT848_INT_HLOCK)  &&  btv->opt_automute)
@@ -3736,10 +3742,22 @@ static irqreturn_t bttv_irq(int irq, void *dev_id, struct pt_regs * regs)
 
                count++;
                if (count > 4) {
-                       btwrite(0, BT848_INT_MASK);
-                       printk(KERN_ERR
-                              "bttv%d: IRQ lockup, cleared int mask [", btv->c.nr);
+
+                       if (count > 8 || !(astat & BT848_INT_GPINT)) {
+                               btwrite(0, BT848_INT_MASK);
+
+                               printk(KERN_ERR
+                                          "bttv%d: IRQ lockup, cleared int mask [", btv->c.nr);
+                       } else {
+                               printk(KERN_ERR
+                                          "bttv%d: IRQ lockup, clearing GPINT from int mask [", btv->c.nr);
+
+                               btwrite(btread(BT848_INT_MASK) & (-1 ^ BT848_INT_GPINT),
+                                               BT848_INT_MASK);
+                       };
+
                        bttv_print_irqbits(stat,astat);
+
                        printk("]\n");
                }
        }
@@ -3808,7 +3826,7 @@ static int __devinit bttv_register_video(struct bttv *btv)
 
        /* video */
        btv->video_dev = vdev_init(btv, &bttv_video_template, "video");
-        if (NULL == btv->video_dev)
+       if (NULL == btv->video_dev)
                goto err;
        if (video_register_device(btv->video_dev,VFL_TYPE_GRABBER,video_nr)<0)
                goto err;
@@ -3818,18 +3836,18 @@ static int __devinit bttv_register_video(struct bttv *btv)
 
        /* vbi */
        btv->vbi_dev = vdev_init(btv, &bttv_vbi_template, "vbi");
-        if (NULL == btv->vbi_dev)
+       if (NULL == btv->vbi_dev)
                goto err;
-        if (video_register_device(btv->vbi_dev,VFL_TYPE_VBI,vbi_nr)<0)
+       if (video_register_device(btv->vbi_dev,VFL_TYPE_VBI,vbi_nr)<0)
                goto err;
        printk(KERN_INFO "bttv%d: registered device vbi%d\n",
               btv->c.nr,btv->vbi_dev->minor & 0x1f);
 
-        if (!btv->has_radio)
+       if (!btv->has_radio)
                return 0;
        /* radio */
        btv->radio_dev = vdev_init(btv, &radio_template, "radio");
-        if (NULL == btv->radio_dev)
+       if (NULL == btv->radio_dev)
                goto err;
        if (video_register_device(btv->radio_dev, VFL_TYPE_RADIO,radio_nr)<0)
                goto err;
@@ -3850,11 +3868,11 @@ static int __devinit bttv_register_video(struct bttv *btv)
 static void pci_set_command(struct pci_dev *dev)
 {
 #if defined(__powerpc__)
-        unsigned int cmd;
+       unsigned int cmd;
 
-        pci_read_config_dword(dev, PCI_COMMAND, &cmd);
-        cmd = (cmd | PCI_COMMAND_MEMORY );
-        pci_write_config_dword(dev, PCI_COMMAND, cmd);
+       pci_read_config_dword(dev, PCI_COMMAND, &cmd);
+       cmd = (cmd | PCI_COMMAND_MEMORY );
+       pci_write_config_dword(dev, PCI_COMMAND, cmd);
 #endif
 }
 
@@ -3868,63 +3886,62 @@ static int __devinit bttv_probe(struct pci_dev *dev,
        if (bttv_num == BTTV_MAX)
                return -ENOMEM;
        printk(KERN_INFO "bttv: Bt8xx card found (%d).\n", bttv_num);
-        btv=&bttvs[bttv_num];
+       btv=&bttvs[bttv_num];
        memset(btv,0,sizeof(*btv));
        btv->c.nr  = bttv_num;
        sprintf(btv->c.name,"bttv%d",btv->c.nr);
 
        /* initialize structs / fill in defaults */
-        init_MUTEX(&btv->lock);
-        init_MUTEX(&btv->reslock);
-        spin_lock_init(&btv->s_lock);
-        spin_lock_init(&btv->gpio_lock);
-        init_waitqueue_head(&btv->gpioq);
-        init_waitqueue_head(&btv->i2c_queue);
-        INIT_LIST_HEAD(&btv->c.subs);
-        INIT_LIST_HEAD(&btv->capture);
-        INIT_LIST_HEAD(&btv->vcapture);
+       init_MUTEX(&btv->lock);
+       init_MUTEX(&btv->reslock);
+       spin_lock_init(&btv->s_lock);
+       spin_lock_init(&btv->gpio_lock);
+       init_waitqueue_head(&btv->gpioq);
+       init_waitqueue_head(&btv->i2c_queue);
+       INIT_LIST_HEAD(&btv->c.subs);
+       INIT_LIST_HEAD(&btv->capture);
+       INIT_LIST_HEAD(&btv->vcapture);
        v4l2_prio_init(&btv->prio);
 
        init_timer(&btv->timeout);
        btv->timeout.function = bttv_irq_timeout;
        btv->timeout.data     = (unsigned long)btv;
 
-        btv->i2c_rc = -1;
-        btv->tuner_type  = UNSET;
-        btv->pinnacle_id = UNSET;
+       btv->i2c_rc = -1;
+       btv->tuner_type  = UNSET;
+       btv->pinnacle_id = UNSET;
        btv->new_input   = UNSET;
-       btv->gpioirq     = 1;
        btv->has_radio=radio[btv->c.nr];
 
        /* pci stuff (init, get irq/mmio, ... */
        btv->c.pci = dev;
-        btv->id  = dev->device;
+       btv->id  = dev->device;
        if (pci_enable_device(dev)) {
-                printk(KERN_WARNING "bttv%d: Can't enable device.\n",
+               printk(KERN_WARNING "bttv%d: Can't enable device.\n",
                       btv->c.nr);
                return -EIO;
        }
-        if (pci_set_dma_mask(dev, DMA_32BIT_MASK)) {
-                printk(KERN_WARNING "bttv%d: No suitable DMA available.\n",
+       if (pci_set_dma_mask(dev, DMA_32BIT_MASK)) {
+               printk(KERN_WARNING "bttv%d: No suitable DMA available.\n",
                       btv->c.nr);
                return -EIO;
-        }
+       }
        if (!request_mem_region(pci_resource_start(dev,0),
                                pci_resource_len(dev,0),
                                btv->c.name)) {
-                printk(KERN_WARNING "bttv%d: can't request iomem (0x%lx).\n",
+               printk(KERN_WARNING "bttv%d: can't request iomem (0x%lx).\n",
                       btv->c.nr, pci_resource_start(dev,0));
                return -EBUSY;
        }
-        pci_set_master(dev);
+       pci_set_master(dev);
        pci_set_command(dev);
        pci_set_drvdata(dev,btv);
 
-        pci_read_config_byte(dev, PCI_CLASS_REVISION, &btv->revision);
-        pci_read_config_byte(dev, PCI_LATENCY_TIMER, &lat);
-        printk(KERN_INFO "bttv%d: Bt%d (rev %d) at %s, ",
-               bttv_num,btv->id, btv->revision, pci_name(dev));
-        printk("irq: %d, latency: %d, mmio: 0x%lx\n",
+       pci_read_config_byte(dev, PCI_CLASS_REVISION, &btv->revision);
+       pci_read_config_byte(dev, PCI_LATENCY_TIMER, &lat);
+       printk(KERN_INFO "bttv%d: Bt%d (rev %d) at %s, ",
+              bttv_num,btv->id, btv->revision, pci_name(dev));
+       printk("irq: %d, latency: %d, mmio: 0x%lx\n",
               btv->c.pci->irq, lat, pci_resource_start(dev,0));
        schedule();
 
@@ -3935,23 +3952,23 @@ static int __devinit bttv_probe(struct pci_dev *dev,
                goto fail1;
        }
 
-        /* identify card */
+       /* identify card */
        bttv_idcard(btv);
 
-        /* disable irqs, register irq handler */
+       /* disable irqs, register irq handler */
        btwrite(0, BT848_INT_MASK);
-        result = request_irq(btv->c.pci->irq, bttv_irq,
-                             SA_SHIRQ | SA_INTERRUPT,btv->c.name,(void *)btv);
-        if (result < 0) {
-                printk(KERN_ERR "bttv%d: can't get IRQ %d\n",
+       result = request_irq(btv->c.pci->irq, bttv_irq,
+                            SA_SHIRQ | SA_INTERRUPT,btv->c.name,(void *)btv);
+       if (result < 0) {
+               printk(KERN_ERR "bttv%d: can't get IRQ %d\n",
                       bttv_num,btv->c.pci->irq);
                goto fail1;
-        }
+       }
 
        if (0 != bttv_handle_chipset(btv)) {
                result = -EIO;
                goto fail2;
-        }
+       }
 
        /* init options from insmod args */
        btv->opt_combfilter = combfilter;
@@ -3977,29 +3994,29 @@ static int __devinit bttv_probe(struct pci_dev *dev,
        btv->input = 0;
 
        /* initialize hardware */
-        if (bttv_gpio)
-                bttv_gpio_tracking(btv,"pre-init");
+       if (bttv_gpio)
+               bttv_gpio_tracking(btv,"pre-init");
 
        bttv_risc_init_main(btv);
        init_bt848(btv);
 
        /* gpio */
-        btwrite(0x00, BT848_GPIO_REG_INP);
-        btwrite(0x00, BT848_GPIO_OUT_EN);
-        if (bttv_verbose)
-                bttv_gpio_tracking(btv,"init");
+       btwrite(0x00, BT848_GPIO_REG_INP);
+       btwrite(0x00, BT848_GPIO_OUT_EN);
+       if (bttv_verbose)
+               bttv_gpio_tracking(btv,"init");
 
-        /* needs to be done before i2c is registered */
-        bttv_init_card1(btv);
+       /* needs to be done before i2c is registered */
+       bttv_init_card1(btv);
 
-        /* register i2c + gpio */
-        init_bttv_i2c(btv);
+       /* register i2c + gpio */
+       init_bttv_i2c(btv);
 
-        /* some card-specific stuff (needs working i2c) */
-        bttv_init_card2(btv);
+       /* some card-specific stuff (needs working i2c) */
+       bttv_init_card2(btv);
        init_irqreg(btv);
 
-        /* register video4linux + input */
+       /* register video4linux + input */
        if (!bttv_tvcards[btv->c.type].no_video) {
                bttv_register_video(btv);
                bt848_bright(btv,32768);
@@ -4018,10 +4035,10 @@ static int __devinit bttv_probe(struct pci_dev *dev,
 
        /* everything is fine */
        bttv_num++;
-        return 0;
+       return 0;
 
  fail2:
-        free_irq(btv->c.pci->irq,btv);
+       free_irq(btv->c.pci->irq,btv);
 
  fail1:
        if (btv->bt848_mmio)
@@ -4034,12 +4051,12 @@ static int __devinit bttv_probe(struct pci_dev *dev,
 
 static void __devexit bttv_remove(struct pci_dev *pci_dev)
 {
-        struct bttv *btv = pci_get_drvdata(pci_dev);
+       struct bttv *btv = pci_get_drvdata(pci_dev);
 
        if (bttv_verbose)
                printk("bttv%d: unloading\n",btv->c.nr);
 
-        /* shutdown everything (DMA+IRQs) */
+       /* shutdown everything (DMA+IRQs) */
        btand(~15, BT848_GPIO_DMA_CTL);
        btwrite(0, BT848_INT_MASK);
        btwrite(~0x0, BT848_INT_STAT);
@@ -4052,7 +4069,7 @@ static void __devexit bttv_remove(struct pci_dev *pci_dev)
        wake_up(&btv->gpioq);
        bttv_sub_del_devices(&btv->c);
 
-        /* unregister i2c_bus + input */
+       /* unregister i2c_bus + input */
        fini_bttv_i2c(btv);
 
        /* unregister video4linux */
@@ -4062,18 +4079,18 @@ static void __devexit bttv_remove(struct pci_dev *pci_dev)
        btcx_riscmem_free(btv->c.pci,&btv->main);
 
        /* free ressources */
-        free_irq(btv->c.pci->irq,btv);
+       free_irq(btv->c.pci->irq,btv);
        iounmap(btv->bt848_mmio);
-        release_mem_region(pci_resource_start(btv->c.pci,0),
-                           pci_resource_len(btv->c.pci,0));
+       release_mem_region(pci_resource_start(btv->c.pci,0),
+                          pci_resource_len(btv->c.pci,0));
 
        pci_set_drvdata(pci_dev, NULL);
-        return;
+       return;
 }
 
 static int bttv_suspend(struct pci_dev *pci_dev, pm_message_t state)
 {
-        struct bttv *btv = pci_get_drvdata(pci_dev);
+       struct bttv *btv = pci_get_drvdata(pci_dev);
        struct bttv_buffer_set idle;
        unsigned long flags;
 
@@ -4108,7 +4125,7 @@ static int bttv_suspend(struct pci_dev *pci_dev, pm_message_t state)
 
 static int bttv_resume(struct pci_dev *pci_dev)
 {
-        struct bttv *btv = pci_get_drvdata(pci_dev);
+       struct bttv *btv = pci_get_drvdata(pci_dev);
        unsigned long flags;
        int err;
 
@@ -4153,24 +4170,24 @@ static int bttv_resume(struct pci_dev *pci_dev)
 }
 
 static struct pci_device_id bttv_pci_tbl[] = {
-        {PCI_VENDOR_ID_BROOKTREE, PCI_DEVICE_ID_BT848,
-         PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+       {PCI_VENDOR_ID_BROOKTREE, PCI_DEVICE_ID_BT848,
+        PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
        {PCI_VENDOR_ID_BROOKTREE, PCI_DEVICE_ID_BT849,
-         PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+        PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
        {PCI_VENDOR_ID_BROOKTREE, PCI_DEVICE_ID_BT878,
-         PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+        PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
        {PCI_VENDOR_ID_BROOKTREE, PCI_DEVICE_ID_BT879,
-         PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
-        {0,}
+        PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+       {0,}
 };
 
 MODULE_DEVICE_TABLE(pci, bttv_pci_tbl);
 
 static struct pci_driver bttv_pci_driver = {
-        .name     = "bttv",
-        .id_table = bttv_pci_tbl,
-        .probe    = bttv_probe,
-        .remove   = __devexit_p(bttv_remove),
+       .name     = "bttv",
+       .id_table = bttv_pci_tbl,
+       .probe    = bttv_probe,
+       .remove   = __devexit_p(bttv_remove),
        .suspend  = bttv_suspend,
        .resume   = bttv_resume,
 };
index 6b280c03e398dc7fa5d4db3607847e4cf5db3acd..575ce8b8e714d995a92c2f6f0daa53c09e6b2dac 100644 (file)
@@ -7,7 +7,7 @@
 
 
     Copyright (C) 1996,97,98 Ralph  Metzler (rjkm@thp.uni-koeln.de)
-                           & Marcus Metzler (mocm@thp.uni-koeln.de)
+                          & Marcus Metzler (mocm@thp.uni-koeln.de)
     (c) 1999-2003 Gerd Knorr <kraxel@bytesex.org>
 
     This program is free software; you can redistribute it and/or modify
index e684df37eb0e249c982b8255ffeb84c814c000d0..77619eb131f61e600e3164f317702c3406c1c3e5 100644 (file)
@@ -5,7 +5,7 @@
     bttv - Bt848 frame grabber driver
 
     Copyright (C) 1996,97,98 Ralph  Metzler (rjkm@thp.uni-koeln.de)
-                           & Marcus Metzler (mocm@thp.uni-koeln.de)
+                          & Marcus Metzler (mocm@thp.uni-koeln.de)
     (c) 1999-2003 Gerd Knorr <kraxel@bytesex.org>
 
     This program is free software; you can redistribute it and/or modify
@@ -237,7 +237,7 @@ bttv_i2c_readbytes(struct bttv *btv, const struct i2c_msg *msg, int last)
  err:
        if (i2c_debug)
                printk(" ERR: %d\n",retval);
-               return retval;
+       return retval;
 }
 
 static int bttv_i2c_xfer(struct i2c_adapter *i2c_adap, struct i2c_msg *msgs, int num)
@@ -290,7 +290,13 @@ static struct i2c_adapter bttv_i2c_adap_hw_template = {
 
 static int attach_inform(struct i2c_client *client)
 {
-        struct bttv *btv = i2c_get_adapdata(client->adapter);
+       struct bttv *btv = i2c_get_adapdata(client->adapter);
+       int addr=ADDR_UNSET;
+
+
+       if (ADDR_UNSET != bttv_tvcards[btv->c.type].tuner_addr)
+               addr = bttv_tvcards[btv->c.type].tuner_addr;
+
 
        if (bttv_debug)
                printk(KERN_DEBUG "bttv%d: %s i2c attach [addr=0x%x,client=%s]\n",
@@ -300,19 +306,20 @@ static int attach_inform(struct i2c_client *client)
                return 0;
 
        if (btv->tuner_type != UNSET) {
-               struct tuner_setup tun_setup;
+               struct tuner_setup tun_setup;
+
+               if ((addr==ADDR_UNSET) ||
+                               (addr==client->addr)) {
 
-               tun_setup.mode_mask = T_RADIO | T_ANALOG_TV | T_DIGITAL_TV;
-               tun_setup.type = btv->tuner_type;
-               tun_setup.addr = ADDR_UNSET;
+                       tun_setup.mode_mask = T_ANALOG_TV | T_DIGITAL_TV | T_RADIO;
+                       tun_setup.type = btv->tuner_type;
+                       tun_setup.addr = addr;
+                       bttv_call_i2c_clients(btv, TUNER_SET_TYPE_ADDR, &tun_setup);
+               }
 
-               client->driver->command (client, TUNER_SET_TYPE_ADDR, &tun_setup);
        }
 
-       if (btv->pinnacle_id != UNSET)
-               client->driver->command(client,AUDC_CONFIG_PINNACLE,
-                                     &btv->pinnacle_id);
-        return 0;
+       return 0;
 }
 
 void bttv_call_i2c_clients(struct bttv *btv, unsigned int cmd, void *arg)
@@ -330,43 +337,43 @@ static struct i2c_client bttv_i2c_client_template = {
 /* read I2C */
 int bttv_I2CRead(struct bttv *btv, unsigned char addr, char *probe_for)
 {
-        unsigned char buffer = 0;
+       unsigned char buffer = 0;
 
        if (0 != btv->i2c_rc)
                return -1;
        if (bttv_verbose && NULL != probe_for)
                printk(KERN_INFO "bttv%d: i2c: checking for %s @ 0x%02x... ",
                       btv->c.nr,probe_for,addr);
-        btv->i2c_client.addr = addr >> 1;
-        if (1 != i2c_master_recv(&btv->i2c_client, &buffer, 1)) {
+       btv->i2c_client.addr = addr >> 1;
+       if (1 != i2c_master_recv(&btv->i2c_client, &buffer, 1)) {
                if (NULL != probe_for) {
                        if (bttv_verbose)
                                printk("not found\n");
                } else
                        printk(KERN_WARNING "bttv%d: i2c read 0x%x: error\n",
                               btv->c.nr,addr);
-                return -1;
+               return -1;
        }
        if (bttv_verbose && NULL != probe_for)
                printk("found\n");
-        return buffer;
+       return buffer;
 }
 
 /* write I2C */
 int bttv_I2CWrite(struct bttv *btv, unsigned char addr, unsigned char b1,
-                    unsigned char b2, int both)
+                   unsigned char b2, int both)
 {
-        unsigned char buffer[2];
-        int bytes = both ? 2 : 1;
+       unsigned char buffer[2];
+       int bytes = both ? 2 : 1;
 
        if (0 != btv->i2c_rc)
                return -1;
-        btv->i2c_client.addr = addr >> 1;
-        buffer[0] = b1;
-        buffer[1] = b2;
-        if (bytes != i2c_master_send(&btv->i2c_client, buffer, bytes))
+       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;
+       return 0;
 }
 
 /* read EEPROM content */
@@ -431,8 +438,8 @@ int __devinit init_bttv_i2c(struct bttv *btv)
                 "bt%d #%d [%s]", btv->id, btv->c.nr,
                 btv->use_i2c_hw ? "hw" : "sw");
 
-        i2c_set_adapdata(&btv->c.i2c_adap, btv);
-        btv->i2c_client.adapter = &btv->c.i2c_adap;
+       i2c_set_adapdata(&btv->c.i2c_adap, btv);
+       btv->i2c_client.adapter = &btv->c.i2c_adap;
 
 #ifdef I2C_CLASS_TV_ANALOG
        if (bttv_tvcards[btv->c.type].no_video)
index e8aada772b89b55d71411eb286648d306d6fdf41..19b564ab0e92e61fd4b4e5515abaebd02fb924a2 100644 (file)
@@ -1,13 +1,13 @@
 /*
 
     bttv-if.c  --  old gpio interface to other kernel modules
-                   don't use in new code, will go away in 2.7
+                  don't use in new code, will go away in 2.7
                   have a look at bttv-gpio.c instead.
 
     bttv - Bt848 frame grabber driver
 
     Copyright (C) 1996,97,98 Ralph  Metzler (rjkm@thp.uni-koeln.de)
-                           & Marcus Metzler (mocm@thp.uni-koeln.de)
+                          & Marcus Metzler (mocm@thp.uni-koeln.de)
     (c) 1999-2003 Gerd Knorr <kraxel@bytesex.org>
 
     This program is free software; you can redistribute it and/or modify
index a5ed99b8944519a676057cad38dc22ee1507d48b..b40e9734bf0885d83724b29b4b5d7683964fe01f 100644 (file)
@@ -74,27 +74,27 @@ bttv_risc_packed(struct bttv *btv, struct btcx_riscmem *risc,
                }
                if (bpl <= sg_dma_len(sg)-offset) {
                        /* fits into current chunk */
-                        *(rp++)=cpu_to_le32(BT848_RISC_WRITE|BT848_RISC_SOL|
+                       *(rp++)=cpu_to_le32(BT848_RISC_WRITE|BT848_RISC_SOL|
                                            BT848_RISC_EOL|bpl);
-                        *(rp++)=cpu_to_le32(sg_dma_address(sg)+offset);
-                        offset+=bpl;
+                       *(rp++)=cpu_to_le32(sg_dma_address(sg)+offset);
+                       offset+=bpl;
                } else {
                        /* scanline needs to be splitted */
-                        todo = bpl;
-                        *(rp++)=cpu_to_le32(BT848_RISC_WRITE|BT848_RISC_SOL|
+                       todo = bpl;
+                       *(rp++)=cpu_to_le32(BT848_RISC_WRITE|BT848_RISC_SOL|
                                            (sg_dma_len(sg)-offset));
-                        *(rp++)=cpu_to_le32(sg_dma_address(sg)+offset);
-                        todo -= (sg_dma_len(sg)-offset);
-                        offset = 0;
-                        sg++;
-                        while (todo > sg_dma_len(sg)) {
-                                *(rp++)=cpu_to_le32(BT848_RISC_WRITE|
+                       *(rp++)=cpu_to_le32(sg_dma_address(sg)+offset);
+                       todo -= (sg_dma_len(sg)-offset);
+                       offset = 0;
+                       sg++;
+                       while (todo > sg_dma_len(sg)) {
+                               *(rp++)=cpu_to_le32(BT848_RISC_WRITE|
                                                    sg_dma_len(sg));
-                                *(rp++)=cpu_to_le32(sg_dma_address(sg));
+                               *(rp++)=cpu_to_le32(sg_dma_address(sg));
                                todo -= sg_dma_len(sg);
                                sg++;
                        }
-                        *(rp++)=cpu_to_le32(BT848_RISC_WRITE|BT848_RISC_EOL|
+                       *(rp++)=cpu_to_le32(BT848_RISC_WRITE|BT848_RISC_EOL|
                                            todo);
                        *(rp++)=cpu_to_le32(sg_dma_address(sg));
                        offset += todo;
@@ -201,8 +201,8 @@ bttv_risc_planar(struct bttv *btv, struct btcx_riscmem *risc,
                                ri |= BT848_RISC_EOL;
 
                        /* write risc instruction */
-                        *(rp++)=cpu_to_le32(ri | ylen);
-                        *(rp++)=cpu_to_le32(((ylen >> hshift) << 16) |
+                       *(rp++)=cpu_to_le32(ri | ylen);
+                       *(rp++)=cpu_to_le32(((ylen >> hshift) << 16) |
                                            (ylen >> hshift));
                        *(rp++)=cpu_to_le32(sg_dma_address(ysg)+yoffset);
                        yoffset += ylen;
@@ -319,7 +319,7 @@ bttv_calc_geo(struct bttv *btv, struct bttv_geometry *geo,
              int width, int height, int interleaved, int norm)
 {
        const struct bttv_tvnorm *tvnorm = &bttv_tvnorms[norm];
-        u32 xsf, sr;
+       u32 xsf, sr;
        int vdelay;
 
        int swidth       = tvnorm->swidth;
@@ -334,52 +334,52 @@ bttv_calc_geo(struct bttv *btv, struct bttv_geometry *geo,
 
        vdelay = tvnorm->vdelay;
 
-        xsf = (width*scaledtwidth)/swidth;
-        geo->hscale =  ((totalwidth*4096UL)/xsf-4096);
-        geo->hdelay =  tvnorm->hdelayx1;
-        geo->hdelay =  (geo->hdelay*width)/swidth;
-        geo->hdelay &= 0x3fe;
-        sr = ((tvnorm->sheight >> (interleaved?0:1))*512)/height - 512;
-        geo->vscale =  (0x10000UL-sr) & 0x1fff;
-        geo->crop   =  ((width>>8)&0x03) | ((geo->hdelay>>6)&0x0c) |
-                ((tvnorm->sheight>>4)&0x30) | ((vdelay>>2)&0xc0);
-        geo->vscale |= interleaved ? (BT848_VSCALE_INT<<8) : 0;
-        geo->vdelay  =  vdelay;
-        geo->width   =  width;
-        geo->sheight =  tvnorm->sheight;
+       xsf = (width*scaledtwidth)/swidth;
+       geo->hscale =  ((totalwidth*4096UL)/xsf-4096);
+       geo->hdelay =  tvnorm->hdelayx1;
+       geo->hdelay =  (geo->hdelay*width)/swidth;
+       geo->hdelay &= 0x3fe;
+       sr = ((tvnorm->sheight >> (interleaved?0:1))*512)/height - 512;
+       geo->vscale =  (0x10000UL-sr) & 0x1fff;
+       geo->crop   =  ((width>>8)&0x03) | ((geo->hdelay>>6)&0x0c) |
+               ((tvnorm->sheight>>4)&0x30) | ((vdelay>>2)&0xc0);
+       geo->vscale |= interleaved ? (BT848_VSCALE_INT<<8) : 0;
+       geo->vdelay  =  vdelay;
+       geo->width   =  width;
+       geo->sheight =  tvnorm->sheight;
        geo->vtotal  =  tvnorm->vtotal;
 
-        if (btv->opt_combfilter) {
-                geo->vtc  = (width < 193) ? 2 : ((width < 385) ? 1 : 0);
-                geo->comb = (width < 769) ? 1 : 0;
-        } else {
-                geo->vtc  = 0;
-                geo->comb = 0;
-        }
+       if (btv->opt_combfilter) {
+               geo->vtc  = (width < 193) ? 2 : ((width < 385) ? 1 : 0);
+               geo->comb = (width < 769) ? 1 : 0;
+       } else {
+               geo->vtc  = 0;
+               geo->comb = 0;
+       }
 }
 
 static void
 bttv_apply_geo(struct bttv *btv, struct bttv_geometry *geo, int odd)
 {
-        int off = odd ? 0x80 : 0x00;
+       int off = odd ? 0x80 : 0x00;
 
        if (geo->comb)
                btor(BT848_VSCALE_COMB, BT848_E_VSCALE_HI+off);
        else
                btand(~BT848_VSCALE_COMB, BT848_E_VSCALE_HI+off);
 
-        btwrite(geo->vtc,             BT848_E_VTC+off);
-        btwrite(geo->hscale >> 8,     BT848_E_HSCALE_HI+off);
-        btwrite(geo->hscale & 0xff,   BT848_E_HSCALE_LO+off);
-        btaor((geo->vscale>>8), 0xe0, BT848_E_VSCALE_HI+off);
-        btwrite(geo->vscale & 0xff,   BT848_E_VSCALE_LO+off);
-        btwrite(geo->width & 0xff,    BT848_E_HACTIVE_LO+off);
-        btwrite(geo->hdelay & 0xff,   BT848_E_HDELAY_LO+off);
-        btwrite(geo->sheight & 0xff,  BT848_E_VACTIVE_LO+off);
-        btwrite(geo->vdelay & 0xff,   BT848_E_VDELAY_LO+off);
-        btwrite(geo->crop,            BT848_E_CROP+off);
+       btwrite(geo->vtc,             BT848_E_VTC+off);
+       btwrite(geo->hscale >> 8,     BT848_E_HSCALE_HI+off);
+       btwrite(geo->hscale & 0xff,   BT848_E_HSCALE_LO+off);
+       btaor((geo->vscale>>8), 0xe0, BT848_E_VSCALE_HI+off);
+       btwrite(geo->vscale & 0xff,   BT848_E_VSCALE_LO+off);
+       btwrite(geo->width & 0xff,    BT848_E_HACTIVE_LO+off);
+       btwrite(geo->hdelay & 0xff,   BT848_E_HDELAY_LO+off);
+       btwrite(geo->sheight & 0xff,  BT848_E_VACTIVE_LO+off);
+       btwrite(geo->vdelay & 0xff,   BT848_E_VDELAY_LO+off);
+       btwrite(geo->crop,            BT848_E_CROP+off);
        btwrite(geo->vtotal>>8,       BT848_VTOTAL_HI);
-        btwrite(geo->vtotal & 0xff,   BT848_VTOTAL_LO);
+       btwrite(geo->vtotal & 0xff,   BT848_VTOTAL_LO);
 }
 
 /* ---------------------------------------------------------- */
@@ -420,7 +420,7 @@ bttv_set_dma(struct bttv *btv, int override)
        } else {
                del_timer(&btv->timeout);
        }
-        btv->main.cpu[RISC_SLOT_LOOP] = cpu_to_le32(cmd);
+       btv->main.cpu[RISC_SLOT_LOOP] = cpu_to_le32(cmd);
 
        btaor(capctl, ~0x0f, BT848_CAP_CTL);
        if (capctl) {
@@ -432,7 +432,7 @@ bttv_set_dma(struct bttv *btv, int override)
        } else {
                if (!btv->dma_on)
                        return;
-                btand(~3, BT848_GPIO_DMA_CTL);
+               btand(~3, BT848_GPIO_DMA_CTL);
                btv->dma_on = 0;
        }
        return;
@@ -460,19 +460,19 @@ bttv_risc_init_main(struct bttv *btv)
        btv->main.cpu[6] = cpu_to_le32(BT848_RISC_JUMP);
        btv->main.cpu[7] = cpu_to_le32(btv->main.dma + (8<<2));
 
-        btv->main.cpu[8] = cpu_to_le32(BT848_RISC_SYNC | BT848_RISC_RESYNC |
+       btv->main.cpu[8] = cpu_to_le32(BT848_RISC_SYNC | BT848_RISC_RESYNC |
                                       BT848_FIFO_STATUS_VRO);
-        btv->main.cpu[9] = cpu_to_le32(0);
+       btv->main.cpu[9] = cpu_to_le32(0);
 
        /* bottom field */
-        btv->main.cpu[10] = cpu_to_le32(BT848_RISC_JUMP);
+       btv->main.cpu[10] = cpu_to_le32(BT848_RISC_JUMP);
        btv->main.cpu[11] = cpu_to_le32(btv->main.dma + (12<<2));
-        btv->main.cpu[12] = cpu_to_le32(BT848_RISC_JUMP);
+       btv->main.cpu[12] = cpu_to_le32(BT848_RISC_JUMP);
        btv->main.cpu[13] = cpu_to_le32(btv->main.dma + (14<<2));
 
        /* jump back to top field */
        btv->main.cpu[14] = cpu_to_le32(BT848_RISC_JUMP);
-        btv->main.cpu[15] = cpu_to_le32(btv->main.dma + (0<<2));
+       btv->main.cpu[15] = cpu_to_le32(btv->main.dma + (0<<2));
 
        return 0;
 }
index d254e90e3bb9fe8718a58bb8b080860b2f2b66e2..124ea41dada4d204d7705b584e0c159166ed31f5 100644 (file)
 /* ---------------------------------------------------------- */
 /* exported by bttv-cards.c                                   */
 
-#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_ADSTECH_TV    0x0c
-#define BTTV_AVERMEDIA98   0x0d
-#define BTTV_VHX           0x0e
-#define BTTV_ZOLTRIX       0x0f
-#define BTTV_PIXVIEWPLAYTV 0x10
-#define BTTV_WINVIEW_601   0x11
-#define BTTV_AVEC_INTERCAP 0x12
-#define BTTV_LIFE_FLYKIT   0x13
-#define BTTV_CEI_RAFFLES   0x14
-#define BTTV_CONFERENCETV  0x15
-#define BTTV_PHOEBE_TVMAS  0x16
-#define BTTV_MODTEC_205    0x17
-#define BTTV_MAGICTVIEW061 0x18
-#define BTTV_VOBIS_BOOSTAR 0x19
-#define BTTV_HAUPPAUG_WCAM 0x1a
-#define BTTV_MAXI          0x1b
-#define BTTV_TERRATV       0x1c
-#define BTTV_PXC200        0x1d
-#define BTTV_FLYVIDEO_98   0x1e
-#define BTTV_IPROTV        0x1f
-#define BTTV_INTEL_C_S_PCI 0x20
-#define BTTV_TERRATVALUE   0x21
-#define BTTV_WINFAST2000   0x22
-#define BTTV_CHRONOS_VS2   0x23
-#define BTTV_TYPHOON_TVIEW 0x24
-#define BTTV_PXELVWPLTVPRO 0x25
-#define BTTV_MAGICTVIEW063 0x26
-#define BTTV_PINNACLE      0x27
-#define BTTV_STB2          0x28
-#define BTTV_AVPHONE98     0x29
-#define BTTV_PV951         0x2a
-#define BTTV_ONAIR_TV      0x2b
-#define BTTV_SIGMA_TVII_FM 0x2c
-#define BTTV_MATRIX_VISION2 0x2d
-#define BTTV_ZOLTRIX_GENIE 0x2e
-#define BTTV_TERRATVRADIO  0x2f
-#define BTTV_DYNALINK      0x30
-#define BTTV_GVBCTV3PCI    0x31
-#define BTTV_PXELVWPLTVPAK 0x32
-#define BTTV_EAGLE         0x33
-#define BTTV_PINNACLEPRO   0x34
-#define BTTV_TVIEW_RDS_FM  0x35
-#define BTTV_LIFETEC_9415  0x36
-#define BTTV_BESTBUY_EASYTV 0x37
-#define BTTV_FLYVIDEO_98FM 0x38
-#define BTTV_GMV1          0x3d
-#define BTTV_BESTBUY_EASYTV2 0x3e
-#define BTTV_ATI_TVWONDER  0x3f
-#define BTTV_ATI_TVWONDERVE 0x40
-#define BTTV_FLYVIDEO2000   0x41
-#define BTTV_TERRATVALUER   0x42
-#define BTTV_GVBCTV4PCI     0x43
-#define BTTV_VOODOOTV_FM    0x44
-#define BTTV_AIMMS          0x45
-#define BTTV_PV_BT878P_PLUS 0x46
-#define BTTV_FLYVIDEO98EZ   0x47
-#define BTTV_PV_BT878P_9B   0x48
-#define BTTV_SENSORAY311    0x49
-#define BTTV_RV605          0x4a
-#define BTTV_WINDVR         0x4c
-#define BTTV_GRANDTEC       0x4d
-#define BTTV_KWORLD         0x4e
-#define BTTV_HAUPPAUGEPVR   0x50
-#define BTTV_GVBCTV5PCI     0x51
-#define BTTV_OSPREY1x0      0x52
-#define BTTV_OSPREY1x0_848  0x53
-#define BTTV_OSPREY101_848  0x54
-#define BTTV_OSPREY1x1      0x55
-#define BTTV_OSPREY1x1_SVID 0x56
-#define BTTV_OSPREY2xx      0x57
-#define BTTV_OSPREY2x0_SVID 0x58
-#define BTTV_OSPREY2x0      0x59
-#define BTTV_OSPREY500      0x5a
-#define BTTV_OSPREY540      0x5b
-#define BTTV_OSPREY2000     0x5c
-#define BTTV_IDS_EAGLE      0x5d
-#define BTTV_PINNACLESAT    0x5e
-#define BTTV_FORMAC_PROTV   0x5f
-#define BTTV_EURESYS_PICOLO 0x61
-#define BTTV_PV150          0x62
-#define BTTV_AD_TVK503      0x63
-#define BTTV_IVC200         0x66
-#define BTTV_XGUARD         0x67
-#define BTTV_NEBULA_DIGITV  0x68
-#define BTTV_PV143          0x69
-#define BTTV_IVC100         0x6e
-#define BTTV_IVC120         0x6f
-#define BTTV_PC_HDTV        0x70
-#define BTTV_TWINHAN_DST    0x71
-#define BTTV_WINFASTVC100   0x72
-#define BTTV_SIMUS_GVC1100  0x74
-#define BTTV_NGSTV_PLUS     0x75
-#define BTTV_LMLBT4         0x76
-#define BTTV_PICOLO_TETRA_CHIP 0x79
-#define BTTV_AVDVBT_771     0x7b
-#define BTTV_AVDVBT_761     0x7c
-#define BTTV_MATRIX_VISIONSQ  0x7d
-#define BTTV_MATRIX_VISIONSLC 0x7e
-#define BTTV_APAC_VIEWCOMP  0x7f
-#define BTTV_DVICO_DVBT_LITE  0x80
-#define BTTV_TIBET_CS16  0x83
-#define BTTV_KODICOM_4400R  0x84
-#define BTTV_ADLINK_RTV24   0x86
-#define BTTV_DVICO_FUSIONHDTV_5_LITE 0x87
-#define BTTV_ACORP_Y878F   0x88
+#define BTTV_BOARD_UNKNOWN                 0x00
+#define BTTV_BOARD_MIRO                    0x01
+#define BTTV_BOARD_HAUPPAUGE               0x02
+#define BTTV_BOARD_STB                     0x03
+#define BTTV_BOARD_INTEL                   0x04
+#define BTTV_BOARD_DIAMOND                 0x05
+#define BTTV_BOARD_AVERMEDIA               0x06
+#define BTTV_BOARD_MATRIX_VISION           0x07
+#define BTTV_BOARD_FLYVIDEO                0x08
+#define BTTV_BOARD_TURBOTV                 0x09
+#define BTTV_BOARD_HAUPPAUGE878            0x0a
+#define BTTV_BOARD_MIROPRO                 0x0b
+#define BTTV_BOARD_ADSTECH_TV              0x0c
+#define BTTV_BOARD_AVERMEDIA98             0x0d
+#define BTTV_BOARD_VHX                     0x0e
+#define BTTV_BOARD_ZOLTRIX                 0x0f
+#define BTTV_BOARD_PIXVIEWPLAYTV           0x10
+#define BTTV_BOARD_WINVIEW_601             0x11
+#define BTTV_BOARD_AVEC_INTERCAP           0x12
+#define BTTV_BOARD_LIFE_FLYKIT             0x13
+#define BTTV_BOARD_CEI_RAFFLES             0x14
+#define BTTV_BOARD_CONFERENCETV            0x15
+#define BTTV_BOARD_PHOEBE_TVMAS            0x16
+#define BTTV_BOARD_MODTEC_205              0x17
+#define BTTV_BOARD_MAGICTVIEW061           0x18
+#define BTTV_BOARD_VOBIS_BOOSTAR           0x19
+#define BTTV_BOARD_HAUPPAUG_WCAM           0x1a
+#define BTTV_BOARD_MAXI                    0x1b
+#define BTTV_BOARD_TERRATV                 0x1c
+#define BTTV_BOARD_PXC200                  0x1d
+#define BTTV_BOARD_FLYVIDEO_98             0x1e
+#define BTTV_BOARD_IPROTV                  0x1f
+#define BTTV_BOARD_INTEL_C_S_PCI           0x20
+#define BTTV_BOARD_TERRATVALUE             0x21
+#define BTTV_BOARD_WINFAST2000             0x22
+#define BTTV_BOARD_CHRONOS_VS2             0x23
+#define BTTV_BOARD_TYPHOON_TVIEW           0x24
+#define BTTV_BOARD_PXELVWPLTVPRO           0x25
+#define BTTV_BOARD_MAGICTVIEW063           0x26
+#define BTTV_BOARD_PINNACLE                0x27
+#define BTTV_BOARD_STB2                    0x28
+#define BTTV_BOARD_AVPHONE98               0x29
+#define BTTV_BOARD_PV951                   0x2a
+#define BTTV_BOARD_ONAIR_TV                0x2b
+#define BTTV_BOARD_SIGMA_TVII_FM           0x2c
+#define BTTV_BOARD_MATRIX_VISION2          0x2d
+#define BTTV_BOARD_ZOLTRIX_GENIE           0x2e
+#define BTTV_BOARD_TERRATVRADIO            0x2f
+#define BTTV_BOARD_DYNALINK                0x30
+#define BTTV_BOARD_GVBCTV3PCI              0x31
+#define BTTV_BOARD_PXELVWPLTVPAK           0x32
+#define BTTV_BOARD_EAGLE                   0x33
+#define BTTV_BOARD_PINNACLEPRO             0x34
+#define BTTV_BOARD_TVIEW_RDS_FM            0x35
+#define BTTV_BOARD_LIFETEC_9415            0x36
+#define BTTV_BOARD_BESTBUY_EASYTV          0x37
+#define BTTV_BOARD_FLYVIDEO_98FM           0x38
+#define BTTV_BOARD_GRANDTEC                0x39
+#define BTTV_BOARD_ASKEY_CPH060            0x3a
+#define BTTV_BOARD_ASKEY_CPH03X            0x3b
+#define BTTV_BOARD_MM100PCTV               0x3c
+#define BTTV_BOARD_GMV1                    0x3d
+#define BTTV_BOARD_BESTBUY_EASYTV2         0x3e
+#define BTTV_BOARD_ATI_TVWONDER            0x3f
+#define BTTV_BOARD_ATI_TVWONDERVE          0x40
+#define BTTV_BOARD_FLYVIDEO2000            0x41
+#define BTTV_BOARD_TERRATVALUER            0x42
+#define BTTV_BOARD_GVBCTV4PCI              0x43
+#define BTTV_BOARD_VOODOOTV_FM             0x44
+#define BTTV_BOARD_AIMMS                   0x45
+#define BTTV_BOARD_PV_BT878P_PLUS          0x46
+#define BTTV_BOARD_FLYVIDEO98EZ            0x47
+#define BTTV_BOARD_PV_BT878P_9B            0x48
+#define BTTV_BOARD_SENSORAY311             0x49
+#define BTTV_BOARD_RV605                   0x4a
+#define BTTV_BOARD_POWERCLR_MTV878         0x4b
+#define BTTV_BOARD_WINDVR                  0x4c
+#define BTTV_BOARD_GRANDTEC_MULTI          0x4d
+#define BTTV_BOARD_KWORLD                  0x4e
+#define BTTV_BOARD_DSP_TCVIDEO             0x4f
+#define BTTV_BOARD_HAUPPAUGEPVR            0x50
+#define BTTV_BOARD_GVBCTV5PCI              0x51
+#define BTTV_BOARD_OSPREY1x0               0x52
+#define BTTV_BOARD_OSPREY1x0_848           0x53
+#define BTTV_BOARD_OSPREY101_848           0x54
+#define BTTV_BOARD_OSPREY1x1               0x55
+#define BTTV_BOARD_OSPREY1x1_SVID          0x56
+#define BTTV_BOARD_OSPREY2xx               0x57
+#define BTTV_BOARD_OSPREY2x0_SVID          0x58
+#define BTTV_BOARD_OSPREY2x0               0x59
+#define BTTV_BOARD_OSPREY500               0x5a
+#define BTTV_BOARD_OSPREY540               0x5b
+#define BTTV_BOARD_OSPREY2000              0x5c
+#define BTTV_BOARD_IDS_EAGLE               0x5d
+#define BTTV_BOARD_PINNACLESAT             0x5e
+#define BTTV_BOARD_FORMAC_PROTV            0x5f
+#define BTTV_BOARD_MACHTV                  0x60
+#define BTTV_BOARD_EURESYS_PICOLO          0x61
+#define BTTV_BOARD_PV150                   0x62
+#define BTTV_BOARD_AD_TVK503               0x63
+#define BTTV_BOARD_HERCULES_SM_TV          0x64
+#define BTTV_BOARD_PACETV                  0x65
+#define BTTV_BOARD_IVC200                  0x66
+#define BTTV_BOARD_XGUARD                  0x67
+#define BTTV_BOARD_NEBULA_DIGITV           0x68
+#define BTTV_BOARD_PV143                   0x69
+#define BTTV_BOARD_VD009X1_MINIDIN         0x6a
+#define BTTV_BOARD_VD009X1_COMBI           0x6b
+#define BTTV_BOARD_VD009_MINIDIN           0x6c
+#define BTTV_BOARD_VD009_COMBI             0x6d
+#define BTTV_BOARD_IVC100                  0x6e
+#define BTTV_BOARD_IVC120                  0x6f
+#define BTTV_BOARD_PC_HDTV                 0x70
+#define BTTV_BOARD_TWINHAN_DST             0x71
+#define BTTV_BOARD_WINFASTVC100            0x72
+#define BTTV_BOARD_TEV560                  0x73
+#define BTTV_BOARD_SIMUS_GVC1100           0x74
+#define BTTV_BOARD_NGSTV_PLUS              0x75
+#define BTTV_BOARD_LMLBT4                  0x76
+#define BTTV_BOARD_TEKRAM_M205             0x77
+#define BTTV_BOARD_CONTVFMI                0x78
+#define BTTV_BOARD_PICOLO_TETRA_CHIP       0x79
+#define BTTV_BOARD_SPIRIT_TV               0x7a
+#define BTTV_BOARD_AVDVBT_771              0x7b
+#define BTTV_BOARD_AVDVBT_761              0x7c
+#define BTTV_BOARD_MATRIX_VISIONSQ         0x7d
+#define BTTV_BOARD_MATRIX_VISIONSLC        0x7e
+#define BTTV_BOARD_APAC_VIEWCOMP           0x7f
+#define BTTV_BOARD_DVICO_DVBT_LITE         0x80
+#define BTTV_BOARD_VGEAR_MYVCD             0x81
+#define BTTV_BOARD_SUPER_TV                0x82
+#define BTTV_BOARD_TIBET_CS16              0x83
+#define BTTV_BOARD_KODICOM_4400R           0x84
+#define BTTV_BOARD_KODICOM_4400R_SL        0x85
+#define BTTV_BOARD_ADLINK_RTV24            0x86
+#define BTTV_BOARD_DVICO_FUSIONHDTV_5_LITE 0x87
+#define BTTV_BOARD_ACORP_Y878F             0x88
+#define BTTV_BOARD_CONCEPTRONIC_CTVFMI2    0x89
+#define BTTV_BOARD_PV_BT878P_2E            0x8a
+#define BTTV_BOARD_PV_M4900                0x8b
+#define BTTV_BOARD_OSPREY440               0x8c
+#define BTTV_BOARD_ASOUND_SKYEYE          0x8d
 
 /* i2c address list */
 #define I2C_TSA5522        0xc2
@@ -177,7 +202,7 @@ struct bttv_core {
        struct list_head     subs;     /* struct bttv_sub_device */
 
        /* device config */
-        unsigned int         nr;       /* dev nr (for printk("bttv%d: ...");  */
+       unsigned int         nr;       /* dev nr (for printk("bttv%d: ...");  */
        unsigned int         type;     /* card type (pointer into tvcards[])  */
        char                 name[8];  /* dev name */
 };
@@ -186,16 +211,16 @@ struct bttv;
 
 struct tvcard
 {
-        char *name;
-        unsigned int video_inputs;
-        unsigned int audio_inputs;
-        unsigned int tuner;
-        unsigned int svhs;
+       char *name;
+       unsigned int video_inputs;
+       unsigned int audio_inputs;
+       unsigned int tuner;
+       unsigned int svhs;
        unsigned int digital_mode; // DIGITAL_MODE_CAMERA or DIGITAL_MODE_VIDEO
-        u32 gpiomask;
-        u32 muxsel[16];
-        u32 audiomux[6]; /* Tuner, Radio, external, internal, mute, stereo */
-        u32 gpiomask2;   /* GPIO MUX mask */
+       u32 gpiomask;
+       u32 muxsel[16];
+       u32 audiomux[6]; /* Tuner, Radio, external, internal, mute, stereo */
+       u32 gpiomask2;   /* GPIO MUX mask */
 
        /* i2c audio flags */
        unsigned int no_msp34xx:1;
@@ -218,6 +243,7 @@ struct tvcard
 
        unsigned int tuner_type;
        unsigned int tuner_addr;
+       unsigned int radio_addr;
 
        unsigned int has_radio;
        void (*audio_hook)(struct bttv *btv, struct video_audio *v, int set);
@@ -246,7 +272,7 @@ extern int bttv_handle_chipset(struct bttv *btv);
    interface below for new code */
 
 /* returns card type + card ID (for bt878-based ones)
-   for possible values see lines below beginning with #define BTTV_UNKNOWN
+   for possible values see lines below beginning with #define BTTV_BOARD_UNKNOWN
    returns negative value if error occurred
 */
 extern int bttv_get_cardinfo(unsigned int card, int *type,
index e0e7c7a84bc53015d1c4064d48b323aea570a691..386f546f7d116b85578db858775c868c125f0d6e 100644 (file)
 struct bttv_tvnorm {
        int   v4l2_id;
        char  *name;
-        u32   Fsc;
-        u16   swidth, sheight; /* scaled standard width, height */
+       u32   Fsc;
+       u16   swidth, sheight; /* scaled standard width, height */
        u16   totalwidth;
        u8    adelay, bdelay, iform;
        u32   scaledtwidth;
        u16   hdelayx1, hactivex1;
        u16   vdelay;
-        u8    vbipack;
+       u8    vbipack;
        u16   vtotal;
        int   sram;
 };
@@ -267,8 +267,8 @@ struct bttv {
 
        /* card configuration info */
        unsigned int cardid;   /* pci subsystem id (bt878 based ones) */
-        unsigned int tuner_type;  /* tuner chip type */
-        unsigned int pinnacle_id;
+       unsigned int tuner_type;  /* tuner chip type */
+       unsigned int pinnacle_id;
        unsigned int svhs;
        struct bttv_pll_info pll;
        int triton1;
@@ -301,9 +301,9 @@ struct bttv {
 
        /* locking */
        spinlock_t s_lock;
-        struct semaphore lock;
+       struct semaphore lock;
        int resources;
-        struct semaphore reslock;
+       struct semaphore reslock;
 #ifdef VIDIOC_G_PRIORITY
        struct v4l2_prio_state prio;
 #endif
diff --git a/drivers/media/video/cs53l32a.c b/drivers/media/video/cs53l32a.c
new file mode 100644 (file)
index 0000000..780b352
--- /dev/null
@@ -0,0 +1,240 @@
+/*
+ * cs53l32a (Adaptec AVC-2010 and AVC-2410) i2c ivtv driver.
+ * Copyright (C) 2005  Martin Vaughan
+ *
+ * Audio source switching for Adaptec AVC-2410 added by Trev Jackson
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/ioctl.h>
+#include <asm/uaccess.h>
+#include <linux/i2c.h>
+#include <linux/i2c-id.h>
+#include <linux/videodev.h>
+#include <media/audiochip.h>
+
+MODULE_DESCRIPTION("i2c device driver for cs53l32a Audio ADC");
+MODULE_AUTHOR("Martin Vaughan");
+MODULE_LICENSE("GPL");
+
+static int debug = 0;
+
+module_param(debug, bool, 0644);
+
+MODULE_PARM_DESC(debug, "Debugging messages\n\t\t\t0=Off (default), 1=On");
+
+#define cs53l32a_dbg(fmt, arg...) \
+       do { \
+               if (debug) \
+                       printk(KERN_INFO "%s debug %d-%04x: " fmt, client->driver->name, \
+                              i2c_adapter_id(client->adapter), client->addr , ## arg); \
+       } while (0)
+
+#define cs53l32a_err(fmt, arg...) do { \
+       printk(KERN_ERR "%s %d-%04x: " fmt, client->driver->name, \
+               i2c_adapter_id(client->adapter), client->addr , ## arg); } while (0)
+#define cs53l32a_info(fmt, arg...) do { \
+       printk(KERN_INFO "%s %d-%04x: " fmt, client->driver->name, \
+               i2c_adapter_id(client->adapter), client->addr , ## arg); } while (0)
+
+static unsigned short normal_i2c[] = { 0x22 >> 1, I2C_CLIENT_END };
+
+
+I2C_CLIENT_INSMOD;
+
+/* ----------------------------------------------------------------------- */
+
+static int cs53l32a_write(struct i2c_client *client, u8 reg, u8 value)
+{
+       return i2c_smbus_write_byte_data(client, reg, value);
+}
+
+static int cs53l32a_read(struct i2c_client *client, u8 reg)
+{
+       return i2c_smbus_read_byte_data(client, reg);
+}
+
+static int cs53l32a_command(struct i2c_client *client, unsigned int cmd,
+                           void *arg)
+{
+       int *input = arg;
+
+       switch (cmd) {
+       case AUDC_SET_INPUT:
+               switch (*input) {
+               case AUDIO_TUNER:
+                       cs53l32a_write(client, 0x01, 0x01);
+                       break;
+               case AUDIO_EXTERN:
+                       cs53l32a_write(client, 0x01, 0x21);
+                       break;
+               case AUDIO_MUTE:
+                       cs53l32a_write(client, 0x03, 0xF0);
+                       break;
+               case AUDIO_UNMUTE:
+                       cs53l32a_write(client, 0x03, 0x30);
+                       break;
+               default:
+                       cs53l32a_err("Invalid input %d.\n", *input);
+                       return -EINVAL;
+               }
+               break;
+
+       case VIDIOC_S_CTRL:
+               {
+                       struct v4l2_control *ctrl = arg;
+
+                       if (ctrl->id != V4L2_CID_AUDIO_VOLUME)
+                               return -EINVAL;
+                       if (ctrl->value > 12 || ctrl->value < -90)
+                               return -EINVAL;
+                       cs53l32a_write(client, 0x04, (u8) ctrl->value);
+                       cs53l32a_write(client, 0x05, (u8) ctrl->value);
+                       break;
+               }
+
+       case VIDIOC_LOG_STATUS:
+               {
+                       u8 v = cs53l32a_read(client, 0x01);
+                       u8 m = cs53l32a_read(client, 0x03);
+
+                       cs53l32a_info("Input: %s%s\n",
+                                     v == 0x21 ? "external line in" : "tuner",
+                                     (m & 0xC0) ? " (muted)" : "");
+                       break;
+               }
+
+       default:
+               return -EINVAL;
+       }
+       return 0;
+}
+
+/* ----------------------------------------------------------------------- */
+
+/* i2c implementation */
+
+/*
+ * Generic i2c probe
+ * concerning the addresses: i2c wants 7 bit (without the r/w bit), so '>>1'
+ */
+
+static struct i2c_driver i2c_driver;
+
+static int cs53l32a_attach(struct i2c_adapter *adapter, int address, int kind)
+{
+       struct i2c_client *client;
+       int i;
+
+       /* Check if the adapter supports the needed features */
+       if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA))
+               return 0;
+
+       client = kmalloc(sizeof(struct i2c_client), GFP_KERNEL);
+       if (client == 0)
+               return -ENOMEM;
+
+       memset(client, 0, sizeof(struct i2c_client));
+       client->addr = address;
+       client->adapter = adapter;
+       client->driver = &i2c_driver;
+       client->flags = I2C_CLIENT_ALLOW_USE;
+       snprintf(client->name, sizeof(client->name) - 1, "cs53l32a");
+
+       cs53l32a_info("chip found @ 0x%x (%s)\n", address << 1, adapter->name);
+
+       for (i = 1; i <= 7; i++) {
+               u8 v = cs53l32a_read(client, i);
+
+               cs53l32a_dbg("Read Reg %d %02x\n", i, v);
+       }
+
+       /* Set cs53l32a internal register for Adaptec 2010/2410 setup */
+
+       cs53l32a_write(client, 0x01, (u8) 0x21);
+       cs53l32a_write(client, 0x02, (u8) 0x29);
+       cs53l32a_write(client, 0x03, (u8) 0x30);
+       cs53l32a_write(client, 0x04, (u8) 0x00);
+       cs53l32a_write(client, 0x05, (u8) 0x00);
+       cs53l32a_write(client, 0x06, (u8) 0x00);
+       cs53l32a_write(client, 0x07, (u8) 0x00);
+
+       /* Display results, should be 0x21,0x29,0x30,0x00,0x00,0x00,0x00 */
+
+       for (i = 1; i <= 7; i++) {
+               u8 v = cs53l32a_read(client, i);
+
+               cs53l32a_dbg("Read Reg %d %02x\n", i, v);
+       }
+
+       i2c_attach_client(client);
+
+       return 0;
+}
+
+static int cs53l32a_probe(struct i2c_adapter *adapter)
+{
+#ifdef I2C_CLASS_TV_ANALOG
+       if (adapter->class & I2C_CLASS_TV_ANALOG)
+#else
+       if (adapter->id == I2C_HW_B_BT848)
+#endif
+               return i2c_probe(adapter, &addr_data, cs53l32a_attach);
+       return 0;
+}
+
+static int cs53l32a_detach(struct i2c_client *client)
+{
+       int err;
+
+       err = i2c_detach_client(client);
+       if (err) {
+               return err;
+       }
+       kfree(client);
+
+       return 0;
+}
+
+/* ----------------------------------------------------------------------- */
+
+/* i2c implementation */
+static struct i2c_driver i2c_driver = {
+       .name = "cs53l32a",
+       .id = I2C_DRIVERID_CS53L32A,
+       .flags = I2C_DF_NOTIFY,
+       .attach_adapter = cs53l32a_probe,
+       .detach_client = cs53l32a_detach,
+       .command = cs53l32a_command,
+       .owner = THIS_MODULE,
+};
+
+
+static int __init cs53l32a_init_module(void)
+{
+       return i2c_add_driver(&i2c_driver);
+}
+
+static void __exit cs53l32a_cleanup_module(void)
+{
+       i2c_del_driver(&i2c_driver);
+}
+
+module_init(cs53l32a_init_module);
+module_exit(cs53l32a_cleanup_module);
diff --git a/drivers/media/video/cx88/Kconfig b/drivers/media/video/cx88/Kconfig
new file mode 100644 (file)
index 0000000..41818b6
--- /dev/null
@@ -0,0 +1,91 @@
+config VIDEO_CX88
+       tristate "Conexant 2388x (bt878 successor) support"
+       depends on VIDEO_DEV && PCI && I2C
+       select I2C_ALGOBIT
+       select FW_LOADER
+       select VIDEO_BTCX
+       select VIDEO_BUF
+       select VIDEO_TUNER
+       select VIDEO_TVEEPROM
+       select VIDEO_IR
+       ---help---
+         This is a video4linux driver for Conexant 2388x based
+         TV cards.
+
+         To compile this driver as a module, choose M here: the
+         module will be called cx8800
+
+config VIDEO_CX88_DVB
+       tristate "DVB/ATSC Support for cx2388x based TV cards"
+       depends on VIDEO_CX88 && DVB_CORE
+       select VIDEO_BUF_DVB
+       ---help---
+         This adds support for DVB/ATSC cards based on the
+         Connexant 2388x chip.
+
+         To compile this driver as a module, choose M here: the
+         module will be called cx88-dvb.
+
+         You must also select one or more DVB/ATSC demodulators.
+         If you are unsure which you need, choose all of them.
+
+config VIDEO_CX88_DVB_ALL_FRONTENDS
+       bool "Build all supported frontends for cx2388x based TV cards"
+       default y
+       depends on VIDEO_CX88_DVB
+       select DVB_MT352
+       select DVB_OR51132
+       select DVB_CX22702
+       select DVB_LGDT330X
+       select DVB_NXT200X
+       ---help---
+         This builds cx88-dvb with all currently supported frontend
+         demodulators.  If you wish to tweak your configuration, and
+         only include support for the hardware that you need, choose N here.
+
+         If you are unsure, choose Y.
+
+config VIDEO_CX88_DVB_MT352
+       tristate "Zarlink MT352 DVB-T Support"
+       default m
+       depends on VIDEO_CX88_DVB && !VIDEO_CX88_DVB_ALL_FRONTENDS
+       select DVB_MT352
+       ---help---
+         This adds DVB-T support for cards based on the
+         Connexant 2388x chip and the MT352 demodulator.
+
+config VIDEO_CX88_DVB_OR51132
+       tristate "OR51132 ATSC Support"
+       default m
+       depends on VIDEO_CX88_DVB && !VIDEO_CX88_DVB_ALL_FRONTENDS
+       select DVB_OR51132
+       ---help---
+         This adds ATSC 8VSB and QAM64/256 support for cards based on the
+         Connexant 2388x chip and the OR51132 demodulator.
+
+config VIDEO_CX88_DVB_CX22702
+       tristate "Conexant CX22702 DVB-T Support"
+       default m
+       depends on VIDEO_CX88_DVB && !VIDEO_CX88_DVB_ALL_FRONTENDS
+       select DVB_CX22702
+       ---help---
+         This adds DVB-T support for cards based on the
+         Connexant 2388x chip and the CX22702 demodulator.
+
+config VIDEO_CX88_DVB_LGDT330X
+       tristate "LG Electronics DT3302/DT3303 ATSC Support"
+       default m
+       depends on VIDEO_CX88_DVB && !VIDEO_CX88_DVB_ALL_FRONTENDS
+       select DVB_LGDT330X
+       ---help---
+         This adds ATSC 8VSB and QAM64/256 support for cards based on the
+         Connexant 2388x chip and the LGDT3302/LGDT3303 demodulator.
+
+config VIDEO_CX88_DVB_NXT200X
+       tristate "NXT2002/NXT2004 ATSC Support"
+       default m
+       depends on VIDEO_CX88_DVB && !VIDEO_CX88_DVB_ALL_FRONTENDS
+       select DVB_NXT200X
+       ---help---
+         This adds ATSC 8VSB and QAM64/256 support for cards based on the
+         Connexant 2388x chip and the NXT2002/NXT2004 demodulator.
index 107e48645e3a1c5b442fa8f904d7c324949435d9..0df40b7734548e99fccf79454bba870868a23680 100644 (file)
@@ -9,6 +9,9 @@ obj-$(CONFIG_VIDEO_CX88_DVB) += cx88-dvb.o
 EXTRA_CFLAGS += -I$(src)/..
 EXTRA_CFLAGS += -I$(srctree)/drivers/media/dvb/dvb-core
 EXTRA_CFLAGS += -I$(srctree)/drivers/media/dvb/frontends
+ifneq ($(CONFIG_VIDEO_BUF_DVB),n)
+ EXTRA_CFLAGS += -DHAVE_VIDEO_BUF_DVB=1
+endif
 ifneq ($(CONFIG_DVB_CX22702),n)
  EXTRA_CFLAGS += -DHAVE_CX22702=1
 endif
@@ -21,3 +24,6 @@ endif
 ifneq ($(CONFIG_DVB_MT352),n)
  EXTRA_CFLAGS += -DHAVE_MT352=1
 endif
+ifneq ($(CONFIG_DVB_NXT200X),n)
+ EXTRA_CFLAGS += -DHAVE_NXT200X=1
+endif
index 0c0c59e94774911a0f27a086568b161b464058f3..4ae3f78cccf2f7fdc512eb38779e25ab003753e5 100644 (file)
@@ -38,7 +38,7 @@ MODULE_AUTHOR("Jelle Foks <jelle@foks.8m.com>");
 MODULE_AUTHOR("Gerd Knorr <kraxel@bytesex.org> [SuSE Labs]");
 MODULE_LICENSE("GPL");
 
-static unsigned int mpegbufs = 8;
+static unsigned int mpegbufs = 32;
 module_param(mpegbufs,int,0644);
 MODULE_PARM_DESC(mpegbufs,"number of mpeg buffers, range 2-32");
 
@@ -436,7 +436,7 @@ static int memory_write(struct cx88_core *core, u32 address, u32 value)
 
 static int memory_read(struct cx88_core *core, u32 address, u32 *value)
 {
-        int retval;
+       int retval;
        u32 val;
 
        /* Warning: address is dword address (4 bytes) */
@@ -605,11 +605,11 @@ static int blackbird_load_firmware(struct cx8802_dev *dev)
        u32 *dataptr;
 
        retval  = register_write(dev->core, IVTV_REG_VPU, 0xFFFFFFED);
-        retval |= register_write(dev->core, IVTV_REG_HW_BLOCKS, IVTV_CMD_HW_BLOCKS_RST);
-        retval |= register_write(dev->core, IVTV_REG_ENC_SDRAM_REFRESH, 0x80000640);
-        retval |= register_write(dev->core, IVTV_REG_ENC_SDRAM_PRECHARGE, 0x1A);
+       retval |= register_write(dev->core, IVTV_REG_HW_BLOCKS, IVTV_CMD_HW_BLOCKS_RST);
+       retval |= register_write(dev->core, IVTV_REG_ENC_SDRAM_REFRESH, 0x80000640);
+       retval |= register_write(dev->core, IVTV_REG_ENC_SDRAM_PRECHARGE, 0x1A);
        msleep(1);
-        retval |= register_write(dev->core, IVTV_REG_APU, 0);
+       retval |= register_write(dev->core, IVTV_REG_APU, 0);
 
        if (retval < 0)
                dprintk(0, "Error with register_write\n");
@@ -657,13 +657,13 @@ static int blackbird_load_firmware(struct cx8802_dev *dev)
        release_firmware(firmware);
        dprintk(0, "Firmware upload successful.\n");
 
-        retval |= register_write(dev->core, IVTV_REG_HW_BLOCKS, IVTV_CMD_HW_BLOCKS_RST);
-        retval |= register_read(dev->core, IVTV_REG_SPU, &value);
-        retval |= register_write(dev->core, IVTV_REG_SPU, value & 0xFFFFFFFE);
+       retval |= register_write(dev->core, IVTV_REG_HW_BLOCKS, IVTV_CMD_HW_BLOCKS_RST);
+       retval |= register_read(dev->core, IVTV_REG_SPU, &value);
+       retval |= register_write(dev->core, IVTV_REG_SPU, value & 0xFFFFFFFE);
        msleep(1);
 
        retval |= register_read(dev->core, IVTV_REG_VPU, &value);
-        retval |= register_write(dev->core, IVTV_REG_VPU, value & 0xFFFFFFE8);
+       retval |= register_write(dev->core, IVTV_REG_VPU, value & 0xFFFFFFE8);
 
        if (retval < 0)
                dprintk(0, "Error with register_write\n");
@@ -683,84 +683,560 @@ DB* DVD | MPEG2 | 720x576PAL | CBR     | 600 :Good    | 6000 Kbps  | 25fps   | M
 =================================================================================================================
 *DB: "DirectBurn"
 */
-static void blackbird_codec_settings(struct cx8802_dev *dev)
+
+static struct blackbird_dnr default_dnr_params = {
+       .mode     = BLACKBIRD_DNR_BITS_MANUAL,
+       .type     = BLACKBIRD_MEDIAN_FILTER_DISABLED,
+       .spatial  = 0,
+       .temporal = 0
+};
+static struct v4l2_mpeg_compression default_mpeg_params = {
+       .st_type          = V4L2_MPEG_PS_2,
+       .st_bitrate       = {
+               .mode     = V4L2_BITRATE_CBR,
+               .min      = 0,
+               .target   = 0,
+               .max      = 0
+       },
+       .ts_pid_pmt       = 16,
+       .ts_pid_audio     = 260,
+       .ts_pid_video     = 256,
+       .ts_pid_pcr       = 259,
+       .ps_size          = 0,
+       .au_type          = V4L2_MPEG_AU_2_II,
+       .au_bitrate       = {
+               .mode     = V4L2_BITRATE_CBR,
+               .min      = 224,
+               .target   = 224,
+               .max      = 224
+       },
+       .au_sample_rate    = 44100,
+       .au_pesid          = 0,
+       .vi_type           = V4L2_MPEG_VI_2,
+       .vi_aspect_ratio   = V4L2_MPEG_ASPECT_4_3,
+       .vi_bitrate        = {
+               .mode      = V4L2_BITRATE_CBR,
+               .min       = 4000,
+               .target    = 4500,
+               .max       = 6000
+       },
+       .vi_frame_rate     = 25,
+       .vi_frames_per_gop = 15,
+       .vi_bframes_count  = 2,
+       .vi_pesid          = 0,
+       .closed_gops       = 0,
+       .pulldown          = 0
+};
+
+static enum blackbird_stream_type mpeg_stream_types[] = {
+       [V4L2_MPEG_SS_1]   = BLACKBIRD_STREAM_MPEG1,
+       [V4L2_MPEG_PS_2]   = BLACKBIRD_STREAM_PROGRAM,
+       [V4L2_MPEG_TS_2]   = BLACKBIRD_STREAM_TRANSPORT,
+       [V4L2_MPEG_PS_DVD] = BLACKBIRD_STREAM_DVD,
+};
+static enum blackbird_aspect_ratio mpeg_stream_ratios[] = {
+       [V4L2_MPEG_ASPECT_SQUARE] = BLACKBIRD_ASPECT_RATIO_1_1_SQUARE,
+       [V4L2_MPEG_ASPECT_4_3]    = BLACKBIRD_ASPECT_RATIO_4_3,
+       [V4L2_MPEG_ASPECT_16_9]   = BLACKBIRD_ASPECT_RATIO_16_9,
+       [V4L2_MPEG_ASPECT_1_221]  = BLACKBIRD_ASPECT_RATIO_221_100,
+};
+static enum blackbird_video_bitrate_type mpeg_video_bitrates[] = {
+       [V4L2_BITRATE_NONE] = BLACKBIRD_VIDEO_CBR,
+       [V4L2_BITRATE_CBR]  = BLACKBIRD_VIDEO_CBR,
+       [V4L2_BITRATE_VBR]  = BLACKBIRD_VIDEO_VBR,
+};
+/* find the best layer I/II bitrate to fit a given numeric value */
+struct bitrate_bits {
+       u32 bits; /* layer bits for the best fit */
+       u32 rate; /* actual numeric value for the layer best fit */
+};
+struct bitrate_approximation {
+       u32                 target;   /* numeric value of the rate we want */
+       struct bitrate_bits layer[2];
+};
+static struct bitrate_approximation mpeg_audio_bitrates[] = {
+       /* target  layer[0].bits           layer[0].rate       layer[1].bits           layer[1].rate */
+       {   0, { {                                0,   0, }, {                                0,   0, }, }, },
+       {  32, { { BLACKBIRD_AUDIO_BITS_LAYER_1_32 ,  32, }, { BLACKBIRD_AUDIO_BITS_LAYER_2_32 ,  32, }, }, },
+       {  48, { { BLACKBIRD_AUDIO_BITS_LAYER_1_64 ,  64, }, { BLACKBIRD_AUDIO_BITS_LAYER_2_48 ,  48, }, }, },
+       {  56, { { BLACKBIRD_AUDIO_BITS_LAYER_1_64 ,  64, }, { BLACKBIRD_AUDIO_BITS_LAYER_2_56 ,  56, }, }, },
+       {  64, { { BLACKBIRD_AUDIO_BITS_LAYER_1_64 ,  64, }, { BLACKBIRD_AUDIO_BITS_LAYER_2_64 ,  64, }, }, },
+       {  80, { { BLACKBIRD_AUDIO_BITS_LAYER_1_96 ,  96, }, { BLACKBIRD_AUDIO_BITS_LAYER_2_80 ,  80, }, }, },
+       {  96, { { BLACKBIRD_AUDIO_BITS_LAYER_1_96 ,  96, }, { BLACKBIRD_AUDIO_BITS_LAYER_2_96 ,  96, }, }, },
+       { 112, { { BLACKBIRD_AUDIO_BITS_LAYER_1_128, 128, }, { BLACKBIRD_AUDIO_BITS_LAYER_2_112, 112, }, }, },
+       { 128, { { BLACKBIRD_AUDIO_BITS_LAYER_1_128, 128, }, { BLACKBIRD_AUDIO_BITS_LAYER_2_128, 128, }, }, },
+       { 160, { { BLACKBIRD_AUDIO_BITS_LAYER_1_160, 160, }, { BLACKBIRD_AUDIO_BITS_LAYER_2_160, 160, }, }, },
+       { 192, { { BLACKBIRD_AUDIO_BITS_LAYER_1_192, 192, }, { BLACKBIRD_AUDIO_BITS_LAYER_2_192, 192, }, }, },
+       { 224, { { BLACKBIRD_AUDIO_BITS_LAYER_1_224, 224, }, { BLACKBIRD_AUDIO_BITS_LAYER_2_224, 224, }, }, },
+       { 256, { { BLACKBIRD_AUDIO_BITS_LAYER_1_256, 256, }, { BLACKBIRD_AUDIO_BITS_LAYER_2_256, 256, }, }, },
+       { 288, { { BLACKBIRD_AUDIO_BITS_LAYER_1_288, 288, }, { BLACKBIRD_AUDIO_BITS_LAYER_2_320, 320, }, }, },
+       { 320, { { BLACKBIRD_AUDIO_BITS_LAYER_1_320, 320, }, { BLACKBIRD_AUDIO_BITS_LAYER_2_320, 320, }, }, },
+       { 352, { { BLACKBIRD_AUDIO_BITS_LAYER_1_352, 352, }, { BLACKBIRD_AUDIO_BITS_LAYER_2_384, 384, }, }, },
+       { 384, { { BLACKBIRD_AUDIO_BITS_LAYER_1_384, 384, }, { BLACKBIRD_AUDIO_BITS_LAYER_2_384, 384, }, }, },
+       { 416, { { BLACKBIRD_AUDIO_BITS_LAYER_1_416, 416, }, { BLACKBIRD_AUDIO_BITS_LAYER_2_384, 384, }, }, },
+       { 448, { { BLACKBIRD_AUDIO_BITS_LAYER_1_448, 448, }, { BLACKBIRD_AUDIO_BITS_LAYER_2_384, 384, }, }, },
+};
+static const int BITRATES_SIZE = ARRAY_SIZE(mpeg_audio_bitrates);
+
+static void blackbird_set_default_params(struct cx8802_dev *dev)
 {
-       int bitrate_mode = 1;
-       int bitrate = 7500000;
-       int bitrate_peak = 7500000;
-       bitrate_mode = BLACKBIRD_VIDEO_CBR;
-       bitrate = 4000*1024;
-       bitrate_peak = 4000*1024;
+       struct v4l2_mpeg_compression *params = &dev->params;
+       u32 au_params;
 
        /* assign stream type */
-       blackbird_api_cmd(dev, BLACKBIRD_API_SET_STREAM_TYPE, 1, 0, BLACKBIRD_STREAM_PROGRAM);
-
-       /* assign output port */
-       blackbird_api_cmd(dev, BLACKBIRD_API_SET_OUTPUT_PORT, 1, 0, BLACKBIRD_OUTPUT_PORT_STREAMING); /* Host */
+       if( params->st_type >= ARRAY_SIZE(mpeg_stream_types) )
+               params->st_type = V4L2_MPEG_PS_2;
+       if( params->st_type == V4L2_MPEG_SS_1 )
+               params->vi_type = V4L2_MPEG_VI_1;
+       else
+               params->vi_type = V4L2_MPEG_VI_2;
+       blackbird_api_cmd(dev, BLACKBIRD_API_SET_STREAM_TYPE, 1, 0, mpeg_stream_types[params->st_type]);
 
        /* assign framerate */
-       blackbird_api_cmd(dev, BLACKBIRD_API_SET_FRAMERATE, 1, 0, BLACKBIRD_FRAMERATE_PAL_25);
-
-       /* assign frame size */
-       blackbird_api_cmd(dev, BLACKBIRD_API_SET_RESOLUTION, 2, 0,
-                         dev->height, dev->width);
+       if( params->vi_frame_rate <= 25 )
+       {
+               params->vi_frame_rate = 25;
+               blackbird_api_cmd(dev, BLACKBIRD_API_SET_FRAMERATE, 1, 0, BLACKBIRD_FRAMERATE_PAL_25);
+       }
+       else
+       {
+               params->vi_frame_rate = 30;
+               blackbird_api_cmd(dev, BLACKBIRD_API_SET_FRAMERATE, 1, 0, BLACKBIRD_FRAMERATE_NTSC_30);
+       }
 
        /* assign aspect ratio */
-       blackbird_api_cmd(dev, BLACKBIRD_API_SET_ASPECT_RATIO, 1, 0, BLACKBIRD_ASPECT_RATIO_4_3);
-
-       /* assign bitrates */
-       blackbird_api_cmd(dev, BLACKBIRD_API_SET_VIDEO_BITRATE, 5, 0,
-                        bitrate_mode,         /* mode */
-                        bitrate,              /* bps */
-                        bitrate_peak / BLACKBIRD_PEAK_RATE_DIVISOR,   /* peak/400 */
-                        BLACKBIRD_MUX_RATE_DEFAULT /*, 0x70*/);             /* encoding buffer, ckennedy */
+       if( params->vi_aspect_ratio >= ARRAY_SIZE(mpeg_stream_ratios) )
+               params->vi_aspect_ratio = V4L2_MPEG_ASPECT_4_3;
+       blackbird_api_cmd(dev, BLACKBIRD_API_SET_ASPECT_RATIO, 1, 0, mpeg_stream_ratios[params->vi_aspect_ratio]);
 
        /* assign gop properties */
-       blackbird_api_cmd(dev, BLACKBIRD_API_SET_GOP_STRUCTURE, 2, 0, 15, 3);
+       blackbird_api_cmd(dev, BLACKBIRD_API_SET_GOP_STRUCTURE, 2, 0, params->vi_frames_per_gop, params->vi_bframes_count+1);
+
+       /* assign gop closure */
+       blackbird_api_cmd(dev, BLACKBIRD_API_SET_GOP_CLOSURE, 1, 0, params->closed_gops);
 
        /* assign 3 2 pulldown */
-       blackbird_api_cmd(dev, BLACKBIRD_API_SET_3_2_PULLDOWN, 1, 0, BLACKBIRD_3_2_PULLDOWN_DISABLED);
+       blackbird_api_cmd(dev, BLACKBIRD_API_SET_3_2_PULLDOWN, 1, 0, params->pulldown);
+
+       /* make sure the params are within bounds */
+       if( params->st_bitrate.mode >= ARRAY_SIZE(mpeg_video_bitrates) )
+               params->vi_bitrate.mode = V4L2_BITRATE_NONE;
+       if( params->vi_bitrate.mode >= ARRAY_SIZE(mpeg_video_bitrates) )
+               params->vi_bitrate.mode = V4L2_BITRATE_NONE;
+       if( params->au_bitrate.mode >= ARRAY_SIZE(mpeg_video_bitrates) )
+               params->au_bitrate.mode = V4L2_BITRATE_NONE;
 
        /* assign audio properties */
        /* note: it's not necessary to set the samplerate, the mpeg encoder seems to autodetect/adjust */
-       /* blackbird_api_cmd(dev, IVTV_API_ASSIGN_AUDIO_PROPERTIES, 1, 0, (2<<2) | (8<<4));
-          blackbird_api_cmd(dev, IVTV_API_ASSIGN_AUDIO_PROPERTIES, 1, 0, 0 | (2 << 2) | (14 << 4)); */
-       blackbird_api_cmd(dev, BLACKBIRD_API_SET_AUDIO_PARAMS, 1, 0,
-                       BLACKBIRD_AUDIO_BITS_44100HZ |
-                       BLACKBIRD_AUDIO_BITS_LAYER_2 |
-                       BLACKBIRD_AUDIO_BITS_LAYER_2_224 |
-                       BLACKBIRD_AUDIO_BITS_STEREO |
+       au_params = BLACKBIRD_AUDIO_BITS_STEREO |
                        /* BLACKBIRD_AUDIO_BITS_BOUND_4 | */
                        BLACKBIRD_AUDIO_BITS_EMPHASIS_NONE |
                        BLACKBIRD_AUDIO_BITS_CRC_OFF |
                        BLACKBIRD_AUDIO_BITS_COPYRIGHT_OFF |
-                       BLACKBIRD_AUDIO_BITS_COPY
-               );
+                       BLACKBIRD_AUDIO_BITS_COPY |
+                       0;
+       if( params->au_sample_rate <= 32000 )
+       {
+               params->au_sample_rate = 32000;
+               au_params |= BLACKBIRD_AUDIO_BITS_32000HZ;
+       }
+       else if( params->au_sample_rate <= 44100 )
+       {
+               params->au_sample_rate = 44100;
+               au_params |= BLACKBIRD_AUDIO_BITS_44100HZ;
+       }
+       else
+       {
+               params->au_sample_rate = 48000;
+               au_params |= BLACKBIRD_AUDIO_BITS_48000HZ;
+       }
+       if( params->au_type == V4L2_MPEG_AU_2_I )
+       {
+               au_params |= BLACKBIRD_AUDIO_BITS_LAYER_1;
+       }
+       else
+       {
+               /* TODO: try to handle the other formats more gracefully */
+               params->au_type = V4L2_MPEG_AU_2_II;
+               au_params |= BLACKBIRD_AUDIO_BITS_LAYER_2;
+       }
+       if( params->au_bitrate.mode )
+       {
+               int layer;
+
+               if( params->au_bitrate.mode == V4L2_BITRATE_CBR )
+                       params->au_bitrate.max = params->vi_bitrate.target;
+               else
+                       params->au_bitrate.target = params->vi_bitrate.max;
+
+               layer = params->au_type;
+               if( params->au_bitrate.target == 0 )
+               {
+                       /* TODO: use the minimum possible bitrate instead of 0 ? */
+                       au_params |= 0;
+               }
+               else if( params->au_bitrate.target >=
+                        mpeg_audio_bitrates[BITRATES_SIZE-1].layer[layer].rate )
+               {
+                       /* clamp the bitrate to the max supported by the standard */
+                       params->au_bitrate.target = mpeg_audio_bitrates[BITRATES_SIZE-1].layer[layer].rate;
+                       params->au_bitrate.max = params->au_bitrate.target;
+                       au_params |= mpeg_audio_bitrates[BITRATES_SIZE-1].layer[layer].bits;
+               }
+               else
+               {
+                       /* round up to the nearest supported bitrate */
+                       int i;
+                       for(i = 1; i < BITRATES_SIZE; i++)
+                       {
+                               if( params->au_bitrate.target > mpeg_audio_bitrates[i-1].layer[layer].rate &&
+                                   params->au_bitrate.target <= mpeg_audio_bitrates[i].layer[layer].rate )
+                               {
+                                       params->au_bitrate.target = mpeg_audio_bitrates[i].layer[layer].rate;
+                                       params->au_bitrate.max = params->au_bitrate.target;
+                                       au_params |= mpeg_audio_bitrates[i].layer[layer].bits;
+                                       break;
+                               }
+                       }
+               }
+       }
+       else
+       {
+               /* TODO: ??? */
+               params->au_bitrate.target = params->au_bitrate.max = 0;
+               au_params |= 0;
+       }
+       blackbird_api_cmd(dev, BLACKBIRD_API_SET_AUDIO_PARAMS, 1, 0, au_params );
+
+       /* assign bitrates */
+       if( params->vi_bitrate.mode )
+       {
+               /* bitrate is set, let's figure out the cbr/vbr mess */
+               if( params->vi_bitrate.max < params->vi_bitrate.target )
+               {
+                       if( params->vi_bitrate.mode == V4L2_BITRATE_CBR )
+                               params->vi_bitrate.max = params->vi_bitrate.target;
+                       else
+                               params->vi_bitrate.target = params->vi_bitrate.max;
+               }
+       }
+       else
+       {
+               if( params->st_bitrate.max < params->st_bitrate.target )
+               {
+                       if( params->st_bitrate.mode == V4L2_BITRATE_VBR )
+                               params->st_bitrate.target = params->st_bitrate.max;
+                       else
+                               params->st_bitrate.max = params->st_bitrate.target;
+               }
+               /* calculate vi_bitrate = st_bitrate - au_bitrate */
+               params->vi_bitrate.max = params->st_bitrate.max - params->au_bitrate.max;
+               params->vi_bitrate.target = params->st_bitrate.target - params->au_bitrate.target;
+       }
+       blackbird_api_cmd(dev, BLACKBIRD_API_SET_VIDEO_BITRATE, 4, 0,
+                               mpeg_video_bitrates[params->vi_bitrate.mode],
+                               params->vi_bitrate.target * 1000, /* kbps -> bps */
+                               params->vi_bitrate.max * 1000 / BLACKBIRD_PEAK_RATE_DIVISOR, /* peak/400 */
+                               BLACKBIRD_MUX_RATE_DEFAULT /*, 0x70*/); /* encoding buffer, ckennedy */
+
+       /* TODO: implement the stream ID stuff:
+               ts_pid_pmt, ts_pid_audio, ts_pid_video, ts_pid_pcr,
+               ps_size, au_pesid, vi_pesid
+       */
+}
+#define CHECK_PARAM( name ) ( dev->params.name != params->name )
+#define IF_PARAM( name ) if( CHECK_PARAM( name ) )
+#define UPDATE_PARAM( name ) dev->params.name = params->name
+void blackbird_set_params(struct cx8802_dev *dev, struct v4l2_mpeg_compression *params)
+{
+       u32 au_params;
+
+       /* assign stream type */
+       if( params->st_type >= ARRAY_SIZE(mpeg_stream_types) )
+               params->st_type = V4L2_MPEG_PS_2;
+       if( params->st_type == V4L2_MPEG_SS_1 )
+               params->vi_type = V4L2_MPEG_VI_1;
+       else
+               params->vi_type = V4L2_MPEG_VI_2;
+       if( CHECK_PARAM( st_type ) || CHECK_PARAM( vi_type ) )
+       {
+               UPDATE_PARAM( st_type );
+               UPDATE_PARAM( vi_type );
+               blackbird_api_cmd(dev, BLACKBIRD_API_SET_STREAM_TYPE, 1, 0, mpeg_stream_types[params->st_type]);
+       }
+
+       /* assign framerate */
+       if( params->vi_frame_rate <= 25 )
+               params->vi_frame_rate = 25;
+       else
+               params->vi_frame_rate = 30;
+       IF_PARAM( vi_frame_rate )
+       {
+               UPDATE_PARAM( vi_frame_rate );
+               if( params->vi_frame_rate == 25 )
+                       blackbird_api_cmd(dev, BLACKBIRD_API_SET_FRAMERATE, 1, 0, BLACKBIRD_FRAMERATE_PAL_25);
+               else
+                       blackbird_api_cmd(dev, BLACKBIRD_API_SET_FRAMERATE, 1, 0, BLACKBIRD_FRAMERATE_NTSC_30);
+       }
+
+       /* assign aspect ratio */
+       if( params->vi_aspect_ratio >= ARRAY_SIZE(mpeg_stream_ratios) )
+               params->vi_aspect_ratio = V4L2_MPEG_ASPECT_4_3;
+       IF_PARAM( vi_aspect_ratio )
+       {
+               UPDATE_PARAM( vi_aspect_ratio );
+               blackbird_api_cmd(dev, BLACKBIRD_API_SET_ASPECT_RATIO, 1, 0, mpeg_stream_ratios[params->vi_aspect_ratio]);
+       }
+
+       /* assign gop properties */
+       if( CHECK_PARAM( vi_frames_per_gop ) || CHECK_PARAM( vi_bframes_count ) )
+       {
+               UPDATE_PARAM( vi_frames_per_gop );
+               UPDATE_PARAM( vi_bframes_count );
+               blackbird_api_cmd(dev, BLACKBIRD_API_SET_GOP_STRUCTURE, 2, 0, params->vi_frames_per_gop, params->vi_bframes_count+1);
+       }
 
        /* assign gop closure */
-       blackbird_api_cmd(dev, BLACKBIRD_API_SET_GOP_CLOSURE, 1, 0, BLACKBIRD_GOP_CLOSURE_OFF);
+       IF_PARAM( closed_gops )
+       {
+               UPDATE_PARAM( closed_gops );
+               blackbird_api_cmd(dev, BLACKBIRD_API_SET_GOP_CLOSURE, 1, 0, params->closed_gops);
+       }
+
+       /* assign 3 2 pulldown */
+       IF_PARAM( pulldown )
+       {
+               UPDATE_PARAM( pulldown );
+               blackbird_api_cmd(dev, BLACKBIRD_API_SET_3_2_PULLDOWN, 1, 0, params->pulldown);
+       }
+
+       /* make sure the params are within bounds */
+       if( params->st_bitrate.mode >= ARRAY_SIZE(mpeg_video_bitrates) )
+               params->vi_bitrate.mode = V4L2_BITRATE_NONE;
+       if( params->vi_bitrate.mode >= ARRAY_SIZE(mpeg_video_bitrates) )
+               params->vi_bitrate.mode = V4L2_BITRATE_NONE;
+       if( params->au_bitrate.mode >= ARRAY_SIZE(mpeg_video_bitrates) )
+               params->au_bitrate.mode = V4L2_BITRATE_NONE;
+
+       /* assign audio properties */
+       /* note: it's not necessary to set the samplerate, the mpeg encoder seems to autodetect/adjust */
+       au_params = BLACKBIRD_AUDIO_BITS_STEREO |
+                       /* BLACKBIRD_AUDIO_BITS_BOUND_4 | */
+       BLACKBIRD_AUDIO_BITS_EMPHASIS_NONE |
+               BLACKBIRD_AUDIO_BITS_CRC_OFF |
+               BLACKBIRD_AUDIO_BITS_COPYRIGHT_OFF |
+               BLACKBIRD_AUDIO_BITS_COPY |
+               0;
+       if( params->au_sample_rate < 32000 )
+       {
+               params->au_sample_rate = 32000;
+               au_params |= BLACKBIRD_AUDIO_BITS_32000HZ;
+       }
+       else if( params->au_sample_rate < 44100 )
+       {
+               params->au_sample_rate = 44100;
+               au_params |= BLACKBIRD_AUDIO_BITS_44100HZ;
+       }
+       else
+       {
+               params->au_sample_rate = 48000;
+               au_params |= BLACKBIRD_AUDIO_BITS_48000HZ;
+       }
+       if( params->au_type == V4L2_MPEG_AU_2_I )
+       {
+               au_params |= BLACKBIRD_AUDIO_BITS_LAYER_1;
+       }
+       else
+       {
+               /* TODO: try to handle the other formats more gracefully */
+               params->au_type = V4L2_MPEG_AU_2_II;
+               au_params |= BLACKBIRD_AUDIO_BITS_LAYER_2;
+       }
+       if( params->au_bitrate.mode )
+       {
+               int layer;
+
+               if( params->au_bitrate.mode == V4L2_BITRATE_CBR )
+                       params->au_bitrate.max = params->vi_bitrate.target;
+               else
+                       params->au_bitrate.target = params->vi_bitrate.max;
+
+               layer = params->au_type;
+               if( params->au_bitrate.target == 0 )
+               {
+                       /* TODO: use the minimum possible bitrate instead of 0 ? */
+                       au_params |= 0;
+               }
+               else if( params->au_bitrate.target >=
+                        mpeg_audio_bitrates[BITRATES_SIZE-1].layer[layer].rate )
+               {
+                       /* clamp the bitrate to the max supported by the standard */
+                       params->au_bitrate.target = mpeg_audio_bitrates[BITRATES_SIZE-1].layer[layer].rate;
+                       params->au_bitrate.max = params->au_bitrate.target;
+                       au_params |= mpeg_audio_bitrates[BITRATES_SIZE-1].layer[layer].bits;
+               }
+               else
+               {
+                       /* round up to the nearest supported bitrate */
+                       int i;
+                       for(i = 1; i < BITRATES_SIZE; i++)
+                       {
+                               if( params->au_bitrate.target > mpeg_audio_bitrates[i-1].layer[layer].rate &&
+                                   params->au_bitrate.target <= mpeg_audio_bitrates[i].layer[layer].rate )
+                               {
+                                       params->au_bitrate.target = mpeg_audio_bitrates[i].layer[layer].rate;
+                                       params->au_bitrate.max = params->au_bitrate.target;
+                                       au_params |= mpeg_audio_bitrates[i].layer[layer].bits;
+                                       break;
+                               }
+                       }
+               }
+       }
+       else
+       {
+               /* TODO: ??? */
+               params->au_bitrate.target = params->au_bitrate.max = 0;
+               au_params |= 0;
+       }
+       if( CHECK_PARAM( au_type ) || CHECK_PARAM( au_sample_rate )
+               || CHECK_PARAM( au_bitrate.mode ) || CHECK_PARAM( au_bitrate.max )
+               || CHECK_PARAM( au_bitrate.target )
+       )
+       {
+               UPDATE_PARAM( au_type );
+               UPDATE_PARAM( au_sample_rate );
+               UPDATE_PARAM( au_bitrate );
+               blackbird_api_cmd(dev, BLACKBIRD_API_SET_AUDIO_PARAMS, 1, 0, au_params );
+       }
+
+       /* assign bitrates */
+       if( params->vi_bitrate.mode )
+       {
+               /* bitrate is set, let's figure out the cbr/vbr mess */
+               if( params->vi_bitrate.max < params->vi_bitrate.target )
+               {
+                       if( params->vi_bitrate.mode == V4L2_BITRATE_CBR )
+                               params->vi_bitrate.max = params->vi_bitrate.target;
+                       else
+                               params->vi_bitrate.target = params->vi_bitrate.max;
+               }
+       }
+       else
+       {
+               if( params->st_bitrate.max < params->st_bitrate.target )
+               {
+                       if( params->st_bitrate.mode == V4L2_BITRATE_VBR )
+                               params->st_bitrate.target = params->st_bitrate.max;
+                       else
+                               params->st_bitrate.max = params->st_bitrate.target;
+               }
+               /* calculate vi_bitrate = st_bitrate - au_bitrate */
+               params->vi_bitrate.max = params->st_bitrate.max - params->au_bitrate.max;
+               params->vi_bitrate.target = params->st_bitrate.target - params->au_bitrate.target;
+       }
+       UPDATE_PARAM( st_bitrate );
+       if( CHECK_PARAM( vi_bitrate.mode ) || CHECK_PARAM( vi_bitrate.max )
+               || CHECK_PARAM( vi_bitrate.target )
+       )
+       {
+               UPDATE_PARAM( vi_bitrate );
+               blackbird_api_cmd(dev, BLACKBIRD_API_SET_VIDEO_BITRATE, 4, 0,
+                               mpeg_video_bitrates[params->vi_bitrate.mode],
+                               params->vi_bitrate.target * 1000, /* kbps -> bps */
+                               params->vi_bitrate.max * 1000 / BLACKBIRD_PEAK_RATE_DIVISOR, /* peak/400 */
+                               BLACKBIRD_MUX_RATE_DEFAULT /*, 0x70*/); /* encoding buffer, ckennedy */
+       }
 
+       /* TODO: implement the stream ID stuff:
+               ts_pid_pmt, ts_pid_audio, ts_pid_video, ts_pid_pcr,
+               ps_size, au_pesid, vi_pesid
+       */
+       UPDATE_PARAM( ts_pid_pmt );
+       UPDATE_PARAM( ts_pid_audio );
+       UPDATE_PARAM( ts_pid_video );
+       UPDATE_PARAM( ts_pid_pcr );
+       UPDATE_PARAM( ps_size );
+       UPDATE_PARAM( au_pesid );
+       UPDATE_PARAM( vi_pesid );
+}
 
+static void blackbird_set_default_dnr_params(struct cx8802_dev *dev)
+{
        /* assign dnr filter mode */
+       if( dev->dnr_params.mode > BLACKBIRD_DNR_BITS_AUTO )
+               dev->dnr_params.mode = BLACKBIRD_DNR_BITS_MANUAL;
+       if( dev->dnr_params.type > BLACKBIRD_MEDIAN_FILTER_DIAGONAL )
+               dev->dnr_params.type = BLACKBIRD_MEDIAN_FILTER_DISABLED;
        blackbird_api_cmd(dev, BLACKBIRD_API_SET_DNR_MODE, 2, 0,
-                       BLACKBIRD_DNR_BITS_MANUAL,
-                       BLACKBIRD_MEDIAN_FILTER_DISABLED
-               );
+                               dev->dnr_params.mode,
+                               dev->dnr_params.type
+                       );
 
        /* assign dnr filter props*/
-       blackbird_api_cmd(dev, BLACKBIRD_API_SET_MANUAL_DNR, 2, 0, 0, 0);
+       if( dev->dnr_params.spatial > 15 )
+               dev->dnr_params.spatial = 15;
+       if( dev->dnr_params.temporal > 31 )
+               dev->dnr_params.temporal = 31;
+       blackbird_api_cmd(dev, BLACKBIRD_API_SET_MANUAL_DNR, 2, 0,
+                               dev->dnr_params.spatial,
+                               dev->dnr_params.temporal
+                       );
+}
+#define CHECK_DNR_PARAM( name ) ( dev->dnr_params.name != dnr_params->name )
+#define UPDATE_DNR_PARAM( name ) dev->dnr_params.name = dnr_params->name
+void blackbird_set_dnr_params(struct cx8802_dev *dev, struct blackbird_dnr* dnr_params)
+{
+       /* assign dnr filter mode */
+       /* clamp values */
+       if( dnr_params->mode > BLACKBIRD_DNR_BITS_AUTO )
+               dnr_params->mode = BLACKBIRD_DNR_BITS_MANUAL;
+       if( dnr_params->type > BLACKBIRD_MEDIAN_FILTER_DIAGONAL )
+               dnr_params->type = BLACKBIRD_MEDIAN_FILTER_DISABLED;
+       /* check if the params actually changed */
+       if( CHECK_DNR_PARAM( mode ) || CHECK_DNR_PARAM( type ) )
+       {
+               UPDATE_DNR_PARAM( mode );
+               UPDATE_DNR_PARAM( type );
+               blackbird_api_cmd(dev, BLACKBIRD_API_SET_DNR_MODE, 2, 0, dnr_params->mode, dnr_params->type);
+       }
+
+       /* assign dnr filter props*/
+       if( dnr_params->spatial > 15 )
+               dnr_params->spatial = 15;
+       if( dnr_params->temporal > 31 )
+               dnr_params->temporal = 31;
+       if( CHECK_DNR_PARAM( spatial ) || CHECK_DNR_PARAM( temporal ) )
+       {
+               UPDATE_DNR_PARAM( spatial );
+               UPDATE_DNR_PARAM( temporal );
+               blackbird_api_cmd(dev, BLACKBIRD_API_SET_MANUAL_DNR, 2, 0, dnr_params->spatial, dnr_params->temporal);
+       }
+}
+
+static void blackbird_codec_settings(struct cx8802_dev *dev)
+{
+
+       /* assign output port */
+       blackbird_api_cmd(dev, BLACKBIRD_API_SET_OUTPUT_PORT, 1, 0, BLACKBIRD_OUTPUT_PORT_STREAMING); /* Host */
+
+       /* assign frame size */
+       blackbird_api_cmd(dev, BLACKBIRD_API_SET_RESOLUTION, 2, 0,
+                               dev->height, dev->width);
 
        /* assign coring levels (luma_h, luma_l, chroma_h, chroma_l) */
        blackbird_api_cmd(dev, BLACKBIRD_API_SET_DNR_MEDIAN, 4, 0, 0, 255, 0, 255);
 
        /* assign spatial filter type: luma_t: horiz_only, chroma_t: horiz_only */
        blackbird_api_cmd(dev, BLACKBIRD_API_SET_SPATIAL_FILTER, 2, 0,
-                       BLACKBIRD_SPATIAL_FILTER_LUMA_1D_HORIZ,
-                       BLACKBIRD_SPATIAL_FILTER_CHROMA_1D_HORIZ
-               );
+                               BLACKBIRD_SPATIAL_FILTER_LUMA_1D_HORIZ,
+                               BLACKBIRD_SPATIAL_FILTER_CHROMA_1D_HORIZ
+                       );
 
        /* assign frame drop rate */
        /* blackbird_api_cmd(dev, IVTV_API_ASSIGN_FRAME_DROP_RATE, 1, 0, 0); */
+
+       blackbird_set_default_params(dev);
+       blackbird_set_default_dnr_params(dev);
 }
 
 static int blackbird_initialize_codec(struct cx8802_dev *dev)
@@ -851,15 +1327,10 @@ static int bb_buf_setup(struct videobuf_queue *q,
        struct cx8802_fh *fh = q->priv_data;
 
        fh->dev->ts_packet_size  = 188 * 4; /* was: 512 */
-       fh->dev->ts_packet_count = 32; /* was: 100 */
+       fh->dev->ts_packet_count = mpegbufs; /* was: 100 */
 
        *size = fh->dev->ts_packet_size * fh->dev->ts_packet_count;
-       if (0 == *count)
-               *count = mpegbufs;
-       if (*count < 2)
-               *count = 2;
-       if (*count > 32)
-               *count = 32;
+       *count = fh->dev->ts_packet_count;
        return 0;
 }
 
@@ -868,7 +1339,7 @@ bb_buf_prepare(struct videobuf_queue *q, struct videobuf_buffer *vb,
               enum v4l2_field field)
 {
        struct cx8802_fh *fh = q->priv_data;
-       return cx8802_buf_prepare(fh->dev, (struct cx88_buffer*)vb);
+       return cx8802_buf_prepare(fh->dev, (struct cx88_buffer*)vb, field);
 }
 
 static void
@@ -920,8 +1391,6 @@ static int mpeg_do_ioctl(struct inode *inode, struct file *file,
                        V4L2_CAP_VIDEO_CAPTURE |
                        V4L2_CAP_READWRITE     |
                        V4L2_CAP_STREAMING     |
-                       V4L2_CAP_VBI_CAPTURE   |
-                       V4L2_CAP_VIDEO_OVERLAY |
                        0;
                if (UNSET != core->tuner_type)
                        cap->capabilities |= V4L2_CAP_TUNER;
@@ -941,27 +1410,52 @@ static int mpeg_do_ioctl(struct inode *inode, struct file *file,
 
                memset(f,0,sizeof(*f));
                f->index = index;
-               strlcpy(f->description, "MPEG TS", sizeof(f->description));
+               strlcpy(f->description, "MPEG", sizeof(f->description));
                f->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
                f->pixelformat = V4L2_PIX_FMT_MPEG;
                return 0;
        }
        case VIDIOC_G_FMT:
-       case VIDIOC_S_FMT:
-       case VIDIOC_TRY_FMT:
        {
-               /* FIXME -- quick'n'dirty for exactly one size ... */
                struct v4l2_format *f = arg;
 
                memset(f,0,sizeof(*f));
                f->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+               f->fmt.pix.pixelformat  = V4L2_PIX_FMT_MPEG;
+               f->fmt.pix.bytesperline = 0;
+               f->fmt.pix.sizeimage    = dev->ts_packet_size * dev->ts_packet_count; /* 188 * 4 * 1024; */
+               f->fmt.pix.colorspace   = 0;
                f->fmt.pix.width        = dev->width;
                f->fmt.pix.height       = dev->height;
+               f->fmt.pix.field        = fh->mpegq.field;
+               dprintk(0,"VIDIOC_G_FMT: w: %d, h: %d, f: %d\n",
+                       dev->width, dev->height, fh->mpegq.field );
+               return 0;
+       }
+       case VIDIOC_TRY_FMT:
+       {
+               struct v4l2_format *f = arg;
+
+               f->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+               f->fmt.pix.pixelformat  = V4L2_PIX_FMT_MPEG;
+               f->fmt.pix.bytesperline = 0;
+               f->fmt.pix.sizeimage    = dev->ts_packet_size * dev->ts_packet_count; /* 188 * 4 * 1024; */;
+               f->fmt.pix.colorspace   = 0;
+               dprintk(0,"VIDIOC_TRY_FMT: w: %d, h: %d, f: %d\n",
+                       dev->width, dev->height, fh->mpegq.field );
+               return 0;
+       }
+       case VIDIOC_S_FMT:
+       {
+               struct v4l2_format *f = arg;
+
+               f->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
                f->fmt.pix.pixelformat  = V4L2_PIX_FMT_MPEG;
-               f->fmt.pix.field        = V4L2_FIELD_NONE;
                f->fmt.pix.bytesperline = 0;
-               f->fmt.pix.sizeimage    = 188 * 4 * 1024; /* 1024 * 512 */ /* FIXME: BUFFER_SIZE */;
+               f->fmt.pix.sizeimage    = dev->ts_packet_size * dev->ts_packet_count; /* 188 * 4 * 1024; */;
                f->fmt.pix.colorspace   = 0;
+               dprintk(0,"VIDIOC_S_FMT: w: %d, h: %d, f: %d\n",
+                       f->fmt.pix.width, f->fmt.pix.height, f->fmt.pix.field );
                return 0;
        }
 
@@ -985,6 +1479,22 @@ static int mpeg_do_ioctl(struct inode *inode, struct file *file,
        case VIDIOC_STREAMOFF:
                return videobuf_streamoff(&fh->mpegq);
 
+       /* --- mpeg compression -------------------------------------- */
+       case VIDIOC_G_MPEGCOMP:
+       {
+               struct v4l2_mpeg_compression *f = arg;
+
+               memcpy(f,&dev->params,sizeof(*f));
+               return 0;
+       }
+       case VIDIOC_S_MPEGCOMP:
+       {
+               struct v4l2_mpeg_compression *f = arg;
+
+               blackbird_set_params(dev, f);
+               return 0;
+       }
+
        default:
                return cx88_do_ioctl( inode, file, 0, dev->core, cmd, arg, cx88_ioctl_hook );
        }
@@ -1034,16 +1544,17 @@ static int mpeg_open(struct inode *inode, struct file *file)
        file->private_data = fh;
        fh->dev      = dev;
 
-       /* FIXME: locking against other video device */
-       cx88_set_scale(dev->core, dev->width, dev->height,
-                      V4L2_FIELD_INTERLACED);
-
        videobuf_queue_init(&fh->mpegq, &blackbird_qops,
                            dev->pci, &dev->slock,
                            V4L2_BUF_TYPE_VIDEO_CAPTURE,
-                           V4L2_FIELD_TOP,
+                           V4L2_FIELD_INTERLACED,
                            sizeof(struct cx88_buffer),
                            fh);
+
+       /* FIXME: locking against other video device */
+       cx88_set_scale(dev->core, dev->width, dev->height,
+                       fh->mpegq.field);
+
        return 0;
 }
 
@@ -1173,6 +1684,8 @@ static int __devinit blackbird_probe(struct pci_dev *pci_dev,
        dev->core = core;
        dev->width = 720;
        dev->height = 576;
+       memcpy(&dev->params,&default_mpeg_params,sizeof(default_mpeg_params));
+       memcpy(&dev->dnr_params,&default_dnr_params,sizeof(default_dnr_params));
 
        err = cx8802_init_common(dev);
        if (0 != err)
@@ -1199,7 +1712,7 @@ static int __devinit blackbird_probe(struct pci_dev *pci_dev,
 
 static void __devexit blackbird_remove(struct pci_dev *pci_dev)
 {
-        struct cx8802_dev *dev = pci_get_drvdata(pci_dev);
+       struct cx8802_dev *dev = pci_get_drvdata(pci_dev);
 
        /* blackbird */
        blackbird_unregister_video(dev);
@@ -1215,8 +1728,8 @@ static struct pci_device_id cx8802_pci_tbl[] = {
        {
                .vendor       = 0x14f1,
                .device       = 0x8802,
-                .subvendor    = PCI_ANY_ID,
-                .subdevice    = PCI_ANY_ID,
+               .subvendor    = PCI_ANY_ID,
+               .subdevice    = PCI_ANY_ID,
        },{
                /* --- end of list --- */
        }
@@ -1224,10 +1737,10 @@ static struct pci_device_id cx8802_pci_tbl[] = {
 MODULE_DEVICE_TABLE(pci, cx8802_pci_tbl);
 
 static struct pci_driver blackbird_pci_driver = {
-        .name     = "cx88-blackbird",
-        .id_table = cx8802_pci_tbl,
-        .probe    = blackbird_probe,
-        .remove   = __devexit_p(blackbird_remove),
+       .name     = "cx88-blackbird",
+       .id_table = cx8802_pci_tbl,
+       .probe    = blackbird_probe,
+       .remove   = __devexit_p(blackbird_remove),
        .suspend  = cx8802_suspend_common,
        .resume   = cx8802_resume_common,
 };
@@ -1257,6 +1770,8 @@ module_exit(blackbird_fini);
 
 EXPORT_SYMBOL(cx88_ioctl_hook);
 EXPORT_SYMBOL(cx88_ioctl_translator);
+EXPORT_SYMBOL(blackbird_set_params);
+EXPORT_SYMBOL(blackbird_set_dnr_params);
 
 /* ----------------------------------------------------------- */
 /*
index 4da91d535a5b0828fa3901d9a68502edb25da6eb..f2268631b7c01246546cbfb26e53eb28031d9bbe 100644 (file)
@@ -126,27 +126,27 @@ struct cx88_board cx88_boards[] = {
                .input          = {{
                        .type   = CX88_VMUX_TELEVISION,
                        .vmux   = 0,
-                        .gpio0  = 0x03ff,
+                       .gpio0  = 0x03ff,
                },{
                        .type   = CX88_VMUX_COMPOSITE1,
                        .vmux   = 1,
-                        .gpio0  = 0x03fe,
+                       .gpio0  = 0x03fe,
                },{
                        .type   = CX88_VMUX_SVIDEO,
                        .vmux   = 2,
-                        .gpio0  = 0x03fe,
+                       .gpio0  = 0x03fe,
                }},
        },
-        [CX88_BOARD_WINFAST2000XP_EXPERT] = {
-                .name           = "Leadtek Winfast 2000XP Expert",
-                .tuner_type     = TUNER_PHILIPS_4IN1,
+       [CX88_BOARD_WINFAST2000XP_EXPERT] = {
+               .name           = "Leadtek Winfast 2000XP Expert",
+               .tuner_type     = TUNER_PHILIPS_4IN1,
                .radio_type     = UNSET,
                .tuner_addr     = ADDR_UNSET,
                .radio_addr     = ADDR_UNSET,
                .tda9887_conf   = TDA9887_PRESENT,
-                .input          = {{
-                        .type   = CX88_VMUX_TELEVISION,
-                        .vmux   = 0,
+               .input          = {{
+                       .type   = CX88_VMUX_TELEVISION,
+                       .vmux   = 0,
                        .gpio0  = 0x00F5e700,
                        .gpio1  = 0x00003004,
                        .gpio2  = 0x00F5e700,
@@ -165,16 +165,16 @@ struct cx88_board cx88_boards[] = {
                        .gpio1  = 0x00003004,
                        .gpio2  = 0x00F5c700,
                        .gpio3  = 0x02000000,
-                }},
-                .radio = {
-                        .type   = CX88_RADIO,
+               }},
+               .radio = {
+                       .type   = CX88_RADIO,
                        .gpio0  = 0x00F5d700,
                        .gpio1  = 0x00003004,
                        .gpio2  = 0x00F5d700,
                        .gpio3  = 0x02000000,
-                },
-        },
-       [CX88_BOARD_AVERTV_303] = {
+               },
+       },
+       [CX88_BOARD_AVERTV_STUDIO_303] = {
                .name           = "AverTV Studio 303 (M126)",
                .tuner_type     = TUNER_PHILIPS_FM1216ME_MK3,
                .radio_type     = UNSET,
@@ -206,7 +206,7 @@ struct cx88_board cx88_boards[] = {
                .radio_type     = UNSET,
                .tuner_addr     = ADDR_UNSET,
                .radio_addr     = ADDR_UNSET,
-               .tda9887_conf   = TDA9887_PRESENT,
+               .tda9887_conf   = TDA9887_PRESENT | TDA9887_INTERCARRIER_NTSC,
                .input          = {{
                        .type   = CX88_VMUX_TELEVISION,
                        .vmux   = 0,
@@ -214,32 +214,32 @@ struct cx88_board cx88_boards[] = {
                        .gpio1  = 0x000080c0,
                        .gpio2  = 0x0000ff40,
                },{
-                        .type   = CX88_VMUX_COMPOSITE1,
-                        .vmux   = 1,
+                       .type   = CX88_VMUX_COMPOSITE1,
+                       .vmux   = 1,
                        .gpio0  = 0x000040bf,
                        .gpio1  = 0x000080c0,
                        .gpio2  = 0x0000ff40,
                },{
-                        .type   = CX88_VMUX_SVIDEO,
-                        .vmux   = 2,
+                       .type   = CX88_VMUX_SVIDEO,
+                       .vmux   = 2,
                        .gpio0  = 0x000040bf,
                        .gpio1  = 0x000080c0,
                        .gpio2  = 0x0000ff40,
-                }},
-                .radio = {
+               }},
+               .radio = {
                         .type   = CX88_RADIO,
-                },
+               },
        },
        [CX88_BOARD_WINFAST_DV2000] = {
-                .name           = "Leadtek Winfast DV2000",
-                .tuner_type     = TUNER_PHILIPS_FM1216ME_MK3,
+               .name           = "Leadtek Winfast DV2000",
+               .tuner_type     = TUNER_PHILIPS_FM1216ME_MK3,
                .radio_type     = UNSET,
                .tuner_addr     = ADDR_UNSET,
                .radio_addr     = ADDR_UNSET,
                .tda9887_conf   = TDA9887_PRESENT,
-                .input          = {{
-                        .type   = CX88_VMUX_TELEVISION,
-                        .vmux   = 0,
+               .input          = {{
+                       .type   = CX88_VMUX_TELEVISION,
+                       .vmux   = 0,
                        .gpio0  = 0x0035e700,
                        .gpio1  = 0x00003004,
                        .gpio2  = 0x0035e700,
@@ -260,14 +260,14 @@ struct cx88_board cx88_boards[] = {
                        .gpio2  = 0x02000000,
                        .gpio3  = 0x02000000,
                }},
-                .radio = {
+               .radio = {
                        .type   = CX88_RADIO,
                        .gpio0  = 0x0035d700,
                        .gpio1  = 0x00007004,
                        .gpio2  = 0x0035d700,
                        .gpio3  = 0x02000000,
                 },
-        },
+       },
        [CX88_BOARD_LEADTEK_PVR2000] = {
                // gpio values for PAL version from regspy by DScaler
                .name           = "Leadtek PVR 2000",
@@ -296,25 +296,25 @@ struct cx88_board cx88_boards[] = {
                .blackbird = 1,
        },
        [CX88_BOARD_IODATA_GVVCP3PCI] = {
-               .name           = "IODATA GV-VCP3/PCI",
+               .name           = "IODATA GV-VCP3/PCI",
                .tuner_type     = TUNER_ABSENT,
-               .radio_type     = UNSET,
+               .radio_type     = UNSET,
                .tuner_addr     = ADDR_UNSET,
                .radio_addr     = ADDR_UNSET,
                .input          = {{
-                       .type   = CX88_VMUX_COMPOSITE1,
-                       .vmux   = 0,
-               },{
-                       .type   = CX88_VMUX_COMPOSITE2,
-                       .vmux   = 1,
-               },{
-                       .type   = CX88_VMUX_SVIDEO,
-                       .vmux   = 2,
-               }},
-       },
+                       .type   = CX88_VMUX_COMPOSITE1,
+                       .vmux   = 0,
+               },{
+                       .type   = CX88_VMUX_COMPOSITE2,
+                       .vmux   = 1,
+               },{
+                       .type   = CX88_VMUX_SVIDEO,
+                       .vmux   = 2,
+               }},
+       },
        [CX88_BOARD_PROLINK_PLAYTVPVR] = {
-                .name           = "Prolink PlayTV PVR",
-                .tuner_type     = TUNER_PHILIPS_FM1236_MK3,
+               .name           = "Prolink PlayTV PVR",
+               .tuner_type     = TUNER_PHILIPS_FM1236_MK3,
                .radio_type     = UNSET,
                .tuner_addr     = ADDR_UNSET,
                .radio_addr     = ADDR_UNSET,
@@ -348,15 +348,15 @@ struct cx88_board cx88_boards[] = {
                        .type   = CX88_VMUX_TELEVISION,
                        .vmux   = 0,
                        .gpio0  = 0x0000fde6,
-               },{
+               },{
                        .type   = CX88_VMUX_SVIDEO,
                        .vmux   = 2,
                        .gpio0  = 0x0000fde6, // 0x0000fda6 L,R RCA audio in?
                }},
-                .radio = {
-                        .type   = CX88_RADIO,
+               .radio = {
+                       .type   = CX88_RADIO,
                        .gpio0  = 0x0000fde2,
-                },
+               },
                .blackbird = 1,
        },
        [CX88_BOARD_MSI_TVANYWHERE] = {
@@ -372,34 +372,34 @@ struct cx88_board cx88_boards[] = {
                        .gpio0  = 0x00000fbf,
                        .gpio2  = 0x0000fc08,
                },{
-                       .type   = CX88_VMUX_COMPOSITE1,
-                       .vmux   = 1,
+                       .type   = CX88_VMUX_COMPOSITE1,
+                       .vmux   = 1,
                        .gpio0  = 0x00000fbf,
                        .gpio2  = 0x0000fc68,
                },{
-                       .type   = CX88_VMUX_SVIDEO,
-                       .vmux   = 2,
+                       .type   = CX88_VMUX_SVIDEO,
+                       .vmux   = 2,
                        .gpio0  = 0x00000fbf,
                        .gpio2  = 0x0000fc68,
-               }},
+               }},
        },
-        [CX88_BOARD_KWORLD_DVB_T] = {
-                .name           = "KWorld/VStream XPert DVB-T",
+       [CX88_BOARD_KWORLD_DVB_T] = {
+               .name           = "KWorld/VStream XPert DVB-T",
                .tuner_type     = TUNER_ABSENT,
                .radio_type     = UNSET,
                .tuner_addr     = ADDR_UNSET,
                .radio_addr     = ADDR_UNSET,
-                .input          = {{
-                        .type   = CX88_VMUX_COMPOSITE1,
-                        .vmux   = 1,
+               .input          = {{
+                       .type   = CX88_VMUX_COMPOSITE1,
+                       .vmux   = 1,
                        .gpio0  = 0x0700,
                        .gpio2  = 0x0101,
-                },{
-                        .type   = CX88_VMUX_SVIDEO,
-                        .vmux   = 2,
+               },{
+                       .type   = CX88_VMUX_SVIDEO,
+                       .vmux   = 2,
                        .gpio0  = 0x0700,
                        .gpio2  = 0x0101,
-                }},
+               }},
                .dvb            = 1,
        },
        [CX88_BOARD_DVICO_FUSIONHDTV_DVB_T1] = {
@@ -425,27 +425,27 @@ struct cx88_board cx88_boards[] = {
                .radio_type     = UNSET,
                .tuner_addr     = ADDR_UNSET,
                .radio_addr     = ADDR_UNSET,
-                .input          = {{
-                        .type   = CX88_VMUX_TELEVISION,
-                        .vmux   = 0,
-                        .gpio0  = 0x07f8,
+               .input          = {{
+                       .type   = CX88_VMUX_TELEVISION,
+                       .vmux   = 0,
+                       .gpio0  = 0x07f8,
                },{
                        .type   = CX88_VMUX_DEBUG,
                        .vmux   = 0,
                        .gpio0  = 0x07f9,  // mono from tuner chip
-                },{
-                        .type   = CX88_VMUX_COMPOSITE1,
-                        .vmux   = 1,
-                        .gpio0  = 0x000007fa,
-                },{
-                        .type   = CX88_VMUX_SVIDEO,
-                        .vmux   = 2,
-                        .gpio0  = 0x000007fa,
-                }},
-                .radio = {
-                        .type   = CX88_RADIO,
-                        .gpio0  = 0x000007f8,
-                },
+               },{
+                       .type   = CX88_VMUX_COMPOSITE1,
+                       .vmux   = 1,
+                       .gpio0  = 0x000007fa,
+               },{
+                       .type   = CX88_VMUX_SVIDEO,
+                       .vmux   = 2,
+                       .gpio0  = 0x000007fa,
+               }},
+               .radio = {
+                       .type   = CX88_RADIO,
+                       .gpio0  = 0x000007f8,
+               },
        },
        [CX88_BOARD_DVICO_FUSIONHDTV_3_GOLD_Q] = {
                .name           = "DViCO FusionHDTV 3 Gold-Q",
@@ -489,28 +489,28 @@ struct cx88_board cx88_boards[] = {
                }},
                .dvb            = 1,
        },
-        [CX88_BOARD_HAUPPAUGE_DVB_T1] = {
+       [CX88_BOARD_HAUPPAUGE_DVB_T1] = {
                .name           = "Hauppauge Nova-T DVB-T",
                .tuner_type     = TUNER_ABSENT,
                .radio_type     = UNSET,
                .tuner_addr     = ADDR_UNSET,
                .radio_addr     = ADDR_UNSET,
                .input          = {{
-                        .type   = CX88_VMUX_DVB,
-                        .vmux   = 0,
-                }},
+                       .type   = CX88_VMUX_DVB,
+                       .vmux   = 0,
+               }},
                .dvb            = 1,
        },
-        [CX88_BOARD_CONEXANT_DVB_T1] = {
+       [CX88_BOARD_CONEXANT_DVB_T1] = {
                .name           = "Conexant DVB-T reference design",
                .tuner_type     = TUNER_ABSENT,
                .radio_type     = UNSET,
                .tuner_addr     = ADDR_UNSET,
                .radio_addr     = ADDR_UNSET,
-                .input          = {{
-                        .type   = CX88_VMUX_DVB,
-                        .vmux   = 0,
-                }},
+               .input          = {{
+                       .type   = CX88_VMUX_DVB,
+                       .vmux   = 0,
+               }},
                .dvb            = 1,
        },
        [CX88_BOARD_PROVIDEO_PV259] = {
@@ -543,12 +543,12 @@ struct cx88_board cx88_boards[] = {
                .dvb            = 1,
        },
        [CX88_BOARD_DNTV_LIVE_DVB_T] = {
-               .name           = "digitalnow DNTV Live! DVB-T",
+               .name           = "digitalnow DNTV Live! DVB-T",
                .tuner_type     = TUNER_ABSENT,
                .radio_type     = UNSET,
                .tuner_addr     = ADDR_UNSET,
                .radio_addr     = ADDR_UNSET,
-               .input          = {{
+               .input          = {{
                        .type   = CX88_VMUX_COMPOSITE1,
                        .vmux   = 1,
                        .gpio0  = 0x00000700,
@@ -705,44 +705,44 @@ struct cx88_board cx88_boards[] = {
                         .gpio0 = 0xbf60,
                 },
        },
-        [CX88_BOARD_DVICO_FUSIONHDTV_3_GOLD_T] = {
+       [CX88_BOARD_DVICO_FUSIONHDTV_3_GOLD_T] = {
                .name           = "DViCO FusionHDTV 3 Gold-T",
                .tuner_type     = TUNER_THOMSON_DTT7611,
                .radio_type     = UNSET,
                .tuner_addr     = ADDR_UNSET,
                .radio_addr     = ADDR_UNSET,
                .input          = {{
-                        .type   = CX88_VMUX_TELEVISION,
-                        .vmux   = 0,
-                        .gpio0  = 0x97ed,
-                },{
-                        .type   = CX88_VMUX_COMPOSITE1,
-                        .vmux   = 1,
-                        .gpio0  = 0x97e9,
-                },{
-                        .type   = CX88_VMUX_SVIDEO,
-                        .vmux   = 2,
-                        .gpio0  = 0x97e9,
-                }},
+                       .type   = CX88_VMUX_TELEVISION,
+                       .vmux   = 0,
+                       .gpio0  = 0x97ed,
+               },{
+                       .type   = CX88_VMUX_COMPOSITE1,
+                       .vmux   = 1,
+                       .gpio0  = 0x97e9,
+               },{
+                       .type   = CX88_VMUX_SVIDEO,
+                       .vmux   = 2,
+                       .gpio0  = 0x97e9,
+               }},
                .dvb            = 1,
-        },
-        [CX88_BOARD_ADSTECH_DVB_T_PCI] = {
-                .name           = "ADS Tech Instant TV DVB-T PCI",
+       },
+       [CX88_BOARD_ADSTECH_DVB_T_PCI] = {
+               .name           = "ADS Tech Instant TV DVB-T PCI",
                .tuner_type     = TUNER_ABSENT,
                .radio_type     = UNSET,
                .tuner_addr     = ADDR_UNSET,
                .radio_addr     = ADDR_UNSET,
                .input          = {{
-                        .type   = CX88_VMUX_COMPOSITE1,
-                        .vmux   = 1,
+                       .type   = CX88_VMUX_COMPOSITE1,
+                       .vmux   = 1,
                        .gpio0  = 0x0700,
                        .gpio2  = 0x0101,
-                },{
-                        .type   = CX88_VMUX_SVIDEO,
-                        .vmux   = 2,
+               },{
+                       .type   = CX88_VMUX_SVIDEO,
+                       .vmux   = 2,
                        .gpio0  = 0x0700,
                        .gpio2  = 0x0101,
-                }},
+               }},
                .dvb            = 1,
        },
        [CX88_BOARD_TERRATEC_CINERGY_1400_DVB_T1] = {
@@ -762,20 +762,139 @@ struct cx88_board cx88_boards[] = {
                .radio_addr     = ADDR_UNSET,
                .tda9887_conf   = TDA9887_PRESENT,
                .input          = {{
-                        .type   = CX88_VMUX_TELEVISION,
-                        .vmux   = 0,
-                        .gpio0  = 0x87fd,
-                },{
-                        .type   = CX88_VMUX_COMPOSITE1,
-                        .vmux   = 1,
-                        .gpio0  = 0x87f9,
-                },{
-                        .type   = CX88_VMUX_SVIDEO,
-                        .vmux   = 2,
-                        .gpio0  = 0x87f9,
-                }},
+                       .type   = CX88_VMUX_TELEVISION,
+                       .vmux   = 0,
+                       .gpio0  = 0x87fd,
+               },{
+                       .type   = CX88_VMUX_COMPOSITE1,
+                       .vmux   = 1,
+                       .gpio0  = 0x87f9,
+               },{
+                       .type   = CX88_VMUX_SVIDEO,
+                       .vmux   = 2,
+                       .gpio0  = 0x87f9,
+               }},
+               .dvb            = 1,
+       },
+       [CX88_BOARD_AVERMEDIA_ULTRATV_MC_550] = {
+               .name           = "AverMedia UltraTV Media Center PCI 550",
+               .tuner_type     = TUNER_PHILIPS_FM1236_MK3,
+               .radio_type     = UNSET,
+               .tuner_addr     = ADDR_UNSET,
+               .radio_addr     = ADDR_UNSET,
+               .tda9887_conf   = TDA9887_PRESENT,
+               .blackbird      = 1,
+               .input          = {{
+                       .type   = CX88_VMUX_COMPOSITE1,
+                       .vmux   = 0,
+                       .gpio0  = 0x0000cd73,
+               },{
+                       .type   = CX88_VMUX_SVIDEO,
+                       .vmux   = 1,
+                       .gpio0  = 0x0000cd73,
+               },{
+                       .type   = CX88_VMUX_TELEVISION,
+                       .vmux   = 3,
+                       .gpio0  = 0x0000cdb3,
+               }},
+               .radio = {
+                       .type   = CX88_RADIO,
+                       .vmux   = 2,
+                       .gpio0  = 0x0000cdf3,
+               },
+       },
+       [CX88_BOARD_KWORLD_VSTREAM_EXPERT_DVD] = {
+                /* Alexander Wold <awold@bigfoot.com> */
+                .name           = "Kworld V-Stream Xpert DVD",
+                .tuner_type     = UNSET,
+                .input          = {{
+                        .type   = CX88_VMUX_COMPOSITE1,
+                        .vmux   = 1,
+                        .gpio0  = 0x03000000,
+                        .gpio1  = 0x01000000,
+                        .gpio2  = 0x02000000,
+                        .gpio3  = 0x00100000,
+                },{
+                        .type   = CX88_VMUX_SVIDEO,
+                        .vmux   = 2,
+                        .gpio0  = 0x03000000,
+                        .gpio1  = 0x01000000,
+                        .gpio2  = 0x02000000,
+                        .gpio3  = 0x00100000,
+                }},
+       },
+       [CX88_BOARD_ATI_HDTVWONDER] = {
+               .name           = "ATI HDTV Wonder",
+               .tuner_type     = TUNER_PHILIPS_TUV1236D,
+               .radio_type     = UNSET,
+               .tuner_addr     = ADDR_UNSET,
+               .radio_addr     = ADDR_UNSET,
+               .input          = {{
+                       .type   = CX88_VMUX_TELEVISION,
+                       .vmux   = 0,
+                       .gpio0  = 0x00000ff7,
+                       .gpio1  = 0x000000ff,
+                       .gpio2  = 0x00000001,
+                       .gpio3  = 0x00000000,
+               },{
+                       .type   = CX88_VMUX_COMPOSITE1,
+                       .vmux   = 1,
+                       .gpio0  = 0x00000ffe,
+                       .gpio1  = 0x000000ff,
+                       .gpio2  = 0x00000001,
+                       .gpio3  = 0x00000000,
+               },{
+                       .type   = CX88_VMUX_SVIDEO,
+                       .vmux   = 2,
+                       .gpio0  = 0x00000ffe,
+                       .gpio1  = 0x000000ff,
+                       .gpio2  = 0x00000001,
+                       .gpio3  = 0x00000000,
+               }},
                .dvb            = 1,
        },
+       [CX88_BOARD_WINFAST_DTV1000] = {
+               .name           = "WinFast DTV1000-T",
+               .tuner_type     = TUNER_ABSENT,
+               .radio_type     = UNSET,
+               .tuner_addr     = ADDR_UNSET,
+               .radio_addr     = ADDR_UNSET,
+               .input          = {{
+                       .type   = CX88_VMUX_DVB,
+                       .vmux   = 0,
+               }},
+               .dvb            = 1,
+       },
+       [CX88_BOARD_AVERTV_303] = {
+               .name           = "AVerTV 303 (M126)",
+               .tuner_type     = TUNER_PHILIPS_FM1216ME_MK3,
+               .radio_type     = UNSET,
+               .tuner_addr     = ADDR_UNSET,
+               .radio_addr     = ADDR_UNSET,
+               .tda9887_conf   = TDA9887_PRESENT,
+               .input          = {{
+                       .type   = CX88_VMUX_TELEVISION,
+                       .vmux   = 0,
+                       .gpio0  = 0x00ff,
+                       .gpio1  = 0xe09f,
+                       .gpio2  = 0x0010,
+                       .gpio3  = 0x0000,
+               },{
+                       .type   = CX88_VMUX_COMPOSITE1,
+                       .vmux   = 1,
+                       .gpio0  = 0x00ff,
+                       .gpio1  = 0xe05f,
+                       .gpio2  = 0x0010,
+                       .gpio3  = 0x0000,
+               },{
+                       .type   = CX88_VMUX_SVIDEO,
+                       .vmux   = 2,
+                       .gpio0  = 0x00ff,
+                       .gpio1  = 0xe05f,
+                       .gpio2  = 0x0010,
+                       .gpio3  = 0x0000,
+               }},
+       },
 };
 const unsigned int cx88_bcount = ARRAY_SIZE(cx88_boards);
 
@@ -804,41 +923,41 @@ struct cx88_subid cx88_subids[] = {
                .subdevice = 0x00f8,
                .card      = CX88_BOARD_ATI_WONDER_PRO,
        },{
-                .subvendor = 0x107d,
-                .subdevice = 0x6611,
-                .card      = CX88_BOARD_WINFAST2000XP_EXPERT,
+               .subvendor = 0x107d,
+               .subdevice = 0x6611,
+               .card      = CX88_BOARD_WINFAST2000XP_EXPERT,
+       },{
+               .subvendor = 0x107d,
+               .subdevice = 0x6613,    /* NTSC */
+               .card      = CX88_BOARD_WINFAST2000XP_EXPERT,
        },{
-                .subvendor = 0x107d,
-                .subdevice = 0x6613,   /* NTSC */
-                .card      = CX88_BOARD_WINFAST2000XP_EXPERT,
+               .subvendor = 0x107d,
+               .subdevice = 0x6620,
+               .card      = CX88_BOARD_WINFAST_DV2000,
+       },{
+               .subvendor = 0x107d,
+               .subdevice = 0x663b,
+               .card      = CX88_BOARD_LEADTEK_PVR2000,
        },{
                .subvendor = 0x107d,
-                .subdevice = 0x6620,
-                .card      = CX88_BOARD_WINFAST_DV2000,
-        },{
-                .subvendor = 0x107d,
-                .subdevice = 0x663b,
-                .card      = CX88_BOARD_LEADTEK_PVR2000,
-        },{
-                .subvendor = 0x107d,
-                .subdevice = 0x663C,
-                .card      = CX88_BOARD_LEADTEK_PVR2000,
-        },{
+               .subdevice = 0x663C,
+               .card      = CX88_BOARD_LEADTEK_PVR2000,
+       },{
                .subvendor = 0x1461,
                .subdevice = 0x000b,
-               .card      = CX88_BOARD_AVERTV_303,
+               .card      = CX88_BOARD_AVERTV_STUDIO_303,
        },{
                .subvendor = 0x1462,
                .subdevice = 0x8606,
                .card      = CX88_BOARD_MSI_TVANYWHERE_MASTER,
        },{
-               .subvendor = 0x10fc,
-               .subdevice = 0xd003,
-               .card      = CX88_BOARD_IODATA_GVVCP3PCI,
+               .subvendor = 0x10fc,
+               .subdevice = 0xd003,
+               .card      = CX88_BOARD_IODATA_GVVCP3PCI,
        },{
-               .subvendor = 0x1043,
-               .subdevice = 0x4823,  /* with mpeg encoder */
-               .card      = CX88_BOARD_ASUS_PVR_416,
+               .subvendor = 0x1043,
+               .subdevice = 0x4823,  /* with mpeg encoder */
+               .card      = CX88_BOARD_ASUS_PVR_416,
        },{
                .subvendor = 0x17de,
                .subdevice = 0x08a6,
@@ -852,43 +971,43 @@ struct cx88_subid cx88_subids[] = {
                .subdevice = 0xd820,
                .card      = CX88_BOARD_DVICO_FUSIONHDTV_3_GOLD_T,
        },{
-               .subvendor = 0x18AC,
-               .subdevice = 0xDB00,
+               .subvendor = 0x18ac,
+               .subdevice = 0xdb00,
                .card      = CX88_BOARD_DVICO_FUSIONHDTV_DVB_T1,
-       },{
+       },{
                .subvendor = 0x0070,
                .subdevice = 0x9002,
                .card      = CX88_BOARD_HAUPPAUGE_DVB_T1,
-       },{
+       },{
                .subvendor = 0x14f1,
                .subdevice = 0x0187,
                .card      = CX88_BOARD_CONEXANT_DVB_T1,
-       },{
+       },{
                .subvendor = 0x1540,
                .subdevice = 0x2580,
                .card      = CX88_BOARD_PROVIDEO_PV259,
        },{
-               .subvendor = 0x18AC,
-               .subdevice = 0xDB10,
+               .subvendor = 0x18ac,
+               .subdevice = 0xdb10,
                .card      = CX88_BOARD_DVICO_FUSIONHDTV_DVB_T_PLUS,
        },{
-                .subvendor = 0x1554,
-                .subdevice = 0x4811,
-                .card      = CX88_BOARD_PIXELVIEW,
+               .subvendor = 0x1554,
+               .subdevice = 0x4811,
+               .card      = CX88_BOARD_PIXELVIEW,
        },{
                .subvendor = 0x7063,
                .subdevice = 0x3000, /* HD-3000 card */
                .card      = CX88_BOARD_PCHDTV_HD3000,
        },{
-               .subvendor = 0x17DE,
-               .subdevice = 0xA8A6,
+               .subvendor = 0x17de,
+               .subdevice = 0xa8a6,
                .card      = CX88_BOARD_DNTV_LIVE_DVB_T,
        },{
                .subvendor = 0x0070,
                .subdevice = 0x2801,
                .card      = CX88_BOARD_HAUPPAUGE_ROSLYN,
        },{
-               .subvendor = 0x14F1,
+               .subvendor = 0x14f1,
                .subdevice = 0x0342,
                .card      = CX88_BOARD_DIGITALLOGIC_MEC,
        },{
@@ -899,14 +1018,30 @@ struct cx88_subid cx88_subids[] = {
                .subvendor = 0x1421,
                .subdevice = 0x0334,
                .card      = CX88_BOARD_ADSTECH_DVB_T_PCI,
-       },{
+       },{
                .subvendor = 0x153b,
                .subdevice = 0x1166,
                .card      = CX88_BOARD_TERRATEC_CINERGY_1400_DVB_T1,
-       },{
+       },{
                .subvendor = 0x18ac,
                .subdevice = 0xd500,
                .card      = CX88_BOARD_DVICO_FUSIONHDTV_5_GOLD,
+       },{
+               .subvendor = 0x1461,
+               .subdevice = 0x8011,
+               .card      = CX88_BOARD_AVERMEDIA_ULTRATV_MC_550,
+       },{
+               .subvendor = PCI_VENDOR_ID_ATI,
+               .subdevice = 0xa101,
+               .card      = CX88_BOARD_ATI_HDTVWONDER,
+       },{
+               .subvendor = 0x107d,
+               .subdevice = 0x665f,
+               .card      = CX88_BOARD_WINFAST_DTV1000,
+       },{
+               .subvendor = 0x1461,
+               .subdevice = 0x000a,
+               .card      = CX88_BOARD_AVERTV_303,
        },
 };
 const unsigned int cx88_idcount = ARRAY_SIZE(cx88_subids);
@@ -1108,6 +1243,19 @@ void cx88_card_setup(struct cx88_core *core)
                cx_clear(MO_GP0_IO, 0x00000007);
                cx_set(MO_GP2_IO, 0x00000101);
                break;
+       case CX88_BOARD_ATI_HDTVWONDER:
+               if (0 == core->i2c_rc) {
+                       /* enable tuner */
+                       int i;
+                       u8 buffer [] = { 0x10,0x12,0x13,0x04,0x16,0x00,0x14,0x04,0x017,0x00 };
+                       core->i2c_client.addr = 0x0a;
+
+                       for (i = 0; i < 5; i++)
+                               if (2 != i2c_master_send(&core->i2c_client,&buffer[i*2],2))
+                                       printk(KERN_WARNING "%s: Unable to enable tuner(%i).\n",
+                                               core->name, i);
+               }
+               break;
        }
        if (cx88_boards[core->board].radio.type == CX88_RADIO)
                core->has_radio = 1;
index dc5c5c1f3461125234d021ed4fdbd79ae72bc2af..eb806af17182ad9c9489ff6008be4f8123f58021 100644 (file)
@@ -31,7 +31,7 @@
 #include <linux/interrupt.h>
 #include <linux/pci.h>
 #include <linux/delay.h>
-#include <linux/videodev.h>
+#include <linux/videodev2.h>
 
 #include "cx88.h"
 
@@ -153,26 +153,26 @@ static u32* cx88_risc_field(u32 *rp, struct scatterlist *sglist,
                }
                if (bpl <= sg_dma_len(sg)-offset) {
                        /* fits into current chunk */
-                        *(rp++)=cpu_to_le32(RISC_WRITE|RISC_SOL|RISC_EOL|bpl);
-                        *(rp++)=cpu_to_le32(sg_dma_address(sg)+offset);
-                        offset+=bpl;
+                       *(rp++)=cpu_to_le32(RISC_WRITE|RISC_SOL|RISC_EOL|bpl);
+                       *(rp++)=cpu_to_le32(sg_dma_address(sg)+offset);
+                       offset+=bpl;
                } else {
                        /* scanline needs to be splitted */
-                        todo = bpl;
-                        *(rp++)=cpu_to_le32(RISC_WRITE|RISC_SOL|
+                       todo = bpl;
+                       *(rp++)=cpu_to_le32(RISC_WRITE|RISC_SOL|
                                            (sg_dma_len(sg)-offset));
-                        *(rp++)=cpu_to_le32(sg_dma_address(sg)+offset);
-                        todo -= (sg_dma_len(sg)-offset);
-                        offset = 0;
-                        sg++;
-                        while (todo > sg_dma_len(sg)) {
-                                *(rp++)=cpu_to_le32(RISC_WRITE|
+                       *(rp++)=cpu_to_le32(sg_dma_address(sg)+offset);
+                       todo -= (sg_dma_len(sg)-offset);
+                       offset = 0;
+                       sg++;
+                       while (todo > sg_dma_len(sg)) {
+                               *(rp++)=cpu_to_le32(RISC_WRITE|
                                                    sg_dma_len(sg));
-                                *(rp++)=cpu_to_le32(sg_dma_address(sg));
+                               *(rp++)=cpu_to_le32(sg_dma_address(sg));
                                todo -= sg_dma_len(sg);
                                sg++;
                        }
-                        *(rp++)=cpu_to_le32(RISC_WRITE|RISC_EOL|todo);
+                       *(rp++)=cpu_to_le32(RISC_WRITE|RISC_EOL|todo);
                        *(rp++)=cpu_to_le32(sg_dma_address(sg));
                        offset += todo;
                }
@@ -309,7 +309,7 @@ struct sram_channel cx88_sram_channels[] = {
                .name       = "video y / packed",
                .cmds_start = 0x180040,
                .ctrl_start = 0x180400,
-               .cdt        = 0x180400 + 64,
+               .cdt        = 0x180400 + 64,
                .fifo_start = 0x180c00,
                .fifo_size  = 0x002800,
                .ptr1_reg   = MO_DMA21_PTR1,
@@ -321,7 +321,7 @@ struct sram_channel cx88_sram_channels[] = {
                .name       = "video u",
                .cmds_start = 0x180080,
                .ctrl_start = 0x1804a0,
-               .cdt        = 0x1804a0 + 64,
+               .cdt        = 0x1804a0 + 64,
                .fifo_start = 0x183400,
                .fifo_size  = 0x000800,
                .ptr1_reg   = MO_DMA22_PTR1,
@@ -333,7 +333,7 @@ struct sram_channel cx88_sram_channels[] = {
                .name       = "video v",
                .cmds_start = 0x1800c0,
                .ctrl_start = 0x180540,
-               .cdt        = 0x180540 + 64,
+               .cdt        = 0x180540 + 64,
                .fifo_start = 0x183c00,
                .fifo_size  = 0x000800,
                .ptr1_reg   = MO_DMA23_PTR1,
@@ -345,7 +345,7 @@ struct sram_channel cx88_sram_channels[] = {
                .name       = "vbi",
                .cmds_start = 0x180100,
                .ctrl_start = 0x1805e0,
-               .cdt        = 0x1805e0 + 64,
+               .cdt        = 0x1805e0 + 64,
                .fifo_start = 0x184400,
                .fifo_size  = 0x001000,
                .ptr1_reg   = MO_DMA24_PTR1,
@@ -357,7 +357,7 @@ struct sram_channel cx88_sram_channels[] = {
                .name       = "audio from",
                .cmds_start = 0x180140,
                .ctrl_start = 0x180680,
-               .cdt        = 0x180680 + 64,
+               .cdt        = 0x180680 + 64,
                .fifo_start = 0x185400,
                .fifo_size  = 0x000200,
                .ptr1_reg   = MO_DMA25_PTR1,
@@ -369,7 +369,7 @@ struct sram_channel cx88_sram_channels[] = {
                .name       = "audio to",
                .cmds_start = 0x180180,
                .ctrl_start = 0x180720,
-               .cdt        = 0x180680 + 64,  /* same as audio IN */
+               .cdt        = 0x180680 + 64,  /* same as audio IN */
                .fifo_start = 0x185400,       /* same as audio IN */
                .fifo_size  = 0x000200,       /* same as audio IN */
                .ptr1_reg   = MO_DMA26_PTR1,
@@ -431,7 +431,7 @@ int cx88_sram_channel_setup(struct cx88_core *core,
 /* ------------------------------------------------------------------ */
 /* debug helper code                                                  */
 
-int cx88_risc_decode(u32 risc)
+static int cx88_risc_decode(u32 risc)
 {
        static char *instr[16] = {
                [ RISC_SYNC    >> 28 ] = "sync",
@@ -845,19 +845,19 @@ static int set_tvaudio(struct cx88_core *core)
                return 0;
 
        if (V4L2_STD_PAL_BG & norm->id) {
-               core->tvaudio = nicam ? WW_NICAM_BGDKL : WW_A2_BG;
+               core->tvaudio = WW_BG;
 
        } else if (V4L2_STD_PAL_DK & norm->id) {
-               core->tvaudio = nicam ? WW_NICAM_BGDKL : WW_A2_DK;
+               core->tvaudio = WW_DK;
 
        } else if (V4L2_STD_PAL_I & norm->id) {
-               core->tvaudio = WW_NICAM_I;
+               core->tvaudio = WW_I;
 
        } else if (V4L2_STD_SECAM_L & norm->id) {
-               core->tvaudio = WW_SYSTEM_L_AM;
+               core->tvaudio = WW_L;
 
        } else if (V4L2_STD_SECAM_DK & norm->id) {
-               core->tvaudio = WW_A2_DK;
+               core->tvaudio = WW_DK;
 
        } else if ((V4L2_STD_NTSC_M & norm->id) ||
                   (V4L2_STD_PAL_M  & norm->id)) {
@@ -1137,7 +1137,7 @@ struct cx88_core* cx88_core_get(struct pci_dev *pci)
        if (!core->radio_addr)
                core->radio_addr = cx88_boards[core->board].radio_addr;
 
-        printk(KERN_INFO "TV tuner %d at 0x%02x, Radio tuner %d at 0x%02x\n",
+       printk(KERN_INFO "TV tuner %d at 0x%02x, Radio tuner %d at 0x%02x\n",
                core->tuner_type, core->tuner_addr<<1,
                core->radio_type, core->radio_addr<<1);
 
@@ -1146,6 +1146,7 @@ struct cx88_core* cx88_core_get(struct pci_dev *pci)
        /* init hardware */
        cx88_reset(core);
        cx88_i2c_init(core,pci);
+       cx88_call_i2c_clients (core, TUNER_SET_STANDBY, NULL);
        cx88_card_setup(core);
        cx88_ir_init(core,pci);
 
index 4334744652de0b22c23122fa311190ff217e02e1..9cce91ec334be22dea666fd84bf8903a78e1c97b 100644 (file)
@@ -29,7 +29,6 @@
 #include <linux/file.h>
 #include <linux/suspend.h>
 
-
 #include "cx88.h"
 #include "dvb-pll.h"
 
@@ -46,6 +45,9 @@
 #ifdef HAVE_LGDT330X
 # include "lgdt330x.h"
 #endif
+#ifdef HAVE_NXT200X
+# include "nxt200x.h"
+#endif
 
 MODULE_DESCRIPTION("driver for cx2388x based DVB cards");
 MODULE_AUTHOR("Chris Pascoe <c.pascoe@itee.uq.edu.au>");
@@ -78,7 +80,7 @@ static int dvb_buf_prepare(struct videobuf_queue *q, struct videobuf_buffer *vb,
                           enum v4l2_field field)
 {
        struct cx8802_dev *dev = q->priv_data;
-       return cx8802_buf_prepare(dev, (struct cx88_buffer*)vb);
+       return cx8802_buf_prepare(dev, (struct cx88_buffer*)vb,field);
 }
 
 static void dvb_buf_queue(struct videobuf_queue *q, struct videobuf_buffer *vb)
@@ -129,7 +131,7 @@ static int dntv_live_dvbt_demod_init(struct dvb_frontend* fe)
        static u8 reset []         = { 0x50, 0x80 };
        static u8 adc_ctl_1_cfg [] = { 0x8E, 0x40 };
        static u8 agc_cfg []       = { 0x67, 0x10, 0x23, 0x00, 0xFF, 0xFF,
-                                      0x00, 0xFF, 0x00, 0x40, 0x40 };
+                                      0x00, 0xFF, 0x00, 0x40, 0x40 };
        static u8 dntv_extra[]     = { 0xB5, 0x7A };
        static u8 capt_range_cfg[] = { 0x75, 0x32 };
 
@@ -285,6 +287,33 @@ static struct lgdt330x_config fusionhdtv_5_gold = {
 };
 #endif
 
+#ifdef HAVE_NXT200X
+static int nxt200x_set_ts_param(struct dvb_frontend* fe,
+                               int is_punctured)
+{
+       struct cx8802_dev *dev= fe->dvb->priv;
+       dev->ts_gen_cntrl = is_punctured ? 0x04 : 0x00;
+       return 0;
+}
+
+static int nxt200x_set_pll_input(u8* buf, int input)
+{
+       if (input)
+               buf[3] |= 0x08;
+       else
+               buf[3] &= ~0x08;
+       return 0;
+}
+
+static struct nxt200x_config ati_hdtvwonder = {
+       .demod_address    = 0x0a,
+       .pll_address      = 0x61,
+       .pll_desc         = &dvb_pll_tuv1236d,
+       .set_pll_input    = nxt200x_set_pll_input,
+       .set_ts_params    = nxt200x_set_ts_param,
+};
+#endif
+
 static int dvb_register(struct cx8802_dev *dev)
 {
        /* init struct videobuf_dvb */
@@ -300,6 +329,7 @@ static int dvb_register(struct cx8802_dev *dev)
                break;
        case CX88_BOARD_TERRATEC_CINERGY_1400_DVB_T1:
        case CX88_BOARD_CONEXANT_DVB_T1:
+       case CX88_BOARD_WINFAST_DTV1000:
                dev->dvb.frontend = cx22702_attach(&connexant_refboard_config,
                                                   &dev->core->i2c_adap);
                break;
@@ -384,6 +414,12 @@ static int dvb_register(struct cx8802_dev *dev)
                                                    &dev->core->i2c_adap);
                }
                break;
+#endif
+#ifdef HAVE_NXT200X
+       case CX88_BOARD_ATI_HDTVWONDER:
+               dev->dvb.frontend = nxt200x_attach(&ati_hdtvwonder,
+                                                &dev->core->i2c_adap);
+               break;
 #endif
        default:
                printk("%s: The frontend of your DVB/ATSC card isn't supported yet\n",
@@ -403,6 +439,9 @@ static int dvb_register(struct cx8802_dev *dev)
        /* Put the analog decoder in standby to keep it quiet */
        cx88_call_i2c_clients (dev->core, TUNER_SET_STANDBY, NULL);
 
+       /* Put the analog decoder in standby to keep it quiet */
+       cx88_call_i2c_clients (dev->core, TUNER_SET_STANDBY, NULL);
+
        /* register everything */
        return videobuf_dvb_register(&dev->dvb, THIS_MODULE, dev);
 }
@@ -461,7 +500,7 @@ static int __devinit dvb_probe(struct pci_dev *pci_dev,
 
 static void __devexit dvb_remove(struct pci_dev *pci_dev)
 {
-        struct cx8802_dev *dev = pci_get_drvdata(pci_dev);
+       struct cx8802_dev *dev = pci_get_drvdata(pci_dev);
 
        /* dvb */
        videobuf_dvb_unregister(&dev->dvb);
@@ -476,8 +515,8 @@ static struct pci_device_id cx8802_pci_tbl[] = {
        {
                .vendor       = 0x14f1,
                .device       = 0x8802,
-                .subvendor    = PCI_ANY_ID,
-                .subdevice    = PCI_ANY_ID,
+               .subvendor    = PCI_ANY_ID,
+               .subdevice    = PCI_ANY_ID,
        },{
                /* --- end of list --- */
        }
@@ -485,10 +524,10 @@ static struct pci_device_id cx8802_pci_tbl[] = {
 MODULE_DEVICE_TABLE(pci, cx8802_pci_tbl);
 
 static struct pci_driver dvb_pci_driver = {
-        .name     = "cx88-dvb",
-        .id_table = cx8802_pci_tbl,
-        .probe    = dvb_probe,
-        .remove   = __devexit_p(dvb_remove),
+       .name     = "cx88-dvb",
+       .id_table = cx8802_pci_tbl,
+       .probe    = dvb_probe,
+       .remove   = __devexit_p(dvb_remove),
        .suspend  = cx8802_suspend_common,
        .resume   = cx8802_resume_common,
 };
index 761cebd40dbda8d3be3a1a539c5adc35ae3cd0d2..9790d412f1927041713c0a23e78f2f83317632ea 100644 (file)
@@ -3,7 +3,7 @@
     cx88-i2c.c  --  all the i2c code is here
 
     Copyright (C) 1996,97,98 Ralph  Metzler (rjkm@thp.uni-koeln.de)
-                           & Marcus Metzler (mocm@thp.uni-koeln.de)
+                          & Marcus Metzler (mocm@thp.uni-koeln.de)
     (c) 2002 Yurij Sysoev <yurij@naturesoft.net>
     (c) 1999-2003 Gerd Knorr <kraxel@bytesex.org>
 
@@ -90,7 +90,7 @@ static int cx8800_bit_getsda(void *data)
 
 static int attach_inform(struct i2c_client *client)
 {
-        struct tuner_setup tun_setup;
+       struct tuner_setup tun_setup;
        struct cx88_core *core = i2c_get_adapdata(client->adapter);
 
        dprintk(1, "%s i2c attach [addr=0x%x,client=%s]\n",
@@ -98,7 +98,7 @@ static int attach_inform(struct i2c_client *client)
        if (!client->driver->command)
                return 0;
 
-        if (core->radio_type != UNSET) {
+       if (core->radio_type != UNSET) {
                if ((core->radio_addr==ADDR_UNSET)||(core->radio_addr==client->addr)) {
                        tun_setup.mode_mask = T_RADIO;
                        tun_setup.type = core->radio_type;
@@ -106,8 +106,8 @@ static int attach_inform(struct i2c_client *client)
 
                        client->driver->command (client, TUNER_SET_TYPE_ADDR, &tun_setup);
                }
-        }
-        if (core->tuner_type != UNSET) {
+       }
+       if (core->tuner_type != UNSET) {
                if ((core->tuner_addr==ADDR_UNSET)||(core->tuner_addr==client->addr)) {
 
                        tun_setup.mode_mask = T_ANALOG_TV;
@@ -116,7 +116,7 @@ static int attach_inform(struct i2c_client *client)
 
                        client->driver->command (client,TUNER_SET_TYPE_ADDR, &tun_setup);
                }
-        }
+       }
 
        if (core->tda9887_conf)
                client->driver->command(client, TDA9887_SET_CONFIG, &core->tda9887_conf);
@@ -159,7 +159,7 @@ static struct i2c_adapter cx8800_i2c_adap_template = {
 };
 
 static struct i2c_client cx8800_i2c_client_template = {
-        .name  = "cx88xx internal",
+       .name   = "cx88xx internal",
 };
 
 static char *i2c_devs[128] = {
@@ -202,10 +202,10 @@ int cx88_i2c_init(struct cx88_core *core, struct pci_dev *pci)
 
        core->i2c_adap.dev.parent = &pci->dev;
        strlcpy(core->i2c_adap.name,core->name,sizeof(core->i2c_adap.name));
-        core->i2c_algo.data = core;
-        i2c_set_adapdata(&core->i2c_adap,core);
-        core->i2c_adap.algo_data = &core->i2c_algo;
-        core->i2c_client.adapter = &core->i2c_adap;
+       core->i2c_algo.data = core;
+       i2c_set_adapdata(&core->i2c_adap,core);
+       core->i2c_adap.algo_data = &core->i2c_algo;
+       core->i2c_client.adapter = &core->i2c_adap;
 
        cx8800_bit_setscl(core,1);
        cx8800_bit_setsda(core,1);
index c27fe4c36f69f0927d95e0b5b918df68f351de29..38b12ebaa49e0d4ac51e0a5ce2c3e997584d9c79 100644 (file)
@@ -553,7 +553,7 @@ void cx88_ir_irq(struct cx88_core *core)
 
                if ((ircode & 0xffff) != 0xeb04) { /* wrong address */
                        ir_dprintk("pulse distance decoded wrong address\n");
-                       break;
+                       break;
                }
 
                if (((~ircode >> 24) & 0xff) != ((ircode >> 16) & 0xff)) { /* wrong checksum */
index ee2300e1ae0b7024830fc2bc7a752d8d89e36682..35e6d0c2b872b8d2650e723d5ae1126b32c59792 100644 (file)
@@ -54,7 +54,7 @@ static int cx8802_start_dma(struct cx8802_dev    *dev,
 {
        struct cx88_core *core = dev->core;
 
-       dprintk(0, "cx8802_start_dma %d\n", buf->vb.width);
+       dprintk(0, "cx8802_start_dma w: %d, h: %d, f: %d\n", dev->width, dev->height, buf->vb.field);
 
        /* setup fifo + format */
        cx88_sram_channel_setup(core, &cx88_sram_channels[SRAM_CH28],
@@ -158,7 +158,8 @@ static int cx8802_restart_queue(struct cx8802_dev    *dev,
 
 /* ------------------------------------------------------------------ */
 
-int cx8802_buf_prepare(struct cx8802_dev *dev, struct cx88_buffer *buf)
+int cx8802_buf_prepare(struct cx8802_dev *dev, struct cx88_buffer *buf,
+                       enum v4l2_field field)
 {
        int size = dev->ts_packet_size * dev->ts_packet_count;
        int rc;
@@ -171,7 +172,7 @@ int cx8802_buf_prepare(struct cx8802_dev *dev, struct cx88_buffer *buf)
                buf->vb.width  = dev->ts_packet_size;
                buf->vb.height = dev->ts_packet_count;
                buf->vb.size   = size;
-               buf->vb.field  = V4L2_FIELD_TOP;
+               buf->vb.field  = field /*V4L2_FIELD_TOP*/;
 
                if (0 != (rc = videobuf_iolock(dev->pci,&buf->vb,NULL)))
                        goto fail;
@@ -315,14 +316,14 @@ static void cx8802_mpeg_irq(struct cx8802_dev *dev)
                spin_unlock(&dev->slock);
        }
 
-        /* other general errors */
-        if (status & 0x1f0100) {
+       /* other general errors */
+       if (status & 0x1f0100) {
                dprintk( 0, "general errors: 0x%08x\n", status & 0x1f0100 );
-                spin_lock(&dev->slock);
+               spin_lock(&dev->slock);
                cx8802_stop_dma(dev);
-                cx8802_restart_queue(dev,&dev->mpegq);
-                spin_unlock(&dev->slock);
-        }
+               cx8802_restart_queue(dev,&dev->mpegq);
+               spin_unlock(&dev->slock);
+       }
 }
 
 #define MAX_IRQ_LOOP 10
@@ -378,8 +379,8 @@ int cx8802_init_common(struct cx8802_dev *dev)
        }
 
        pci_read_config_byte(dev->pci, PCI_CLASS_REVISION, &dev->pci_rev);
-        pci_read_config_byte(dev->pci, PCI_LATENCY_TIMER,  &dev->pci_lat);
-        printk(KERN_INFO "%s/2: found at %s, rev: %d, irq: %d, "
+       pci_read_config_byte(dev->pci, PCI_LATENCY_TIMER,  &dev->pci_lat);
+       printk(KERN_INFO "%s/2: found at %s, rev: %d, irq: %d, "
               "latency: %d, mmio: 0x%lx\n", dev->core->name,
               pci_name(dev->pci), dev->pci_rev, dev->pci->irq,
               dev->pci_lat,pci_resource_start(dev->pci,0));
@@ -429,7 +430,7 @@ void cx8802_fini_common(struct cx8802_dev *dev)
 
 int cx8802_suspend_common(struct pci_dev *pci_dev, pm_message_t state)
 {
-        struct cx8802_dev *dev = pci_get_drvdata(pci_dev);
+       struct cx8802_dev *dev = pci_get_drvdata(pci_dev);
        struct cx88_core *core = dev->core;
 
        /* stop mpeg dma */
index 0a3a62fc9bbb729dafa5a33e781963c88f9fd099..d3bf5b17b1d40dde2a2b1f2d28b4c80bfbfd7966 100644 (file)
@@ -3,9 +3,9 @@
     cx88x-hw.h - CX2388x register offsets
 
     Copyright (C) 1996,97,98 Ralph Metzler (rjkm@thp.uni-koeln.de)
-                  2001 Michael Eskin
-                  2002 Yurij Sysoev <yurij@naturesoft.net>
-                  2003 Gerd Knorr <kraxel@bytesex.org>
+                 2001 Michael Eskin
+                 2002 Yurij Sysoev <yurij@naturesoft.net>
+                 2003 Gerd Knorr <kraxel@bytesex.org>
 
     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
 #define ColorFormatGamma         0x1000
 
 #define Interlaced              0x1
-#define NonInterlaced           0x0
+#define NonInterlaced           0x0
 
 #define FieldEven               0x1
 #define FieldOdd                0x0
 
-#define TGReadWriteMode                 0x0
-#define TGEnableMode            0x1
+#define TGReadWriteMode                 0x0
+#define TGEnableMode            0x1
 
 #define DV_CbAlign              0x0
 #define DV_Y0Align              0x1
index 2765acee0285f7fe216a2d0718731abde310aa59..6d9bec1c583b0ecfb03f28ae70af9c94fb01a238 100644 (file)
 #include "cx88.h"
 
 static unsigned int audio_debug = 0;
-module_param(audio_debug,int,0644);
-MODULE_PARM_DESC(audio_debug,"enable debug messages [audio]");
+module_param(audio_debug, int, 0644);
+MODULE_PARM_DESC(audio_debug, "enable debug messages [audio]");
 
 #define dprintk(fmt, arg...)   if (audio_debug) \
        printk(KERN_DEBUG "%s/0: " fmt, core->name , ## arg)
 
 /* ----------------------------------------------------------- */
 
-static char *aud_ctl_names[64] =
-{
-       [ EN_BTSC_FORCE_MONO       ] = "BTSC_FORCE_MONO",
-       [ EN_BTSC_FORCE_STEREO     ] = "BTSC_FORCE_STEREO",
-       [ EN_BTSC_FORCE_SAP        ] = "BTSC_FORCE_SAP",
-       [ EN_BTSC_AUTO_STEREO      ] = "BTSC_AUTO_STEREO",
-       [ EN_BTSC_AUTO_SAP         ] = "BTSC_AUTO_SAP",
-       [ EN_A2_FORCE_MONO1        ] = "A2_FORCE_MONO1",
-       [ EN_A2_FORCE_MONO2        ] = "A2_FORCE_MONO2",
-       [ EN_A2_FORCE_STEREO       ] = "A2_FORCE_STEREO",
-       [ EN_A2_AUTO_MONO2         ] = "A2_AUTO_MONO2",
-       [ EN_A2_AUTO_STEREO        ] = "A2_AUTO_STEREO",
-       [ EN_EIAJ_FORCE_MONO1      ] = "EIAJ_FORCE_MONO1",
-       [ EN_EIAJ_FORCE_MONO2      ] = "EIAJ_FORCE_MONO2",
-       [ EN_EIAJ_FORCE_STEREO     ] = "EIAJ_FORCE_STEREO",
-       [ EN_EIAJ_AUTO_MONO2       ] = "EIAJ_AUTO_MONO2",
-       [ EN_EIAJ_AUTO_STEREO      ] = "EIAJ_AUTO_STEREO",
-       [ EN_NICAM_FORCE_MONO1     ] = "NICAM_FORCE_MONO1",
-       [ EN_NICAM_FORCE_MONO2     ] = "NICAM_FORCE_MONO2",
-       [ EN_NICAM_FORCE_STEREO    ] = "NICAM_FORCE_STEREO",
-       [ EN_NICAM_AUTO_MONO2      ] = "NICAM_AUTO_MONO2",
-       [ EN_NICAM_AUTO_STEREO     ] = "NICAM_AUTO_STEREO",
-       [ EN_FMRADIO_FORCE_MONO    ] = "FMRADIO_FORCE_MONO",
-       [ EN_FMRADIO_FORCE_STEREO  ] = "FMRADIO_FORCE_STEREO",
-       [ EN_FMRADIO_AUTO_STEREO   ] = "FMRADIO_AUTO_STEREO",
+static char *aud_ctl_names[64] = {
+       [EN_BTSC_FORCE_MONO] = "BTSC_FORCE_MONO",
+       [EN_BTSC_FORCE_STEREO] = "BTSC_FORCE_STEREO",
+       [EN_BTSC_FORCE_SAP] = "BTSC_FORCE_SAP",
+       [EN_BTSC_AUTO_STEREO] = "BTSC_AUTO_STEREO",
+       [EN_BTSC_AUTO_SAP] = "BTSC_AUTO_SAP",
+       [EN_A2_FORCE_MONO1] = "A2_FORCE_MONO1",
+       [EN_A2_FORCE_MONO2] = "A2_FORCE_MONO2",
+       [EN_A2_FORCE_STEREO] = "A2_FORCE_STEREO",
+       [EN_A2_AUTO_MONO2] = "A2_AUTO_MONO2",
+       [EN_A2_AUTO_STEREO] = "A2_AUTO_STEREO",
+       [EN_EIAJ_FORCE_MONO1] = "EIAJ_FORCE_MONO1",
+       [EN_EIAJ_FORCE_MONO2] = "EIAJ_FORCE_MONO2",
+       [EN_EIAJ_FORCE_STEREO] = "EIAJ_FORCE_STEREO",
+       [EN_EIAJ_AUTO_MONO2] = "EIAJ_AUTO_MONO2",
+       [EN_EIAJ_AUTO_STEREO] = "EIAJ_AUTO_STEREO",
+       [EN_NICAM_FORCE_MONO1] = "NICAM_FORCE_MONO1",
+       [EN_NICAM_FORCE_MONO2] = "NICAM_FORCE_MONO2",
+       [EN_NICAM_FORCE_STEREO] = "NICAM_FORCE_STEREO",
+       [EN_NICAM_AUTO_MONO2] = "NICAM_AUTO_MONO2",
+       [EN_NICAM_AUTO_STEREO] = "NICAM_AUTO_STEREO",
+       [EN_FMRADIO_FORCE_MONO] = "FMRADIO_FORCE_MONO",
+       [EN_FMRADIO_FORCE_STEREO] = "FMRADIO_FORCE_STEREO",
+       [EN_FMRADIO_AUTO_STEREO] = "FMRADIO_AUTO_STEREO",
 };
 
 struct rlist {
@@ -97,8 +96,7 @@ struct rlist {
        u32 val;
 };
 
-static void set_audio_registers(struct cx88_core *core,
-                               const struct rlist *l)
+static void set_audio_registers(struct cx88_core *core, const struct rlist *l)
 {
        int i;
 
@@ -119,17 +117,18 @@ static void set_audio_registers(struct cx88_core *core,
        }
 }
 
-static void set_audio_start(struct cx88_core *core,
-                       u32 mode)
+static void set_audio_start(struct cx88_core *core, u32 mode)
 {
        // mute
-       cx_write(AUD_VOL_CTL,       (1 << 6));
+       cx_write(AUD_VOL_CTL, (1 << 6));
 
        // start programming
-       cx_write(AUD_CTL,           0x0000);
-       cx_write(AUD_INIT,          mode);
-       cx_write(AUD_INIT_LD,       0x0001);
-       cx_write(AUD_SOFT_RESET,    0x0001);
+       cx_write(MO_AUD_DMACNTRL, 0x0000);
+       msleep(100);
+       //cx_write(AUD_CTL, 0x0000);
+       cx_write(AUD_INIT, mode);
+       cx_write(AUD_INIT_LD, 0x0001);
+       cx_write(AUD_SOFT_RESET, 0x0001);
 }
 
 static void set_audio_finish(struct cx88_core *core, u32 ctl)
@@ -148,12 +147,13 @@ static void set_audio_finish(struct cx88_core *core, u32 ctl)
                cx_write(AUD_I2SCNTL, 0);
                //cx_write(AUD_APB_IN_RATE_ADJ, 0);
        } else {
-       ctl |= EN_DAC_ENABLE;
-       cx_write(AUD_CTL, ctl);
+               ctl |= EN_DAC_ENABLE;
+               cx_write(AUD_CTL, ctl);
        }
 
        /* finish programming */
        cx_write(AUD_SOFT_RESET, 0x0000);
+       cx_write(MO_AUD_DMACNTRL, 0x0003);
 
        /* unmute */
        volume = cx_sread(SHADOW_AUD_VOL_CTL);
@@ -162,486 +162,463 @@ static void set_audio_finish(struct cx88_core *core, u32 ctl)
 
 /* ----------------------------------------------------------- */
 
-static void set_audio_standard_BTSC(struct cx88_core *core, unsigned int sap, u32 mode)
+static void set_audio_standard_BTSC(struct cx88_core *core, unsigned int sap,
+                                   u32 mode)
 {
        static const struct rlist btsc[] = {
-       { AUD_AFE_12DB_EN,             0x00000001 },
-               { AUD_OUT1_SEL,                0x00000013 },
-               { AUD_OUT1_SHIFT,              0x00000000 },
-               { AUD_POLY0_DDS_CONSTANT,      0x0012010c },
-               { AUD_DMD_RA_DDS,              0x00c3e7aa },
-               { AUD_DBX_IN_GAIN,             0x00004734 },
-               { AUD_DBX_WBE_GAIN,            0x00004640 },
-               { AUD_DBX_SE_GAIN,             0x00008d31 },
-               { AUD_DCOC_0_SRC,              0x0000001a },
-               { AUD_IIR1_4_SEL,              0x00000021 },
-               { AUD_DCOC_PASS_IN,            0x00000003 },
-               { AUD_DCOC_0_SHIFT_IN0,        0x0000000a },
-               { AUD_DCOC_0_SHIFT_IN1,        0x00000008 },
-               { AUD_DCOC_1_SHIFT_IN0,        0x0000000a },
-               { AUD_DCOC_1_SHIFT_IN1,        0x00000008 },
-               { AUD_DN0_FREQ,                0x0000283b },
-               { AUD_DN2_SRC_SEL,             0x00000008 },
-               { AUD_DN2_FREQ,                0x00003000 },
-               { AUD_DN2_AFC,                 0x00000002 },
-               { AUD_DN2_SHFT,                0x00000000 },
-               { AUD_IIR2_2_SEL,              0x00000020 },
-               { AUD_IIR2_2_SHIFT,            0x00000000 },
-               { AUD_IIR2_3_SEL,              0x0000001f },
-               { AUD_IIR2_3_SHIFT,            0x00000000 },
-               { AUD_CRDC1_SRC_SEL,           0x000003ce },
-               { AUD_CRDC1_SHIFT,             0x00000000 },
-               { AUD_CORDIC_SHIFT_1,          0x00000007 },
-               { AUD_DCOC_1_SRC,              0x0000001b },
-               { AUD_DCOC1_SHIFT,             0x00000000 },
-               { AUD_RDSI_SEL,                0x00000008 },
-               { AUD_RDSQ_SEL,                0x00000008 },
-               { AUD_RDSI_SHIFT,              0x00000000 },
-               { AUD_RDSQ_SHIFT,              0x00000000 },
-               { AUD_POLYPH80SCALEFAC,        0x00000003 },
+               {AUD_AFE_12DB_EN, 0x00000001},
+               {AUD_OUT1_SEL, 0x00000013},
+               {AUD_OUT1_SHIFT, 0x00000000},
+               {AUD_POLY0_DDS_CONSTANT, 0x0012010c},
+               {AUD_DMD_RA_DDS, 0x00c3e7aa},
+               {AUD_DBX_IN_GAIN, 0x00004734},
+               {AUD_DBX_WBE_GAIN, 0x00004640},
+               {AUD_DBX_SE_GAIN, 0x00008d31},
+               {AUD_DCOC_0_SRC, 0x0000001a},
+               {AUD_IIR1_4_SEL, 0x00000021},
+               {AUD_DCOC_PASS_IN, 0x00000003},
+               {AUD_DCOC_0_SHIFT_IN0, 0x0000000a},
+               {AUD_DCOC_0_SHIFT_IN1, 0x00000008},
+               {AUD_DCOC_1_SHIFT_IN0, 0x0000000a},
+               {AUD_DCOC_1_SHIFT_IN1, 0x00000008},
+               {AUD_DN0_FREQ, 0x0000283b},
+               {AUD_DN2_SRC_SEL, 0x00000008},
+               {AUD_DN2_FREQ, 0x00003000},
+               {AUD_DN2_AFC, 0x00000002},
+               {AUD_DN2_SHFT, 0x00000000},
+               {AUD_IIR2_2_SEL, 0x00000020},
+               {AUD_IIR2_2_SHIFT, 0x00000000},
+               {AUD_IIR2_3_SEL, 0x0000001f},
+               {AUD_IIR2_3_SHIFT, 0x00000000},
+               {AUD_CRDC1_SRC_SEL, 0x000003ce},
+               {AUD_CRDC1_SHIFT, 0x00000000},
+               {AUD_CORDIC_SHIFT_1, 0x00000007},
+               {AUD_DCOC_1_SRC, 0x0000001b},
+               {AUD_DCOC1_SHIFT, 0x00000000},
+               {AUD_RDSI_SEL, 0x00000008},
+               {AUD_RDSQ_SEL, 0x00000008},
+               {AUD_RDSI_SHIFT, 0x00000000},
+               {AUD_RDSQ_SHIFT, 0x00000000},
+               {AUD_POLYPH80SCALEFAC, 0x00000003},
                { /* end of list */ },
        };
        static const struct rlist btsc_sap[] = {
-       { AUD_AFE_12DB_EN,             0x00000001 },
-               { AUD_DBX_IN_GAIN,             0x00007200 },
-               { AUD_DBX_WBE_GAIN,            0x00006200 },
-               { AUD_DBX_SE_GAIN,             0x00006200 },
-               { AUD_IIR1_1_SEL,              0x00000000 },
-               { AUD_IIR1_3_SEL,              0x00000001 },
-               { AUD_DN1_SRC_SEL,             0x00000007 },
-               { AUD_IIR1_4_SHIFT,            0x00000006 },
-               { AUD_IIR2_1_SHIFT,            0x00000000 },
-               { AUD_IIR2_2_SHIFT,            0x00000000 },
-               { AUD_IIR3_0_SHIFT,            0x00000000 },
-               { AUD_IIR3_1_SHIFT,            0x00000000 },
-               { AUD_IIR3_0_SEL,              0x0000000d },
-               { AUD_IIR3_1_SEL,              0x0000000e },
-               { AUD_DEEMPH1_SRC_SEL,         0x00000014 },
-               { AUD_DEEMPH1_SHIFT,           0x00000000 },
-               { AUD_DEEMPH1_G0,              0x00004000 },
-               { AUD_DEEMPH1_A0,              0x00000000 },
-               { AUD_DEEMPH1_B0,              0x00000000 },
-               { AUD_DEEMPH1_A1,              0x00000000 },
-               { AUD_DEEMPH1_B1,              0x00000000 },
-               { AUD_OUT0_SEL,                0x0000003f },
-               { AUD_OUT1_SEL,                0x0000003f },
-               { AUD_DN1_AFC,                 0x00000002 },
-               { AUD_DCOC_0_SHIFT_IN0,        0x0000000a },
-               { AUD_DCOC_0_SHIFT_IN1,        0x00000008 },
-               { AUD_DCOC_1_SHIFT_IN0,        0x0000000a },
-               { AUD_DCOC_1_SHIFT_IN1,        0x00000008 },
-               { AUD_IIR1_0_SEL,              0x0000001d },
-               { AUD_IIR1_2_SEL,              0x0000001e },
-               { AUD_IIR2_1_SEL,              0x00000002 },
-               { AUD_IIR2_2_SEL,              0x00000004 },
-               { AUD_IIR3_2_SEL,              0x0000000f },
-               { AUD_DCOC2_SHIFT,             0x00000001 },
-               { AUD_IIR3_2_SHIFT,            0x00000001 },
-               { AUD_DEEMPH0_SRC_SEL,         0x00000014 },
-               { AUD_CORDIC_SHIFT_1,          0x00000006 },
-               { AUD_POLY0_DDS_CONSTANT,      0x000e4db2 },
-               { AUD_DMD_RA_DDS,              0x00f696e6 },
-               { AUD_IIR2_3_SEL,              0x00000025 },
-               { AUD_IIR1_4_SEL,              0x00000021 },
-               { AUD_DN1_FREQ,                0x0000c965 },
-               { AUD_DCOC_PASS_IN,            0x00000003 },
-               { AUD_DCOC_0_SRC,              0x0000001a },
-               { AUD_DCOC_1_SRC,              0x0000001b },
-               { AUD_DCOC1_SHIFT,             0x00000000 },
-               { AUD_RDSI_SEL,                0x00000009 },
-               { AUD_RDSQ_SEL,                0x00000009 },
-               { AUD_RDSI_SHIFT,              0x00000000 },
-               { AUD_RDSQ_SHIFT,              0x00000000 },
-               { AUD_POLYPH80SCALEFAC,        0x00000003 },
+               {AUD_AFE_12DB_EN, 0x00000001},
+               {AUD_DBX_IN_GAIN, 0x00007200},
+               {AUD_DBX_WBE_GAIN, 0x00006200},
+               {AUD_DBX_SE_GAIN, 0x00006200},
+               {AUD_IIR1_1_SEL, 0x00000000},
+               {AUD_IIR1_3_SEL, 0x00000001},
+               {AUD_DN1_SRC_SEL, 0x00000007},
+               {AUD_IIR1_4_SHIFT, 0x00000006},
+               {AUD_IIR2_1_SHIFT, 0x00000000},
+               {AUD_IIR2_2_SHIFT, 0x00000000},
+               {AUD_IIR3_0_SHIFT, 0x00000000},
+               {AUD_IIR3_1_SHIFT, 0x00000000},
+               {AUD_IIR3_0_SEL, 0x0000000d},
+               {AUD_IIR3_1_SEL, 0x0000000e},
+               {AUD_DEEMPH1_SRC_SEL, 0x00000014},
+               {AUD_DEEMPH1_SHIFT, 0x00000000},
+               {AUD_DEEMPH1_G0, 0x00004000},
+               {AUD_DEEMPH1_A0, 0x00000000},
+               {AUD_DEEMPH1_B0, 0x00000000},
+               {AUD_DEEMPH1_A1, 0x00000000},
+               {AUD_DEEMPH1_B1, 0x00000000},
+               {AUD_OUT0_SEL, 0x0000003f},
+               {AUD_OUT1_SEL, 0x0000003f},
+               {AUD_DN1_AFC, 0x00000002},
+               {AUD_DCOC_0_SHIFT_IN0, 0x0000000a},
+               {AUD_DCOC_0_SHIFT_IN1, 0x00000008},
+               {AUD_DCOC_1_SHIFT_IN0, 0x0000000a},
+               {AUD_DCOC_1_SHIFT_IN1, 0x00000008},
+               {AUD_IIR1_0_SEL, 0x0000001d},
+               {AUD_IIR1_2_SEL, 0x0000001e},
+               {AUD_IIR2_1_SEL, 0x00000002},
+               {AUD_IIR2_2_SEL, 0x00000004},
+               {AUD_IIR3_2_SEL, 0x0000000f},
+               {AUD_DCOC2_SHIFT, 0x00000001},
+               {AUD_IIR3_2_SHIFT, 0x00000001},
+               {AUD_DEEMPH0_SRC_SEL, 0x00000014},
+               {AUD_CORDIC_SHIFT_1, 0x00000006},
+               {AUD_POLY0_DDS_CONSTANT, 0x000e4db2},
+               {AUD_DMD_RA_DDS, 0x00f696e6},
+               {AUD_IIR2_3_SEL, 0x00000025},
+               {AUD_IIR1_4_SEL, 0x00000021},
+               {AUD_DN1_FREQ, 0x0000c965},
+               {AUD_DCOC_PASS_IN, 0x00000003},
+               {AUD_DCOC_0_SRC, 0x0000001a},
+               {AUD_DCOC_1_SRC, 0x0000001b},
+               {AUD_DCOC1_SHIFT, 0x00000000},
+               {AUD_RDSI_SEL, 0x00000009},
+               {AUD_RDSQ_SEL, 0x00000009},
+               {AUD_RDSI_SHIFT, 0x00000000},
+               {AUD_RDSQ_SHIFT, 0x00000000},
+               {AUD_POLYPH80SCALEFAC, 0x00000003},
                { /* end of list */ },
        };
 
        mode |= EN_FMRADIO_EN_RDS;
 
        if (sap) {
-               dprintk("%s SAP (status: unknown)\n",__FUNCTION__);
-       set_audio_start(core, SEL_SAP);
+               dprintk("%s SAP (status: unknown)\n", __FUNCTION__);
+               set_audio_start(core, SEL_SAP);
                set_audio_registers(core, btsc_sap);
                set_audio_finish(core, mode);
        } else {
-               dprintk("%s (status: known-good)\n",__FUNCTION__);
-       set_audio_start(core, SEL_BTSC);
+               dprintk("%s (status: known-good)\n", __FUNCTION__);
+               set_audio_start(core, SEL_BTSC);
                set_audio_registers(core, btsc);
                set_audio_finish(core, mode);
        }
 }
 
-
-static void set_audio_standard_NICAM_L(struct cx88_core *core, int stereo)
+static void set_audio_standard_NICAM(struct cx88_core *core, u32 mode)
 {
-       /* This is probably weird..
-       * Let's operate and find out. */
-
-       static const struct rlist nicam_l_mono[] = {
-               { AUD_ERRLOGPERIOD_R,     0x00000064 },
-               { AUD_ERRINTRPTTHSHLD1_R, 0x00000FFF },
-               { AUD_ERRINTRPTTHSHLD2_R, 0x0000001F },
-               { AUD_ERRINTRPTTHSHLD3_R, 0x0000000F },
-
-               { AUD_PDF_DDS_CNST_BYTE2, 0x48 },
-               { AUD_PDF_DDS_CNST_BYTE1, 0x3D },
-               { AUD_QAM_MODE,           0x00 },
-               { AUD_PDF_DDS_CNST_BYTE0, 0xf5 },
-               { AUD_PHACC_FREQ_8MSB,    0x3a },
-               { AUD_PHACC_FREQ_8LSB,    0x4a },
-
-               { AUD_DEEMPHGAIN_R, 0x6680 },
-               { AUD_DEEMPHNUMER1_R, 0x353DE },
-               { AUD_DEEMPHNUMER2_R, 0x1B1 },
-               { AUD_DEEMPHDENOM1_R, 0x0F3D0 },
-               { AUD_DEEMPHDENOM2_R, 0x0 },
-               { AUD_FM_MODE_ENABLE, 0x7 },
-               { AUD_POLYPH80SCALEFAC, 0x3 },
-               { AUD_AFE_12DB_EN, 0x1 },
-               { AAGC_GAIN, 0x0 },
-               { AAGC_HYST, 0x18 },
-               { AAGC_DEF, 0x20 },
-               { AUD_DN0_FREQ, 0x0 },
-               { AUD_POLY0_DDS_CONSTANT, 0x0E4DB2 },
-               { AUD_DCOC_0_SRC, 0x21 },
-               { AUD_IIR1_0_SEL, 0x0 },
-               { AUD_IIR1_0_SHIFT, 0x7 },
-               { AUD_IIR1_1_SEL, 0x2 },
-               { AUD_IIR1_1_SHIFT, 0x0 },
-               { AUD_DCOC_1_SRC, 0x3 },
-               { AUD_DCOC1_SHIFT, 0x0 },
-               { AUD_DCOC_PASS_IN, 0x0 },
-               { AUD_IIR1_2_SEL, 0x23 },
-               { AUD_IIR1_2_SHIFT, 0x0 },
-               { AUD_IIR1_3_SEL, 0x4 },
-               { AUD_IIR1_3_SHIFT, 0x7 },
-               { AUD_IIR1_4_SEL, 0x5 },
-               { AUD_IIR1_4_SHIFT, 0x7 },
-               { AUD_IIR3_0_SEL, 0x7 },
-               { AUD_IIR3_0_SHIFT, 0x0 },
-               { AUD_DEEMPH0_SRC_SEL, 0x11 },
-               { AUD_DEEMPH0_SHIFT, 0x0 },
-               { AUD_DEEMPH0_G0, 0x7000 },
-               { AUD_DEEMPH0_A0, 0x0 },
-               { AUD_DEEMPH0_B0, 0x0 },
-               { AUD_DEEMPH0_A1, 0x0 },
-               { AUD_DEEMPH0_B1, 0x0 },
-               { AUD_DEEMPH1_SRC_SEL, 0x11 },
-               { AUD_DEEMPH1_SHIFT, 0x0 },
-               { AUD_DEEMPH1_G0, 0x7000 },
-               { AUD_DEEMPH1_A0, 0x0 },
-               { AUD_DEEMPH1_B0, 0x0 },
-               { AUD_DEEMPH1_A1, 0x0 },
-               { AUD_DEEMPH1_B1, 0x0 },
-               { AUD_OUT0_SEL, 0x3F },
-               { AUD_OUT1_SEL, 0x3F },
-               { AUD_DMD_RA_DDS, 0x0F5C285 },
-               { AUD_PLL_INT, 0x1E },
-               { AUD_PLL_DDS, 0x0 },
-               { AUD_PLL_FRAC, 0x0E542 },
-
-               // setup QAM registers
-               { AUD_RATE_ADJ1,      0x00000100 },
-               { AUD_RATE_ADJ2,      0x00000200 },
-               { AUD_RATE_ADJ3,      0x00000300 },
-               { AUD_RATE_ADJ4,      0x00000400 },
-               { AUD_RATE_ADJ5,      0x00000500 },
-               { AUD_RATE_THRES_DMD, 0x000000C0 },
+       static const struct rlist nicam_l[] = {
+               {AUD_AFE_12DB_EN, 0x00000001},
+               {AUD_RATE_ADJ1, 0x00000060},
+               {AUD_RATE_ADJ2, 0x000000F9},
+               {AUD_RATE_ADJ3, 0x000001CC},
+               {AUD_RATE_ADJ4, 0x000002B3},
+               {AUD_RATE_ADJ5, 0x00000726},
+               {AUD_DEEMPHDENOM1_R, 0x0000F3D0},
+               {AUD_DEEMPHDENOM2_R, 0x00000000},
+               {AUD_ERRLOGPERIOD_R, 0x00000064},
+               {AUD_ERRINTRPTTHSHLD1_R, 0x00000FFF},
+               {AUD_ERRINTRPTTHSHLD2_R, 0x0000001F},
+               {AUD_ERRINTRPTTHSHLD3_R, 0x0000000F},
+               {AUD_POLYPH80SCALEFAC, 0x00000003},
+               {AUD_DMD_RA_DDS, 0x00C00000},
+               {AUD_PLL_INT, 0x0000001E},
+               {AUD_PLL_DDS, 0x00000000},
+               {AUD_PLL_FRAC, 0x0000E542},
+               {AUD_START_TIMER, 0x00000000},
+               {AUD_DEEMPHNUMER1_R, 0x000353DE},
+               {AUD_DEEMPHNUMER2_R, 0x000001B1},
+               {AUD_PDF_DDS_CNST_BYTE2, 0x06},
+               {AUD_PDF_DDS_CNST_BYTE1, 0x82},
+               {AUD_PDF_DDS_CNST_BYTE0, 0x12},
+               {AUD_QAM_MODE, 0x05},
+               {AUD_PHACC_FREQ_8MSB, 0x34},
+               {AUD_PHACC_FREQ_8LSB, 0x4C},
+               {AUD_DEEMPHGAIN_R, 0x00006680},
+               {AUD_RATE_THRES_DMD, 0x000000C0},
                { /* end of list */ },
        };
 
-       static const struct rlist nicam_l[] = {
-               // setup QAM registers
-               { AUD_RATE_ADJ1, 0x00000060 },
-               { AUD_RATE_ADJ2, 0x000000F9 },
-               { AUD_RATE_ADJ3, 0x000001CC },
-               { AUD_RATE_ADJ4, 0x000002B3 },
-               { AUD_RATE_ADJ5, 0x00000726 },
-               { AUD_DEEMPHDENOM1_R, 0x0000F3D0 },
-               { AUD_DEEMPHDENOM2_R, 0x00000000 },
-               { AUD_ERRLOGPERIOD_R, 0x00000064 },
-               { AUD_ERRINTRPTTHSHLD1_R, 0x00000FFF },
-               { AUD_ERRINTRPTTHSHLD2_R, 0x0000001F },
-               { AUD_ERRINTRPTTHSHLD3_R, 0x0000000F },
-               { AUD_POLYPH80SCALEFAC, 0x00000003 },
-               { AUD_DMD_RA_DDS, 0x00C00000 },
-               { AUD_PLL_INT, 0x0000001E },
-               { AUD_PLL_DDS, 0x00000000 },
-               { AUD_PLL_FRAC, 0x0000E542 },
-               { AUD_START_TIMER, 0x00000000 },
-               { AUD_DEEMPHNUMER1_R, 0x000353DE },
-               { AUD_DEEMPHNUMER2_R, 0x000001B1 },
-               { AUD_PDF_DDS_CNST_BYTE2, 0x06 },
-               { AUD_PDF_DDS_CNST_BYTE1, 0x82 },
-               { AUD_QAM_MODE, 0x05 },
-               { AUD_PDF_DDS_CNST_BYTE0, 0x12 },
-               { AUD_PHACC_FREQ_8MSB, 0x34 },
-               { AUD_PHACC_FREQ_8LSB, 0x4C },
-               { AUD_DEEMPHGAIN_R, 0x00006680 },
-               { AUD_RATE_THRES_DMD, 0x000000C0  },
+       static const struct rlist nicam_bgdki_common[] = {
+               {AUD_AFE_12DB_EN, 0x00000001},
+               {AUD_RATE_ADJ1, 0x00000010},
+               {AUD_RATE_ADJ2, 0x00000040},
+               {AUD_RATE_ADJ3, 0x00000100},
+               {AUD_RATE_ADJ4, 0x00000400},
+               {AUD_RATE_ADJ5, 0x00001000},
+               //{ AUD_DMD_RA_DDS,        0x00c0d5ce },
+               {AUD_ERRLOGPERIOD_R, 0x00000fff},
+               {AUD_ERRINTRPTTHSHLD1_R, 0x000003ff},
+               {AUD_ERRINTRPTTHSHLD2_R, 0x000000ff},
+               {AUD_ERRINTRPTTHSHLD3_R, 0x0000003f},
+               {AUD_POLYPH80SCALEFAC, 0x00000003},
+               {AUD_DEEMPHGAIN_R, 0x000023c2},
+               {AUD_DEEMPHNUMER1_R, 0x0002a7bc},
+               {AUD_DEEMPHNUMER2_R, 0x0003023e},
+               {AUD_DEEMPHDENOM1_R, 0x0000f3d0},
+               {AUD_DEEMPHDENOM2_R, 0x00000000},
+               {AUD_PDF_DDS_CNST_BYTE2, 0x06},
+               {AUD_PDF_DDS_CNST_BYTE1, 0x82},
+               {AUD_QAM_MODE, 0x05},
                { /* end of list */ },
-       } ;
-       dprintk("%s (status: devel), stereo : %d\n",__FUNCTION__,stereo);
-
-       if (!stereo) {
-       /* AM Mono */
-               set_audio_start(core, SEL_A2);
-               set_audio_registers(core, nicam_l_mono);
-       set_audio_finish(core, EN_A2_FORCE_MONO1);
-       } else {
-       /* Nicam Stereo */
-               set_audio_start(core, SEL_NICAM);
-               set_audio_registers(core, nicam_l);
-       set_audio_finish(core, 0x1924); /* FIXME */
-       }
-}
+       };
 
-static void set_audio_standard_PAL_I(struct cx88_core *core, int stereo)
-{
-       static const struct rlist pal_i_fm_mono[] = {
-       {AUD_ERRLOGPERIOD_R,       0x00000064},
-       {AUD_ERRINTRPTTHSHLD1_R,   0x00000fff},
-       {AUD_ERRINTRPTTHSHLD2_R,   0x0000001f},
-       {AUD_ERRINTRPTTHSHLD3_R,   0x0000000f},
-       {AUD_PDF_DDS_CNST_BYTE2,   0x06},
-       {AUD_PDF_DDS_CNST_BYTE1,   0x82},
-       {AUD_PDF_DDS_CNST_BYTE0,   0x12},
-       {AUD_QAM_MODE,             0x05},
-       {AUD_PHACC_FREQ_8MSB,      0x3a},
-       {AUD_PHACC_FREQ_8LSB,      0x93},
-       {AUD_DMD_RA_DDS,           0x002a4f2f},
-       {AUD_PLL_INT,              0x0000001e},
-       {AUD_PLL_DDS,              0x00000004},
-       {AUD_PLL_FRAC,             0x0000e542},
-       {AUD_RATE_ADJ1,            0x00000100},
-       {AUD_RATE_ADJ2,            0x00000200},
-       {AUD_RATE_ADJ3,            0x00000300},
-       {AUD_RATE_ADJ4,            0x00000400},
-       {AUD_RATE_ADJ5,            0x00000500},
-       {AUD_THR_FR,               0x00000000},
-       {AUD_PILOT_BQD_1_K0,       0x0000755b},
-       {AUD_PILOT_BQD_1_K1,       0x00551340},
-       {AUD_PILOT_BQD_1_K2,       0x006d30be},
-       {AUD_PILOT_BQD_1_K3,       0xffd394af},
-       {AUD_PILOT_BQD_1_K4,       0x00400000},
-       {AUD_PILOT_BQD_2_K0,       0x00040000},
-       {AUD_PILOT_BQD_2_K1,       0x002a4841},
-       {AUD_PILOT_BQD_2_K2,       0x00400000},
-       {AUD_PILOT_BQD_2_K3,       0x00000000},
-       {AUD_PILOT_BQD_2_K4,       0x00000000},
-       {AUD_MODE_CHG_TIMER,       0x00000060},
-       {AUD_AFE_12DB_EN,          0x00000001},
-       {AAGC_HYST,                0x0000000a},
-       {AUD_CORDIC_SHIFT_0,       0x00000007},
-       {AUD_CORDIC_SHIFT_1,       0x00000007},
-       {AUD_C1_UP_THR,            0x00007000},
-       {AUD_C1_LO_THR,            0x00005400},
-       {AUD_C2_UP_THR,            0x00005400},
-       {AUD_C2_LO_THR,            0x00003000},
-       {AUD_DCOC_0_SRC,           0x0000001a},
-       {AUD_DCOC0_SHIFT,          0x00000000},
-       {AUD_DCOC_0_SHIFT_IN0,     0x0000000a},
-       {AUD_DCOC_0_SHIFT_IN1,     0x00000008},
-       {AUD_DCOC_PASS_IN,         0x00000003},
-       {AUD_IIR3_0_SEL,           0x00000021},
-       {AUD_DN2_AFC,              0x00000002},
-       {AUD_DCOC_1_SRC,           0x0000001b},
-       {AUD_DCOC1_SHIFT,          0x00000000},
-       {AUD_DCOC_1_SHIFT_IN0,     0x0000000a},
-       {AUD_DCOC_1_SHIFT_IN1,     0x00000008},
-       {AUD_IIR3_1_SEL,           0x00000023},
-       {AUD_DN0_FREQ,             0x000035a3},
-       {AUD_DN2_FREQ,             0x000029c7},
-       {AUD_CRDC0_SRC_SEL,        0x00000511},
-       {AUD_IIR1_0_SEL,           0x00000001},
-       {AUD_IIR1_1_SEL,           0x00000000},
-       {AUD_IIR3_2_SEL,           0x00000003},
-       {AUD_IIR3_2_SHIFT,         0x00000000},
-       {AUD_IIR3_0_SEL,           0x00000002},
-       {AUD_IIR2_0_SEL,           0x00000021},
-       {AUD_IIR2_0_SHIFT,         0x00000002},
-       {AUD_DEEMPH0_SRC_SEL,      0x0000000b},
-       {AUD_DEEMPH1_SRC_SEL,      0x0000000b},
-       {AUD_POLYPH80SCALEFAC,     0x00000001},
-       {AUD_START_TIMER,          0x00000000},
-       { /* end of list */ },
-       };
-
-       static const struct rlist pal_i_nicam[] = {
-       { AUD_RATE_ADJ1,           0x00000010 },
-       { AUD_RATE_ADJ2,           0x00000040 },
-       { AUD_RATE_ADJ3,           0x00000100 },
-       { AUD_RATE_ADJ4,           0x00000400 },
-       { AUD_RATE_ADJ5,           0x00001000 },
-       //     { AUD_DMD_RA_DDS,          0x00c0d5ce },
-       { AUD_DEEMPHGAIN_R,        0x000023c2 },
-       { AUD_DEEMPHNUMER1_R,      0x0002a7bc },
-       { AUD_DEEMPHNUMER2_R,      0x0003023e },
-       { AUD_DEEMPHDENOM1_R,      0x0000f3d0 },
-       { AUD_DEEMPHDENOM2_R,      0x00000000 },
-       { AUD_DEEMPHDENOM2_R,      0x00000000 },
-       { AUD_ERRLOGPERIOD_R,      0x00000fff },
-       { AUD_ERRINTRPTTHSHLD1_R,  0x000003ff },
-       { AUD_ERRINTRPTTHSHLD2_R,  0x000000ff },
-       { AUD_ERRINTRPTTHSHLD3_R,  0x0000003f },
-       { AUD_POLYPH80SCALEFAC,    0x00000003 },
-       { AUD_PDF_DDS_CNST_BYTE2,  0x06 },
-       { AUD_PDF_DDS_CNST_BYTE1,  0x82 },
-       { AUD_PDF_DDS_CNST_BYTE0,  0x16 },
-       { AUD_QAM_MODE,            0x05 },
-       { AUD_PDF_DDS_CNST_BYTE0,  0x12 },
-       { AUD_PHACC_FREQ_8MSB,     0x3a },
-       { AUD_PHACC_FREQ_8LSB,     0x93 },
-       { /* end of list */ },
+       static const struct rlist nicam_i[] = {
+               {AUD_PDF_DDS_CNST_BYTE0, 0x12},
+               {AUD_PHACC_FREQ_8MSB, 0x3a},
+               {AUD_PHACC_FREQ_8LSB, 0x93},
+               { /* end of list */ },
        };
 
-       dprintk("%s (status: devel), stereo : %d\n",__FUNCTION__,stereo);
+       static const struct rlist nicam_default[] = {
+               {AUD_PDF_DDS_CNST_BYTE0, 0x16},
+               {AUD_PHACC_FREQ_8MSB, 0x34},
+               {AUD_PHACC_FREQ_8LSB, 0x4c},
+               { /* end of list */ },
+       };
 
-       if (!stereo) {
-       /* FM Mono */
-       set_audio_start(core, SEL_A2);
-               set_audio_registers(core, pal_i_fm_mono);
-               set_audio_finish(core, EN_DMTRX_SUMDIFF | EN_A2_FORCE_MONO1);
-       } else {
-       /* Nicam Stereo */
-       set_audio_start(core, SEL_NICAM);
-               set_audio_registers(core, pal_i_nicam);
-               set_audio_finish(core, EN_DMTRX_LR | EN_DMTRX_BYPASS | EN_NICAM_AUTO_STEREO);
-       }
+       set_audio_start(core,SEL_NICAM);
+       switch (core->tvaudio) {
+       case WW_L:
+               dprintk("%s SECAM-L NICAM (status: devel)\n", __FUNCTION__);
+               set_audio_registers(core, nicam_l);
+               break;
+       case WW_I:
+               dprintk("%s PAL-I NICAM (status: devel)\n", __FUNCTION__);
+               set_audio_registers(core, nicam_bgdki_common);
+               set_audio_registers(core, nicam_i);
+               break;
+       default:
+               dprintk("%s PAL-BGDK NICAM (status: unknown)\n", __FUNCTION__);
+               set_audio_registers(core, nicam_bgdki_common);
+               set_audio_registers(core, nicam_default);
+               break;
+       };
+
+       mode |= EN_DMTRX_LR | EN_DMTRX_BYPASS;
+       set_audio_finish(core, mode);
 }
 
 static void set_audio_standard_A2(struct cx88_core *core, u32 mode)
 {
-       static const struct rlist a2_common[] = {
-       {AUD_ERRLOGPERIOD_R,            0x00000064},
-       {AUD_ERRINTRPTTHSHLD1_R,        0x00000fff},
-       {AUD_ERRINTRPTTHSHLD2_R,        0x0000001f},
-       {AUD_ERRINTRPTTHSHLD3_R,        0x0000000f},
-       {AUD_PDF_DDS_CNST_BYTE2,        0x06},
-       {AUD_PDF_DDS_CNST_BYTE1,        0x82},
-       {AUD_PDF_DDS_CNST_BYTE0,        0x12},
-       {AUD_QAM_MODE,                  0x05},
-       {AUD_PHACC_FREQ_8MSB,           0x34},
-       {AUD_PHACC_FREQ_8LSB,           0x4c},
-       {AUD_RATE_ADJ1,                 0x00000100},
-       {AUD_RATE_ADJ2,                 0x00000200},
-       {AUD_RATE_ADJ3,                 0x00000300},
-       {AUD_RATE_ADJ4,                 0x00000400},
-       {AUD_RATE_ADJ5,                 0x00000500},
-       {AUD_THR_FR,                    0x00000000},
-       {AAGC_HYST,                     0x0000001a},
-       {AUD_PILOT_BQD_1_K0,            0x0000755b},
-       {AUD_PILOT_BQD_1_K1,            0x00551340},
-       {AUD_PILOT_BQD_1_K2,            0x006d30be},
-       {AUD_PILOT_BQD_1_K3,            0xffd394af},
-       {AUD_PILOT_BQD_1_K4,            0x00400000},
-       {AUD_PILOT_BQD_2_K0,            0x00040000},
-       {AUD_PILOT_BQD_2_K1,            0x002a4841},
-       {AUD_PILOT_BQD_2_K2,            0x00400000},
-       {AUD_PILOT_BQD_2_K3,            0x00000000},
-       {AUD_PILOT_BQD_2_K4,            0x00000000},
-       {AUD_MODE_CHG_TIMER,            0x00000040},
-       {AUD_AFE_12DB_EN,               0x00000001},
-       {AUD_CORDIC_SHIFT_0,            0x00000007},
-       {AUD_CORDIC_SHIFT_1,            0x00000007},
-       {AUD_DEEMPH0_G0,                0x00000380},
-       {AUD_DEEMPH1_G0,                0x00000380},
-       {AUD_DCOC_0_SRC,                0x0000001a},
-       {AUD_DCOC0_SHIFT,               0x00000000},
-       {AUD_DCOC_0_SHIFT_IN0,          0x0000000a},
-       {AUD_DCOC_0_SHIFT_IN1,          0x00000008},
-       {AUD_DCOC_PASS_IN,              0x00000003},
-       {AUD_IIR3_0_SEL,                0x00000021},
-       {AUD_DN2_AFC,                   0x00000002},
-       {AUD_DCOC_1_SRC,                0x0000001b},
-       {AUD_DCOC1_SHIFT,               0x00000000},
-       {AUD_DCOC_1_SHIFT_IN0,          0x0000000a},
-       {AUD_DCOC_1_SHIFT_IN1,          0x00000008},
-       {AUD_IIR3_1_SEL,                0x00000023},
-       {AUD_RDSI_SEL,                  0x00000017},
-       {AUD_RDSI_SHIFT,                0x00000000},
-       {AUD_RDSQ_SEL,                  0x00000017},
-       {AUD_RDSQ_SHIFT,                0x00000000},
-       {AUD_PLL_INT,                   0x0000001e},
-       {AUD_PLL_DDS,                   0x00000000},
-       {AUD_PLL_FRAC,                  0x0000e542},
-       {AUD_POLYPH80SCALEFAC,          0x00000001},
-       {AUD_START_TIMER,               0x00000000},
-       { /* end of list */ },
+       static const struct rlist a2_bgdk_common[] = {
+               {AUD_ERRLOGPERIOD_R, 0x00000064},
+               {AUD_ERRINTRPTTHSHLD1_R, 0x00000fff},
+               {AUD_ERRINTRPTTHSHLD2_R, 0x0000001f},
+               {AUD_ERRINTRPTTHSHLD3_R, 0x0000000f},
+               {AUD_PDF_DDS_CNST_BYTE2, 0x06},
+               {AUD_PDF_DDS_CNST_BYTE1, 0x82},
+               {AUD_PDF_DDS_CNST_BYTE0, 0x12},
+               {AUD_QAM_MODE, 0x05},
+               {AUD_PHACC_FREQ_8MSB, 0x34},
+               {AUD_PHACC_FREQ_8LSB, 0x4c},
+               {AUD_RATE_ADJ1, 0x00000100},
+               {AUD_RATE_ADJ2, 0x00000200},
+               {AUD_RATE_ADJ3, 0x00000300},
+               {AUD_RATE_ADJ4, 0x00000400},
+               {AUD_RATE_ADJ5, 0x00000500},
+               {AUD_THR_FR, 0x00000000},
+               {AAGC_HYST, 0x0000001a},
+               {AUD_PILOT_BQD_1_K0, 0x0000755b},
+               {AUD_PILOT_BQD_1_K1, 0x00551340},
+               {AUD_PILOT_BQD_1_K2, 0x006d30be},
+               {AUD_PILOT_BQD_1_K3, 0xffd394af},
+               {AUD_PILOT_BQD_1_K4, 0x00400000},
+               {AUD_PILOT_BQD_2_K0, 0x00040000},
+               {AUD_PILOT_BQD_2_K1, 0x002a4841},
+               {AUD_PILOT_BQD_2_K2, 0x00400000},
+               {AUD_PILOT_BQD_2_K3, 0x00000000},
+               {AUD_PILOT_BQD_2_K4, 0x00000000},
+               {AUD_MODE_CHG_TIMER, 0x00000040},
+               {AUD_AFE_12DB_EN, 0x00000001},
+               {AUD_CORDIC_SHIFT_0, 0x00000007},
+               {AUD_CORDIC_SHIFT_1, 0x00000007},
+               {AUD_DEEMPH0_G0, 0x00000380},
+               {AUD_DEEMPH1_G0, 0x00000380},
+               {AUD_DCOC_0_SRC, 0x0000001a},
+               {AUD_DCOC0_SHIFT, 0x00000000},
+               {AUD_DCOC_0_SHIFT_IN0, 0x0000000a},
+               {AUD_DCOC_0_SHIFT_IN1, 0x00000008},
+               {AUD_DCOC_PASS_IN, 0x00000003},
+               {AUD_IIR3_0_SEL, 0x00000021},
+               {AUD_DN2_AFC, 0x00000002},
+               {AUD_DCOC_1_SRC, 0x0000001b},
+               {AUD_DCOC1_SHIFT, 0x00000000},
+               {AUD_DCOC_1_SHIFT_IN0, 0x0000000a},
+               {AUD_DCOC_1_SHIFT_IN1, 0x00000008},
+               {AUD_IIR3_1_SEL, 0x00000023},
+               {AUD_RDSI_SEL, 0x00000017},
+               {AUD_RDSI_SHIFT, 0x00000000},
+               {AUD_RDSQ_SEL, 0x00000017},
+               {AUD_RDSQ_SHIFT, 0x00000000},
+               {AUD_PLL_INT, 0x0000001e},
+               {AUD_PLL_DDS, 0x00000000},
+               {AUD_PLL_FRAC, 0x0000e542},
+               {AUD_POLYPH80SCALEFAC, 0x00000001},
+               {AUD_START_TIMER, 0x00000000},
+               { /* end of list */ },
        };
 
        static const struct rlist a2_bg[] = {
-       {AUD_DMD_RA_DDS,                0x002a4f2f},
-       {AUD_C1_UP_THR,                 0x00007000},
-       {AUD_C1_LO_THR,                 0x00005400},
-       {AUD_C2_UP_THR,                 0x00005400},
-       {AUD_C2_LO_THR,                 0x00003000},
+               {AUD_DMD_RA_DDS, 0x002a4f2f},
+               {AUD_C1_UP_THR, 0x00007000},
+               {AUD_C1_LO_THR, 0x00005400},
+               {AUD_C2_UP_THR, 0x00005400},
+               {AUD_C2_LO_THR, 0x00003000},
                { /* end of list */ },
        };
 
        static const struct rlist a2_dk[] = {
-       {AUD_DMD_RA_DDS,                0x002a4f2f},
-       {AUD_C1_UP_THR,                 0x00007000},
-       {AUD_C1_LO_THR,                 0x00005400},
-       {AUD_C2_UP_THR,                 0x00005400},
-       {AUD_C2_LO_THR,                 0x00003000},
-       {AUD_DN0_FREQ,                  0x00003a1c},
-       {AUD_DN2_FREQ,                  0x0000d2e0},
+               {AUD_DMD_RA_DDS, 0x002a4f2f},
+               {AUD_C1_UP_THR, 0x00007000},
+               {AUD_C1_LO_THR, 0x00005400},
+               {AUD_C2_UP_THR, 0x00005400},
+               {AUD_C2_LO_THR, 0x00003000},
+               {AUD_DN0_FREQ, 0x00003a1c},
+               {AUD_DN2_FREQ, 0x0000d2e0},
                { /* end of list */ },
        };
-/* unknown, probably NTSC-M */
-       static const struct rlist a2_m[] = {
-       {AUD_DMD_RA_DDS,                0x002a0425},
-       {AUD_C1_UP_THR,                 0x00003c00},
-       {AUD_C1_LO_THR,                 0x00003000},
-       {AUD_C2_UP_THR,                 0x00006000},
-       {AUD_C2_LO_THR,                 0x00003c00},
-       {AUD_DEEMPH0_A0,                0x00007a80},
-       {AUD_DEEMPH1_A0,                0x00007a80},
-       {AUD_DEEMPH0_G0,                0x00001200},
-       {AUD_DEEMPH1_G0,                0x00001200},
-       {AUD_DN0_FREQ,                  0x0000283b},
-       {AUD_DN1_FREQ,                  0x00003418},
-       {AUD_DN2_FREQ,                  0x000029c7},
-       {AUD_POLY0_DDS_CONSTANT,        0x000a7540},
+
+       static const struct rlist a1_i[] = {
+               {AUD_ERRLOGPERIOD_R, 0x00000064},
+               {AUD_ERRINTRPTTHSHLD1_R, 0x00000fff},
+               {AUD_ERRINTRPTTHSHLD2_R, 0x0000001f},
+               {AUD_ERRINTRPTTHSHLD3_R, 0x0000000f},
+               {AUD_PDF_DDS_CNST_BYTE2, 0x06},
+               {AUD_PDF_DDS_CNST_BYTE1, 0x82},
+               {AUD_PDF_DDS_CNST_BYTE0, 0x12},
+               {AUD_QAM_MODE, 0x05},
+               {AUD_PHACC_FREQ_8MSB, 0x3a},
+               {AUD_PHACC_FREQ_8LSB, 0x93},
+               {AUD_DMD_RA_DDS, 0x002a4f2f},
+               {AUD_PLL_INT, 0x0000001e},
+               {AUD_PLL_DDS, 0x00000004},
+               {AUD_PLL_FRAC, 0x0000e542},
+               {AUD_RATE_ADJ1, 0x00000100},
+               {AUD_RATE_ADJ2, 0x00000200},
+               {AUD_RATE_ADJ3, 0x00000300},
+               {AUD_RATE_ADJ4, 0x00000400},
+               {AUD_RATE_ADJ5, 0x00000500},
+               {AUD_THR_FR, 0x00000000},
+               {AUD_PILOT_BQD_1_K0, 0x0000755b},
+               {AUD_PILOT_BQD_1_K1, 0x00551340},
+               {AUD_PILOT_BQD_1_K2, 0x006d30be},
+               {AUD_PILOT_BQD_1_K3, 0xffd394af},
+               {AUD_PILOT_BQD_1_K4, 0x00400000},
+               {AUD_PILOT_BQD_2_K0, 0x00040000},
+               {AUD_PILOT_BQD_2_K1, 0x002a4841},
+               {AUD_PILOT_BQD_2_K2, 0x00400000},
+               {AUD_PILOT_BQD_2_K3, 0x00000000},
+               {AUD_PILOT_BQD_2_K4, 0x00000000},
+               {AUD_MODE_CHG_TIMER, 0x00000060},
+               {AUD_AFE_12DB_EN, 0x00000001},
+               {AAGC_HYST, 0x0000000a},
+               {AUD_CORDIC_SHIFT_0, 0x00000007},
+               {AUD_CORDIC_SHIFT_1, 0x00000007},
+               {AUD_C1_UP_THR, 0x00007000},
+               {AUD_C1_LO_THR, 0x00005400},
+               {AUD_C2_UP_THR, 0x00005400},
+               {AUD_C2_LO_THR, 0x00003000},
+               {AUD_DCOC_0_SRC, 0x0000001a},
+               {AUD_DCOC0_SHIFT, 0x00000000},
+               {AUD_DCOC_0_SHIFT_IN0, 0x0000000a},
+               {AUD_DCOC_0_SHIFT_IN1, 0x00000008},
+               {AUD_DCOC_PASS_IN, 0x00000003},
+               {AUD_IIR3_0_SEL, 0x00000021},
+               {AUD_DN2_AFC, 0x00000002},
+               {AUD_DCOC_1_SRC, 0x0000001b},
+               {AUD_DCOC1_SHIFT, 0x00000000},
+               {AUD_DCOC_1_SHIFT_IN0, 0x0000000a},
+               {AUD_DCOC_1_SHIFT_IN1, 0x00000008},
+               {AUD_IIR3_1_SEL, 0x00000023},
+               {AUD_DN0_FREQ, 0x000035a3},
+               {AUD_DN2_FREQ, 0x000029c7},
+               {AUD_CRDC0_SRC_SEL, 0x00000511},
+               {AUD_IIR1_0_SEL, 0x00000001},
+               {AUD_IIR1_1_SEL, 0x00000000},
+               {AUD_IIR3_2_SEL, 0x00000003},
+               {AUD_IIR3_2_SHIFT, 0x00000000},
+               {AUD_IIR3_0_SEL, 0x00000002},
+               {AUD_IIR2_0_SEL, 0x00000021},
+               {AUD_IIR2_0_SHIFT, 0x00000002},
+               {AUD_DEEMPH0_SRC_SEL, 0x0000000b},
+               {AUD_DEEMPH1_SRC_SEL, 0x0000000b},
+               {AUD_POLYPH80SCALEFAC, 0x00000001},
+               {AUD_START_TIMER, 0x00000000},
                { /* end of list */ },
        };
 
-       static const struct rlist a2_deemph50[] = {
-       {AUD_DEEMPH0_G0,                0x00000380},
-       {AUD_DEEMPH1_G0,                0x00000380},
-       {AUD_DEEMPHGAIN_R,              0x000011e1},
-       {AUD_DEEMPHNUMER1_R,            0x0002a7bc},
-       {AUD_DEEMPHNUMER2_R,            0x0003023c},
-       { /* end of list */ },
+       static const struct rlist am_l[] = {
+               {AUD_ERRLOGPERIOD_R, 0x00000064},
+               {AUD_ERRINTRPTTHSHLD1_R, 0x00000FFF},
+               {AUD_ERRINTRPTTHSHLD2_R, 0x0000001F},
+               {AUD_ERRINTRPTTHSHLD3_R, 0x0000000F},
+               {AUD_PDF_DDS_CNST_BYTE2, 0x48},
+               {AUD_PDF_DDS_CNST_BYTE1, 0x3D},
+               {AUD_QAM_MODE, 0x00},
+               {AUD_PDF_DDS_CNST_BYTE0, 0xf5},
+               {AUD_PHACC_FREQ_8MSB, 0x3a},
+               {AUD_PHACC_FREQ_8LSB, 0x4a},
+               {AUD_DEEMPHGAIN_R, 0x00006680},
+               {AUD_DEEMPHNUMER1_R, 0x000353DE},
+               {AUD_DEEMPHNUMER2_R, 0x000001B1},
+               {AUD_DEEMPHDENOM1_R, 0x0000F3D0},
+               {AUD_DEEMPHDENOM2_R, 0x00000000},
+               {AUD_FM_MODE_ENABLE, 0x00000007},
+               {AUD_POLYPH80SCALEFAC, 0x00000003},
+               {AUD_AFE_12DB_EN, 0x00000001},
+               {AAGC_GAIN, 0x00000000},
+               {AAGC_HYST, 0x00000018},
+               {AAGC_DEF, 0x00000020},
+               {AUD_DN0_FREQ, 0x00000000},
+               {AUD_POLY0_DDS_CONSTANT, 0x000E4DB2},
+               {AUD_DCOC_0_SRC, 0x00000021},
+               {AUD_IIR1_0_SEL, 0x00000000},
+               {AUD_IIR1_0_SHIFT, 0x00000007},
+               {AUD_IIR1_1_SEL, 0x00000002},
+               {AUD_IIR1_1_SHIFT, 0x00000000},
+               {AUD_DCOC_1_SRC, 0x00000003},
+               {AUD_DCOC1_SHIFT, 0x00000000},
+               {AUD_DCOC_PASS_IN, 0x00000000},
+               {AUD_IIR1_2_SEL, 0x00000023},
+               {AUD_IIR1_2_SHIFT, 0x00000000},
+               {AUD_IIR1_3_SEL, 0x00000004},
+               {AUD_IIR1_3_SHIFT, 0x00000007},
+               {AUD_IIR1_4_SEL, 0x00000005},
+               {AUD_IIR1_4_SHIFT, 0x00000007},
+               {AUD_IIR3_0_SEL, 0x00000007},
+               {AUD_IIR3_0_SHIFT, 0x00000000},
+               {AUD_DEEMPH0_SRC_SEL, 0x00000011},
+               {AUD_DEEMPH0_SHIFT, 0x00000000},
+               {AUD_DEEMPH0_G0, 0x00007000},
+               {AUD_DEEMPH0_A0, 0x00000000},
+               {AUD_DEEMPH0_B0, 0x00000000},
+               {AUD_DEEMPH0_A1, 0x00000000},
+               {AUD_DEEMPH0_B1, 0x00000000},
+               {AUD_DEEMPH1_SRC_SEL, 0x00000011},
+               {AUD_DEEMPH1_SHIFT, 0x00000000},
+               {AUD_DEEMPH1_G0, 0x00007000},
+               {AUD_DEEMPH1_A0, 0x00000000},
+               {AUD_DEEMPH1_B0, 0x00000000},
+               {AUD_DEEMPH1_A1, 0x00000000},
+               {AUD_DEEMPH1_B1, 0x00000000},
+               {AUD_OUT0_SEL, 0x0000003F},
+               {AUD_OUT1_SEL, 0x0000003F},
+               {AUD_DMD_RA_DDS, 0x00F5C285},
+               {AUD_PLL_INT, 0x0000001E},
+               {AUD_PLL_DDS, 0x00000000},
+               {AUD_PLL_FRAC, 0x0000E542},
+               {AUD_RATE_ADJ1, 0x00000100},
+               {AUD_RATE_ADJ2, 0x00000200},
+               {AUD_RATE_ADJ3, 0x00000300},
+               {AUD_RATE_ADJ4, 0x00000400},
+               {AUD_RATE_ADJ5, 0x00000500},
+               {AUD_RATE_THRES_DMD, 0x000000C0},
+               { /* end of list */ },
        };
 
-       static const struct rlist a2_deemph75[] = {
-       {AUD_DEEMPH0_G0,                0x00000480},
-       {AUD_DEEMPH1_G0,                0x00000480},
-       {AUD_DEEMPHGAIN_R,              0x00009000},
-       {AUD_DEEMPHNUMER1_R,            0x000353de},
-       {AUD_DEEMPHNUMER2_R,            0x000001b1},
+       static const struct rlist a2_deemph50[] = {
+               {AUD_DEEMPH0_G0, 0x00000380},
+               {AUD_DEEMPH1_G0, 0x00000380},
+               {AUD_DEEMPHGAIN_R, 0x000011e1},
+               {AUD_DEEMPHNUMER1_R, 0x0002a7bc},
+               {AUD_DEEMPHNUMER2_R, 0x0003023c},
                { /* end of list */ },
        };
 
        set_audio_start(core, SEL_A2);
-       set_audio_registers(core, a2_common);
        switch (core->tvaudio) {
-       case WW_A2_BG:
-               dprintk("%s PAL-BG A2 (status: known-good)\n",__FUNCTION__);
-       set_audio_registers(core, a2_bg);
-       set_audio_registers(core, a2_deemph50);
+       case WW_BG:
+               dprintk("%s PAL-BG A1/2 (status: known-good)\n", __FUNCTION__);
+               set_audio_registers(core, a2_bgdk_common);
+               set_audio_registers(core, a2_bg);
+               set_audio_registers(core, a2_deemph50);
                break;
-       case WW_A2_DK:
-               dprintk("%s PAL-DK A2 (status: known-good)\n",__FUNCTION__);
-       set_audio_registers(core, a2_dk);
-       set_audio_registers(core, a2_deemph50);
+       case WW_DK:
+               dprintk("%s PAL-DK A1/2 (status: known-good)\n", __FUNCTION__);
+               set_audio_registers(core, a2_bgdk_common);
+               set_audio_registers(core, a2_dk);
+               set_audio_registers(core, a2_deemph50);
                break;
-       case WW_A2_M:
-               dprintk("%s NTSC-M A2 (status: unknown)\n",__FUNCTION__);
-       set_audio_registers(core, a2_m);
-       set_audio_registers(core, a2_deemph75);
+       case WW_I:
+               dprintk("%s PAL-I A1 (status: known-good)\n", __FUNCTION__);
+               set_audio_registers(core, a1_i);
+               set_audio_registers(core, a2_deemph50);
+               break;
+       case WW_L:
+               dprintk("%s AM-L (status: devel)\n", __FUNCTION__);
+               set_audio_registers(core, am_l);
+               break;
+       default:
+               dprintk("%s Warning: wrong value\n", __FUNCTION__);
+               return;
                break;
        };
 
@@ -656,71 +633,71 @@ static void set_audio_standard_EIAJ(struct cx88_core *core)
 
                { /* end of list */ },
        };
-       dprintk("%s (status: unknown)\n",__FUNCTION__);
+       dprintk("%s (status: unknown)\n", __FUNCTION__);
 
        set_audio_start(core, SEL_EIAJ);
        set_audio_registers(core, eiaj);
        set_audio_finish(core, EN_EIAJ_AUTO_STEREO);
 }
 
-static void set_audio_standard_FM(struct cx88_core *core, enum cx88_deemph_type deemph)
+static void set_audio_standard_FM(struct cx88_core *core,
+                                 enum cx88_deemph_type deemph)
 {
        static const struct rlist fm_deemph_50[] = {
-               { AUD_DEEMPH0_G0,       0x0C45 },
-               { AUD_DEEMPH0_A0,       0x6262 },
-               { AUD_DEEMPH0_B0,       0x1C29 },
-               { AUD_DEEMPH0_A1,       0x3FC66},
-               { AUD_DEEMPH0_B1,       0x399A },
-
-               { AUD_DEEMPH1_G0,       0x0D80 },
-               { AUD_DEEMPH1_A0,       0x6262 },
-               { AUD_DEEMPH1_B0,       0x1C29 },
-               { AUD_DEEMPH1_A1,       0x3FC66},
-               { AUD_DEEMPH1_B1,       0x399A},
-
-               { AUD_POLYPH80SCALEFAC, 0x0003},
+               {AUD_DEEMPH0_G0, 0x0C45},
+               {AUD_DEEMPH0_A0, 0x6262},
+               {AUD_DEEMPH0_B0, 0x1C29},
+               {AUD_DEEMPH0_A1, 0x3FC66},
+               {AUD_DEEMPH0_B1, 0x399A},
+
+               {AUD_DEEMPH1_G0, 0x0D80},
+               {AUD_DEEMPH1_A0, 0x6262},
+               {AUD_DEEMPH1_B0, 0x1C29},
+               {AUD_DEEMPH1_A1, 0x3FC66},
+               {AUD_DEEMPH1_B1, 0x399A},
+
+               {AUD_POLYPH80SCALEFAC, 0x0003},
                { /* end of list */ },
        };
        static const struct rlist fm_deemph_75[] = {
-               { AUD_DEEMPH0_G0,       0x091B },
-               { AUD_DEEMPH0_A0,       0x6B68 },
-               { AUD_DEEMPH0_B0,       0x11EC },
-               { AUD_DEEMPH0_A1,       0x3FC66},
-               { AUD_DEEMPH0_B1,       0x399A },
-
-               { AUD_DEEMPH1_G0,       0x0AA0 },
-               { AUD_DEEMPH1_A0,       0x6B68 },
-               { AUD_DEEMPH1_B0,       0x11EC },
-               { AUD_DEEMPH1_A1,       0x3FC66},
-               { AUD_DEEMPH1_B1,       0x399A},
-
-               { AUD_POLYPH80SCALEFAC, 0x0003},
+               {AUD_DEEMPH0_G0, 0x091B},
+               {AUD_DEEMPH0_A0, 0x6B68},
+               {AUD_DEEMPH0_B0, 0x11EC},
+               {AUD_DEEMPH0_A1, 0x3FC66},
+               {AUD_DEEMPH0_B1, 0x399A},
+
+               {AUD_DEEMPH1_G0, 0x0AA0},
+               {AUD_DEEMPH1_A0, 0x6B68},
+               {AUD_DEEMPH1_B0, 0x11EC},
+               {AUD_DEEMPH1_A1, 0x3FC66},
+               {AUD_DEEMPH1_B1, 0x399A},
+
+               {AUD_POLYPH80SCALEFAC, 0x0003},
                { /* end of list */ },
        };
 
        /* It is enough to leave default values? */
        static const struct rlist fm_no_deemph[] = {
 
-               { AUD_POLYPH80SCALEFAC, 0x0003},
+               {AUD_POLYPH80SCALEFAC, 0x0003},
                { /* end of list */ },
        };
 
-       dprintk("%s (status: unknown)\n",__FUNCTION__);
+       dprintk("%s (status: unknown)\n", __FUNCTION__);
        set_audio_start(core, SEL_FMRADIO);
 
-       switch (deemph)
-       {
-               case FM_NO_DEEMPH:
-                       set_audio_registers(core, fm_no_deemph);
-                       break;
+       switch (deemph) {
+       case FM_NO_DEEMPH:
+               set_audio_registers(core, fm_no_deemph);
+               break;
 
-               case FM_DEEMPH_50:
-                       set_audio_registers(core, fm_deemph_50);
-                       break;
+       case FM_DEEMPH_50:
+               set_audio_registers(core, fm_deemph_50);
+               break;
 
-               case FM_DEEMPH_75:
-                       set_audio_registers(core, fm_deemph_75);
-                       break;
+       case FM_DEEMPH_75:
+               set_audio_registers(core, fm_deemph_75);
+               break;
        }
 
        set_audio_finish(core, EN_FMRADIO_AUTO_STEREO);
@@ -728,36 +705,64 @@ static void set_audio_standard_FM(struct cx88_core *core, enum cx88_deemph_type
 
 /* ----------------------------------------------------------- */
 
+int cx88_detect_nicam(struct cx88_core *core)
+{
+       int i, j = 0;
+
+       dprintk("start nicam autodetect.\n");
+
+       for (i = 0; i < 6; i++) {
+               /* if bit1=1 then nicam is detected */
+               j += ((cx_read(AUD_NICAM_STATUS2) & 0x02) >> 1);
+
+               /* 3x detected: absolutly sure now */
+               if (j == 3) {
+                       dprintk("nicam is detected.\n");
+                       return 1;
+               }
+
+               /* wait a little bit for next reading status */
+               msleep(10);
+       }
+
+       dprintk("nicam is not detected.\n");
+       return 0;
+}
+
 void cx88_set_tvaudio(struct cx88_core *core)
 {
        switch (core->tvaudio) {
        case WW_BTSC:
                set_audio_standard_BTSC(core, 0, EN_BTSC_AUTO_STEREO);
                break;
-       case WW_NICAM_BGDKL:
-               set_audio_standard_NICAM_L(core,0);
-               break;
-       case WW_NICAM_I:
-               set_audio_standard_PAL_I(core,0);
-               break;
-       case WW_A2_BG:
-       case WW_A2_DK:
-       case WW_A2_M:
-       set_audio_standard_A2(core, EN_A2_FORCE_MONO1);
+       case WW_BG:
+       case WW_DK:
+       case WW_I:
+       case WW_L:
+               /* prepare all dsp registers */
+               set_audio_standard_A2(core, EN_A2_FORCE_MONO1);
+
+               /* set nicam mode - otherwise
+                  AUD_NICAM_STATUS2 contains wrong values */
+               set_audio_standard_NICAM(core, EN_NICAM_AUTO_STEREO);
+               if (0 == cx88_detect_nicam(core)) {
+                       /* fall back to fm / am mono */
+                       set_audio_standard_A2(core, EN_A2_FORCE_MONO1);
+                       core->use_nicam = 0;
+               } else {
+                       core->use_nicam = 1;
+               }
                break;
        case WW_EIAJ:
                set_audio_standard_EIAJ(core);
                break;
        case WW_FM:
-               set_audio_standard_FM(core,FM_NO_DEEMPH);
-               break;
-       case WW_SYSTEM_L_AM:
-               set_audio_standard_NICAM_L(core, 1);
+               set_audio_standard_FM(core, FM_NO_DEEMPH);
                break;
        case WW_NONE:
        default:
                printk("%s/0: unknown tv audio mode [%d]\n",
-               core->name, core->tvaudio);
+                      core->name, core->tvaudio);
                break;
        }
        return;
@@ -766,24 +771,16 @@ void cx88_set_tvaudio(struct cx88_core *core)
 void cx88_newstation(struct cx88_core *core)
 {
        core->audiomode_manual = UNSET;
-
-       switch (core->tvaudio) {
-       case WW_SYSTEM_L_AM:
-               /* try nicam ... */
-               core->audiomode_current = V4L2_TUNER_MODE_STEREO;
-               set_audio_standard_NICAM_L(core, 1);
-               break;
-       }
 }
 
 void cx88_get_stereo(struct cx88_core *core, struct v4l2_tuner *t)
 {
-       static char *m[] = {"stereo", "dual mono", "mono", "sap"};
-       static char *p[] = {"no pilot", "pilot c1", "pilot c2", "?"};
-       u32 reg,mode,pilot;
+       static char *m[] = { "stereo", "dual mono", "mono", "sap" };
+       static char *p[] = { "no pilot", "pilot c1", "pilot c2", "?" };
+       u32 reg, mode, pilot;
 
-       reg   = cx_read(AUD_STATUS);
-       mode  = reg & 0x03;
+       reg = cx_read(AUD_STATUS);
+       mode = reg & 0x03;
        pilot = (reg >> 2) & 0x03;
 
        if (core->astat != reg)
@@ -800,14 +797,13 @@ void cx88_get_stereo(struct cx88_core *core, struct v4l2_tuner *t)
 
 # if 0
        t->capability = V4L2_TUNER_CAP_STEREO | V4L2_TUNER_CAP_SAP |
-               V4L2_TUNER_CAP_LANG1 | V4L2_TUNER_CAP_LANG2;
+           V4L2_TUNER_CAP_LANG1 | V4L2_TUNER_CAP_LANG2;
        t->rxsubchans = V4L2_TUNER_SUB_MONO;
-       t->audmode    = V4L2_TUNER_MODE_MONO;
+       t->audmode = V4L2_TUNER_MODE_MONO;
 
        switch (core->tvaudio) {
        case WW_BTSC:
-               t->capability = V4L2_TUNER_CAP_STEREO |
-                       V4L2_TUNER_CAP_SAP;
+               t->capability = V4L2_TUNER_CAP_STEREO | V4L2_TUNER_CAP_SAP;
                t->rxsubchans = V4L2_TUNER_SUB_STEREO;
                if (1 == pilot) {
                        /* SAP */
@@ -819,13 +815,15 @@ void cx88_get_stereo(struct cx88_core *core, struct v4l2_tuner *t)
        case WW_A2_M:
                if (1 == pilot) {
                        /* stereo */
-                       t->rxsubchans = V4L2_TUNER_SUB_MONO | V4L2_TUNER_SUB_STEREO;
+                       t->rxsubchans =
+                           V4L2_TUNER_SUB_MONO | V4L2_TUNER_SUB_STEREO;
                        if (0 == mode)
                                t->audmode = V4L2_TUNER_MODE_STEREO;
                }
                if (2 == pilot) {
                        /* dual language -- FIXME */
-                       t->rxsubchans = V4L2_TUNER_SUB_LANG1 | V4L2_TUNER_SUB_LANG2;
+                       t->rxsubchans =
+                           V4L2_TUNER_SUB_LANG1 | V4L2_TUNER_SUB_LANG2;
                        t->audmode = V4L2_TUNER_MODE_LANG1;
                }
                break;
@@ -840,7 +838,7 @@ void cx88_get_stereo(struct cx88_core *core, struct v4l2_tuner *t)
                        t->audmode = V4L2_TUNER_MODE_STEREO;
                        t->rxsubchans |= V4L2_TUNER_SUB_STEREO;
                }
-               break ;
+               break;
        default:
                /* nothing */
                break;
@@ -851,7 +849,7 @@ void cx88_get_stereo(struct cx88_core *core, struct v4l2_tuner *t)
 
 void cx88_set_stereo(struct cx88_core *core, u32 mode, int manual)
 {
-       u32 ctl  = UNSET;
+       u32 ctl = UNSET;
        u32 mask = UNSET;
 
        if (manual) {
@@ -879,68 +877,58 @@ void cx88_set_stereo(struct cx88_core *core, u32 mode, int manual)
                        break;
                }
                break;
-       case WW_A2_BG:
-       case WW_A2_DK:
-       case WW_A2_M:
-               switch (mode) {
-               case V4L2_TUNER_MODE_MONO:
-               case V4L2_TUNER_MODE_LANG1:
-               set_audio_standard_A2(core, EN_A2_FORCE_MONO1);
-                       break;
-               case V4L2_TUNER_MODE_LANG2:
-               set_audio_standard_A2(core, EN_A2_FORCE_MONO2);
-                       break;
-               case V4L2_TUNER_MODE_STEREO:
-               set_audio_standard_A2(core, EN_A2_FORCE_STEREO);
-                       break;
-               }
-               break;
-       case WW_NICAM_BGDKL:
-               switch (mode) {
-               case V4L2_TUNER_MODE_MONO:
-                       ctl  = EN_NICAM_FORCE_MONO1;
-                       mask = 0x3f;
-                       break;
-               case V4L2_TUNER_MODE_LANG1:
-                       ctl  = EN_NICAM_AUTO_MONO2;
-                       mask = 0x3f;
-                       break;
-               case V4L2_TUNER_MODE_STEREO:
-                       ctl  = EN_NICAM_FORCE_STEREO | EN_DMTRX_LR;
-                       mask = 0x93f;
-                       break;
-               }
-               break;
-       case WW_SYSTEM_L_AM:
-               switch (mode) {
-               case V4L2_TUNER_MODE_MONO:
-               case V4L2_TUNER_MODE_LANG1:  /* FIXME */
-                       set_audio_standard_NICAM_L(core, 0);
-                       break;
-               case V4L2_TUNER_MODE_STEREO:
-                       set_audio_standard_NICAM_L(core, 1);
-                       break;
-               }
-               break;
-       case WW_NICAM_I:
-               switch (mode) {
-               case V4L2_TUNER_MODE_MONO:
-               case V4L2_TUNER_MODE_LANG1:
-                       set_audio_standard_PAL_I(core, 0);
-                       break;
-               case V4L2_TUNER_MODE_STEREO:
-                       set_audio_standard_PAL_I(core, 1);
-                       break;
+       case WW_BG:
+       case WW_DK:
+       case WW_I:
+       case WW_L:
+               if (1 == core->use_nicam) {
+                       switch (mode) {
+                       case V4L2_TUNER_MODE_MONO:
+                       case V4L2_TUNER_MODE_LANG1:
+                               set_audio_standard_NICAM(core,
+                                                        EN_NICAM_FORCE_MONO1);
+                               break;
+                       case V4L2_TUNER_MODE_LANG2:
+                               set_audio_standard_NICAM(core,
+                                                        EN_NICAM_FORCE_MONO2);
+                               break;
+                       case V4L2_TUNER_MODE_STEREO:
+                               set_audio_standard_NICAM(core,
+                                                        EN_NICAM_FORCE_STEREO);
+                               break;
+                       }
+               } else {
+                       if ((core->tvaudio == WW_I) || (core->tvaudio == WW_L)) {
+                               /* fall back to fm / am mono */
+                               set_audio_standard_A2(core, EN_A2_FORCE_MONO1);
+                       } else {
+                               /* TODO: Add A2 autodection */
+                               switch (mode) {
+                               case V4L2_TUNER_MODE_MONO:
+                               case V4L2_TUNER_MODE_LANG1:
+                                       set_audio_standard_A2(core,
+                                                             EN_A2_FORCE_MONO1);
+                                       break;
+                               case V4L2_TUNER_MODE_LANG2:
+                                       set_audio_standard_A2(core,
+                                                             EN_A2_FORCE_MONO2);
+                                       break;
+                               case V4L2_TUNER_MODE_STEREO:
+                                       set_audio_standard_A2(core,
+                                                             EN_A2_FORCE_STEREO);
+                                       break;
+                               }
+                       }
                }
                break;
        case WW_FM:
                switch (mode) {
                case V4L2_TUNER_MODE_MONO:
-                       ctl  = EN_FMRADIO_FORCE_MONO;
+                       ctl = EN_FMRADIO_FORCE_MONO;
                        mask = 0x3f;
                        break;
                case V4L2_TUNER_MODE_STEREO:
-                       ctl  = EN_FMRADIO_AUTO_STEREO;
+                       ctl = EN_FMRADIO_AUTO_STEREO;
                        mask = 0x3f;
                        break;
                }
@@ -970,8 +958,8 @@ int cx88_audio_thread(void *data)
                        break;
 
                /* just monitor the audio status for now ... */
-               memset(&t,0,sizeof(t));
-               cx88_get_stereo(core,&t);
+               memset(&t, 0, sizeof(t));
+               cx88_get_stereo(core, &t);
 
                if (UNSET != core->audiomode_manual)
                        /* manually set, don't do anything. */
index 3dbc074fb515a10c62783e1bda568b63a8a1c596..24a48f8a48c18a16be2dd96e278703ae7f153753 100644 (file)
@@ -34,6 +34,9 @@
 
 #include "cx88.h"
 
+/* Include V4L1 specific functions. Should be removed soon */
+#include <linux/videodev.h>
+
 MODULE_DESCRIPTION("v4l2 driver module for cx2388x based TV cards");
 MODULE_AUTHOR("Gerd Knorr <kraxel@bytesex.org> [SuSE Labs]");
 MODULE_LICENSE("GPL");
@@ -100,7 +103,7 @@ static struct cx88_tvnorm tvnorms[] = {
                .id        = V4L2_STD_PAL_I,
                .cxiformat = VideoFormatPAL,
                .cxoformat = 0x181f0008,
-        },{
+       },{
                .name      = "PAL-M",
                .id        = V4L2_STD_PAL_M,
                .cxiformat = VideoFormatPALM,
@@ -470,7 +473,7 @@ static int restart_video_queue(struct cx8800_dev    *dev,
        struct list_head *item;
 
        if (!list_empty(&q->active)) {
-               buf = list_entry(q->active.next, struct cx88_buffer, vb.queue);
+               buf = list_entry(q->active.next, struct cx88_buffer, vb.queue);
                dprintk(2,"restart_queue [%p/%d]: restart dma\n",
                        buf, buf->vb.i);
                start_video_dma(dev, q, buf);
@@ -486,7 +489,7 @@ static int restart_video_queue(struct cx8800_dev    *dev,
        for (;;) {
                if (list_empty(&q->queued))
                        return 0;
-               buf = list_entry(q->queued.next, struct cx88_buffer, vb.queue);
+               buf = list_entry(q->queued.next, struct cx88_buffer, vb.queue);
                if (NULL == prev) {
                        list_del(&buf->vb.queue);
                        list_add_tail(&buf->vb.queue,&q->active);
@@ -783,11 +786,11 @@ static int video_open(struct inode *inode, struct file *file)
                cx88_call_i2c_clients(core,AUDC_SET_RADIO,NULL);
        }
 
-        return 0;
+       return 0;
 }
 
 static ssize_t
-video_read(struct file *file, char *data, size_t count, loff_t *ppos)
+video_read(struct file *file, char __user *data, size_t count, loff_t *ppos)
 {
        struct cx8800_fh *fh = file->private_data;
 
@@ -922,7 +925,7 @@ static int set_control(struct cx88_core *core, struct v4l2_control *ctl)
 {
        /* struct cx88_core *core = dev->core; */
        struct cx88_ctrl *c = NULL;
-        u32 v_sat_value;
+       u32 v_sat_value;
        u32 value;
        int i;
 
@@ -1187,7 +1190,7 @@ static int video_do_ioctl(struct inode *inode, struct file *file,
                struct v4l2_format *f = arg;
                return cx8800_try_fmt(dev,fh,f);
        }
-
+#ifdef HAVE_V4L1
        /* --- streaming capture ------------------------------------- */
        case VIDIOCGMBUF:
        {
@@ -1213,6 +1216,7 @@ static int video_do_ioctl(struct inode *inode, struct file *file,
                }
                return 0;
        }
+#endif
        case VIDIOC_REQBUFS:
                return videobuf_reqbufs(get_queue(fh), arg);
 
@@ -1244,7 +1248,6 @@ static int video_do_ioctl(struct inode *inode, struct file *file,
                res_free(dev,fh,res);
                return 0;
        }
-
        default:
                return cx88_do_ioctl( inode, file, fh->radio, core, cmd, arg, video_do_ioctl );
        }
@@ -1252,15 +1255,13 @@ static int video_do_ioctl(struct inode *inode, struct file *file,
 }
 
 int cx88_do_ioctl(struct inode *inode, struct file *file, int radio,
-                  struct cx88_core *core, unsigned int cmd, void *arg, v4l2_kioctl driver_ioctl)
+                 struct cx88_core *core, unsigned int cmd, void *arg, v4l2_kioctl driver_ioctl)
 {
        int err;
 
+       dprintk( 1, "CORE IOCTL: 0x%x\n", cmd );
        if (video_debug > 1)
                cx88_print_ioctl(core->name,cmd);
-       printk( KERN_INFO "CORE IOCTL: 0x%x\n", cmd );
-       cx88_print_ioctl(core->name,cmd);
-       dprintk( 1, "CORE IOCTL: 0x%x\n", cmd );
 
        switch (cmd) {
        /* ---------- tv norms ---------- */
@@ -1401,7 +1402,7 @@ int cx88_do_ioctl(struct inode *inode, struct file *file, int radio,
 
                cx88_get_stereo(core ,t);
                reg = cx_read(MO_DEVICE_STATUS);
-                t->signal = (reg & (1<<5)) ? 0xffff : 0x0000;
+               t->signal = (reg & (1<<5)) ? 0xffff : 0x0000;
                return 0;
        }
        case VIDIOC_S_TUNER:
@@ -1488,7 +1489,7 @@ static int radio_do_ioctl(struct inode *inode, struct file *file,
                struct v4l2_capability *cap = arg;
 
                memset(cap,0,sizeof(*cap));
-                strcpy(cap->driver, "cx8800");
+               strcpy(cap->driver, "cx8800");
                strlcpy(cap->card, cx88_boards[core->board].name,
                        sizeof(cap->card));
                sprintf(cap->bus_info,"PCI:%s", pci_name(dev->pci));
@@ -1505,6 +1506,7 @@ static int radio_do_ioctl(struct inode *inode, struct file *file,
 
                memset(t,0,sizeof(*t));
                strcpy(t->name, "Radio");
+               t->type = V4L2_TUNER_RADIO;
 
                cx88_call_i2c_clients(core,VIDIOC_G_TUNER,t);
                return 0;
@@ -1539,6 +1541,7 @@ static int radio_do_ioctl(struct inode *inode, struct file *file,
                *id = 0;
                return 0;
        }
+#ifdef HAVE_V4L1
        case VIDIOCSTUNER:
        {
                struct video_tuner *v = arg;
@@ -1549,6 +1552,7 @@ static int radio_do_ioctl(struct inode *inode, struct file *file,
                cx88_call_i2c_clients(core,VIDIOCSTUNER,v);
                return 0;
        }
+#endif
        case VIDIOC_S_TUNER:
        {
                struct v4l2_tuner *t = arg;
@@ -1829,8 +1833,8 @@ static int __devinit cx8800_initdev(struct pci_dev *pci_dev,
 
        /* print pci info */
        pci_read_config_byte(pci_dev, PCI_CLASS_REVISION, &dev->pci_rev);
-        pci_read_config_byte(pci_dev, PCI_LATENCY_TIMER,  &dev->pci_lat);
-        printk(KERN_INFO "%s/0: found at %s, rev: %d, irq: %d, "
+       pci_read_config_byte(pci_dev, PCI_LATENCY_TIMER,  &dev->pci_lat);
+       printk(KERN_INFO "%s/0: found at %s, rev: %d, irq: %d, "
               "latency: %d, mmio: 0x%lx\n", core->name,
               pci_name(pci_dev), dev->pci_rev, pci_dev->irq,
               dev->pci_lat,pci_resource_start(pci_dev,0));
@@ -1946,7 +1950,7 @@ fail_free:
 
 static void __devexit cx8800_finidev(struct pci_dev *pci_dev)
 {
-        struct cx8800_dev *dev = pci_get_drvdata(pci_dev);
+       struct cx8800_dev *dev = pci_get_drvdata(pci_dev);
        struct cx88_core *core = dev->core;
 
        /* stop thread */
index f48dd43535688f676ba7a9c2f28418e79377f068..b19d3a9e22981889dd6bc05aaa77faed5f1e6ab2 100644 (file)
@@ -22,7 +22,7 @@
 #include <linux/pci.h>
 #include <linux/i2c.h>
 #include <linux/i2c-algo-bit.h>
-#include <linux/videodev.h>
+#include <linux/videodev2.h>
 #include <linux/kdev_t.h>
 
 #include <media/tuner.h>
@@ -148,7 +148,7 @@ extern struct sram_channel cx88_sram_channels[];
 #define CX88_BOARD_PIXELVIEW                3
 #define CX88_BOARD_ATI_WONDER_PRO           4
 #define CX88_BOARD_WINFAST2000XP_EXPERT     5
-#define CX88_BOARD_AVERTV_303               6
+#define CX88_BOARD_AVERTV_STUDIO_303        6
 #define CX88_BOARD_MSI_TVANYWHERE_MASTER    7
 #define CX88_BOARD_WINFAST_DV2000           8
 #define CX88_BOARD_LEADTEK_PVR2000          9
@@ -174,6 +174,11 @@ extern struct sram_channel cx88_sram_channels[];
 #define CX88_BOARD_ADSTECH_DVB_T_PCI          29
 #define CX88_BOARD_TERRATEC_CINERGY_1400_DVB_T1  30
 #define CX88_BOARD_DVICO_FUSIONHDTV_5_GOLD 31
+#define CX88_BOARD_AVERMEDIA_ULTRATV_MC_550 32
+#define CX88_BOARD_KWORLD_VSTREAM_EXPERT_DVD 33
+#define CX88_BOARD_ATI_HDTVWONDER          34
+#define CX88_BOARD_WINFAST_DTV1000         35
+#define CX88_BOARD_AVERTV_303              36
 
 enum cx88_itype {
        CX88_VMUX_COMPOSITE1 = 1,
@@ -203,8 +208,8 @@ struct cx88_board {
        int                     tda9887_conf;
        struct cx88_input       input[MAX_CX88_INPUT];
        struct cx88_input       radio;
-       int                     blackbird:1;
-       int                     dvb:1;
+       unsigned int            blackbird:1;
+       unsigned int            dvb:1;
 };
 
 struct cx88_subid {
@@ -255,8 +260,8 @@ struct cx88_core {
        /* pci stuff */
        int                        pci_bus;
        int                        pci_slot;
-        u32                        __iomem *lmmio;
-        u8                         __iomem *bmmio;
+       u32                        __iomem *lmmio;
+       u8                         __iomem *bmmio;
        u32                        shadow[SHADOW_MAX];
        int                        pci_irqmask;
 
@@ -287,6 +292,7 @@ struct cx88_core {
        u32                        audiomode_current;
        u32                        input;
        u32                        astat;
+       u32                        use_nicam;
 
        /* IR remote control state */
        struct cx88_IR             *ir;
@@ -370,6 +376,14 @@ struct cx8802_suspend_state {
        int                        disabled;
 };
 
+/* TODO: move this to struct v4l2_mpeg_compression ? */
+struct blackbird_dnr {
+       u32                       mode;
+       u32                       type;
+       u32                       spatial;
+       u32                       temporal;
+};
+
 struct cx8802_dev {
        struct cx88_core           *core;
        spinlock_t                 slock;
@@ -400,6 +414,10 @@ struct cx8802_dev {
 
        /* for switching modulation types */
        unsigned char              ts_gen_cntrl;
+
+       /* mpeg params */
+       struct v4l2_mpeg_compression params;
+       struct blackbird_dnr       dnr_params;
 };
 
 /* ----------------------------------------------------------- */
@@ -514,22 +532,20 @@ extern void cx88_card_setup(struct cx88_core *core);
 
 #define WW_NONE                 1
 #define WW_BTSC                 2
-#define WW_NICAM_I      3
-#define WW_NICAM_BGDKL  4
-#define WW_A1           5
-#define WW_A2_BG        6
-#define WW_A2_DK        7
-#define WW_A2_M                 8
-#define WW_EIAJ                 9
-#define WW_SYSTEM_L_AM 10
-#define WW_I2SPT       11
-#define WW_FM          12
+#define WW_BG           3
+#define WW_DK           4
+#define WW_I            5
+#define WW_L            6
+#define WW_EIAJ                 7
+#define WW_I2SPT        8
+#define WW_FM           9
 
 void cx88_set_tvaudio(struct cx88_core *core);
 void cx88_newstation(struct cx88_core *core);
 void cx88_get_stereo(struct cx88_core *core, struct v4l2_tuner *t);
 void cx88_set_stereo(struct cx88_core *core, u32 mode, int manual);
 int cx88_audio_thread(void *data);
+int cx88_detect_nicam(struct cx88_core *core);
 
 /* ----------------------------------------------------------- */
 /* cx88-input.c                                                */
@@ -541,7 +557,8 @@ void cx88_ir_irq(struct cx88_core *core);
 /* ----------------------------------------------------------- */
 /* cx88-mpeg.c                                                 */
 
-int cx8802_buf_prepare(struct cx8802_dev *dev, struct cx88_buffer *buf);
+int cx8802_buf_prepare(struct cx8802_dev *dev, struct cx88_buffer *buf,
+                       enum v4l2_field field);
 void cx8802_buf_queue(struct cx8802_dev *dev, struct cx88_buffer *buf);
 void cx8802_cancel_buffers(struct cx8802_dev *dev);
 
@@ -562,6 +579,10 @@ extern int cx88_do_ioctl(struct inode *inode, struct file *file, int radio,
 extern int (*cx88_ioctl_hook)(struct inode *inode, struct file *file,
                                unsigned int cmd, void *arg);
 extern unsigned int (*cx88_ioctl_translator)(unsigned int cmd);
+void blackbird_set_params(struct cx8802_dev *dev,
+                               struct v4l2_mpeg_compression *params);
+void blackbird_set_dnr_params(struct cx8802_dev *dev,
+                               struct blackbird_dnr* dnr_params);
 
 /*
  * Local variables:
diff --git a/drivers/media/video/em28xx/Kconfig b/drivers/media/video/em28xx/Kconfig
new file mode 100644 (file)
index 0000000..885fd01
--- /dev/null
@@ -0,0 +1,12 @@
+config VIDEO_EM28XX
+       tristate "Empia EM2800/2820/2840 USB video capture support"
+       depends on VIDEO_DEV && USB && I2C
+       select VIDEO_BUF
+       select VIDEO_TUNER
+       select VIDEO_TVEEPROM
+       select VIDEO_IR
+       ---help---
+         This is a video4linux driver for Empia 28xx based TV cards.
+
+         To compile this driver as a module, choose M here: the
+         module will be called em28xx
diff --git a/drivers/media/video/em28xx/Makefile b/drivers/media/video/em28xx/Makefile
new file mode 100644 (file)
index 0000000..da457a0
--- /dev/null
@@ -0,0 +1,6 @@
+em28xx-objs     := em28xx-video.o em28xx-i2c.o em28xx-cards.o em28xx-core.o \
+                  em28xx-input.o
+
+obj-$(CONFIG_VIDEO_EM28XX) += em28xx.o
+
+EXTRA_CFLAGS += -I$(src)/..
diff --git a/drivers/media/video/em28xx/em28xx-cards.c b/drivers/media/video/em28xx/em28xx-cards.c
new file mode 100644 (file)
index 0000000..57779e6
--- /dev/null
@@ -0,0 +1,292 @@
+/*
+   em28xx-cards.c - driver for Empia EM2800/EM2820/2840 USB video capture devices
+
+   Copyright (C) 2005 Ludovico Cavedon <cavedon@sssup.it>
+                     Markus Rechberger <mrechberger@gmail.com>
+                     Mauro Carvalho Chehab <mchehab@brturbo.com.br>
+                     Sascha Sommer <saschasommer@freenet.de>
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 2 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software
+   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/pci.h>
+#include <linux/delay.h>
+#include <linux/i2c.h>
+#include <linux/usb.h>
+#include <media/tuner.h>
+#include <media/audiochip.h>
+#include <media/tveeprom.h>
+#include "msp3400.h"
+
+#include "em28xx.h"
+
+struct em28xx_board em28xx_boards[] = {
+       [EM2800_BOARD_UNKNOWN] = {
+               .name         = "Unknown EM2800 video grabber",
+               .is_em2800    = 1,
+               .vchannels    = 2,
+               .norm         = VIDEO_MODE_PAL,
+               .tda9887_conf = TDA9887_PRESENT,
+               .has_tuner    = 1,
+               .decoder      = EM28XX_SAA7113,
+               .input           = {{
+                       .type     = EM28XX_VMUX_COMPOSITE1,
+                       .vmux     = 0,
+                       .amux     = 1,
+               },{
+                       .type     = EM28XX_VMUX_SVIDEO,
+                       .vmux     = 9,
+                       .amux     = 1,
+               }},
+       },
+       [EM2820_BOARD_UNKNOWN] = {
+               .name         = "Unknown EM2820/2840 video grabber",
+               .is_em2800    = 0,
+               .vchannels    = 2,
+               .norm         = VIDEO_MODE_PAL,
+               .tda9887_conf = TDA9887_PRESENT,
+               .has_tuner    = 1,
+               .decoder      = EM28XX_SAA7113,
+               .input           = {{
+                       .type     = EM28XX_VMUX_COMPOSITE1,
+                       .vmux     = 0,
+                       .amux     = 1,
+               },{
+                       .type     = EM28XX_VMUX_SVIDEO,
+                       .vmux     = 9,
+                       .amux     = 1,
+               }},
+       },
+       [EM2820_BOARD_TERRATEC_CINERGY_250] = {
+               .name         = "Terratec Cinergy 250 USB",
+               .vchannels    = 3,
+               .norm         = VIDEO_MODE_PAL,
+               .tuner_type   = TUNER_LG_PAL_NEW_TAPC,
+               .tda9887_conf = TDA9887_PRESENT,
+               .has_tuner    = 1,
+               .decoder      = EM28XX_SAA7113,
+               .input          = {{
+                       .type     = EM28XX_VMUX_TELEVISION,
+                       .vmux     = 2,
+                       .amux     = 0,
+               },{
+                       .type     = EM28XX_VMUX_COMPOSITE1,
+                       .vmux     = 0,
+                       .amux     = 1,
+               },{
+                       .type     = EM28XX_VMUX_SVIDEO,
+                       .vmux     = 9,
+                       .amux     = 1,
+               }},
+       },
+       [EM2820_BOARD_PINNACLE_USB_2] = {
+               .name         = "Pinnacle PCTV USB 2",
+               .vchannels    = 3,
+               .norm         = VIDEO_MODE_PAL,
+               .tuner_type   = TUNER_LG_PAL_NEW_TAPC,
+               .tda9887_conf = TDA9887_PRESENT,
+               .has_tuner    = 1,
+               .decoder      = EM28XX_SAA7113,
+               .input          = {{
+                       .type     = EM28XX_VMUX_TELEVISION,
+                       .vmux     = 2,
+                       .amux     = 0,
+               },{
+                       .type     = EM28XX_VMUX_COMPOSITE1,
+                       .vmux     = 0,
+                       .amux     = 1,
+               },{
+                       .type     = EM28XX_VMUX_SVIDEO,
+                       .vmux     = 9,
+                       .amux     = 1,
+               }},
+       },
+       [EM2820_BOARD_HAUPPAUGE_WINTV_USB_2] = {
+               .name         = "Hauppauge WinTV USB 2",
+               .vchannels    = 3,
+               .norm         = VIDEO_MODE_NTSC,
+               .tuner_type   = TUNER_PHILIPS_FM1236_MK3,
+               .tda9887_conf = TDA9887_PRESENT|TDA9887_PORT1_ACTIVE|TDA9887_PORT2_ACTIVE,
+               .has_tuner    = 1,
+               .decoder      = EM28XX_TVP5150,
+               .has_msp34xx  = 1,
+               /*FIXME: S-Video not tested */
+               .input          = {{
+                       .type     = EM28XX_VMUX_TELEVISION,
+                       .vmux     = 0,
+                       .amux     = 6,
+               },{
+                       .type     = EM28XX_VMUX_SVIDEO,
+                       .vmux     = 2,
+                       .amux     = 1,
+               }},
+       },
+       [EM2820_BOARD_MSI_VOX_USB_2] = {
+               .name           = "MSI VOX USB 2.0",
+               .vchannels      = 3,
+               .norm           = VIDEO_MODE_PAL,
+               .tuner_type     = TUNER_LG_PAL_NEW_TAPC,
+               .tda9887_conf   = TDA9887_PRESENT|TDA9887_PORT1_ACTIVE|TDA9887_PORT2_ACTIVE,
+               .has_tuner      = 1,
+               .decoder        = EM28XX_SAA7114,
+               .input          = {{
+                       .type     = EM28XX_VMUX_TELEVISION,
+                       .vmux     = 4,
+                       .amux     = 0,
+               },{
+                       .type     = EM28XX_VMUX_COMPOSITE1,
+                       .vmux     = 0,
+                       .amux     = 1,
+               },{
+                       .type     = EM28XX_VMUX_SVIDEO,
+                       .vmux     = 9,
+                       .amux     = 1,
+               }},
+       },
+       [EM2800_BOARD_TERRATEC_CINERGY_200] = {
+               .name         = "Terratec Cinergy 200 USB",
+               .is_em2800    = 1,
+               .vchannels    = 3,
+               .norm         = VIDEO_MODE_PAL,
+               .tuner_type   = TUNER_LG_PAL_NEW_TAPC,
+               .tda9887_conf = TDA9887_PRESENT,
+               .has_tuner    = 1,
+               .decoder      = EM28XX_SAA7113,
+               .input          = {{
+                       .type     = EM28XX_VMUX_TELEVISION,
+                       .vmux     = 2,
+                       .amux     = 0,
+               },{
+                       .type     = EM28XX_VMUX_COMPOSITE1,
+                       .vmux     = 0,
+                       .amux     = 1,
+               },{
+                       .type     = EM28XX_VMUX_SVIDEO,
+                       .vmux     = 9,
+                       .amux     = 1,
+               }},
+       },
+       [EM2800_BOARD_LEADTEK_WINFAST_USBII] = {
+               .name         = "Leadtek Winfast USB II",
+               .is_em2800    = 1,
+               .vchannels    = 3,
+               .norm         = VIDEO_MODE_PAL,
+               .tuner_type   = TUNER_LG_PAL_NEW_TAPC,
+               .tda9887_conf = TDA9887_PRESENT,
+               .has_tuner    = 1,
+               .decoder      = EM28XX_SAA7113,
+               .input          = {{
+                       .type     = EM28XX_VMUX_TELEVISION,
+                       .vmux     = 2,
+                       .amux     = 0,
+               },{
+                       .type     = EM28XX_VMUX_COMPOSITE1,
+                       .vmux     = 0,
+                       .amux     = 1,
+               },{
+                       .type     = EM28XX_VMUX_SVIDEO,
+                       .vmux     = 9,
+                       .amux     = 1,
+               }},
+       },
+       [EM2800_BOARD_KWORLD_USB2800] = {
+               .name         = "Kworld USB2800",
+               .is_em2800    = 1,
+               .vchannels    = 3,
+               .norm         = VIDEO_MODE_PAL,
+               .tuner_type   = TUNER_PHILIPS_ATSC,
+               .tda9887_conf = TDA9887_PRESENT,
+               .has_tuner    = 1,
+               .decoder      = EM28XX_SAA7113,
+               .input          = {{
+                       .type     = EM28XX_VMUX_TELEVISION,
+                       .vmux     = 2,
+                       .amux     = 0,
+               },{
+                       .type     = EM28XX_VMUX_COMPOSITE1,
+                       .vmux     = 0,
+                       .amux     = 1,
+               },{
+                       .type     = EM28XX_VMUX_SVIDEO,
+                       .vmux     = 9,
+                       .amux     = 1,
+               }},
+       },
+       [EM2820_BOARD_PINNACLE_DVC_90] = {
+               .name         = "Pinnacle Dazzle DVC 90",
+               .vchannels    = 3,
+               .norm         = VIDEO_MODE_PAL,
+               .has_tuner    = 0,
+               .decoder      = EM28XX_SAA7113,
+               .input          = {{
+                       .type     = EM28XX_VMUX_COMPOSITE1,
+                       .vmux     = 0,
+                       .amux     = 1,
+               },{
+                       .type     = EM28XX_VMUX_SVIDEO,
+                       .vmux     = 9,
+                       .amux     = 1,
+               }},
+       },
+};
+const unsigned int em28xx_bcount = ARRAY_SIZE(em28xx_boards);
+
+/* table of devices that work with this driver */
+struct usb_device_id em28xx_id_table [] = {
+       { USB_DEVICE(0xeb1a, 0x2800), .driver_info = EM2800_BOARD_UNKNOWN },
+       { USB_DEVICE(0xeb1a, 0x2820), .driver_info = EM2820_BOARD_MSI_VOX_USB_2 },
+       { USB_DEVICE(0x0ccd, 0x0036), .driver_info = EM2820_BOARD_TERRATEC_CINERGY_250 },
+       { USB_DEVICE(0x2304, 0x0208), .driver_info = EM2820_BOARD_PINNACLE_USB_2 },
+       { USB_DEVICE(0x2040, 0x4200), .driver_info = EM2820_BOARD_HAUPPAUGE_WINTV_USB_2 },
+       { USB_DEVICE(0x2304, 0x0207), .driver_info = EM2820_BOARD_PINNACLE_DVC_90 },
+       { },
+};
+
+void em28xx_card_setup(struct em28xx *dev)
+{
+       /* request some modules */
+       if (dev->model == EM2820_BOARD_HAUPPAUGE_WINTV_USB_2) {
+               struct tveeprom tv;
+               struct v4l2_audioout ao;
+#ifdef CONFIG_MODULES
+               request_module("tveeprom");
+               request_module("ir-kbd-i2c");
+               request_module("msp3400");
+#endif
+               /* Call first TVeeprom */
+
+               dev->i2c_client.addr = 0xa0 >> 1;
+               tveeprom_hauppauge_analog(&dev->i2c_client, &tv, dev->eedata);
+
+               dev->tuner_type= tv.tuner_type;
+               if (tv.audio_processor == AUDIO_CHIP_MSP34XX) {
+                       dev->has_msp34xx=1;
+                       memset (&ao,0,sizeof(ao));
+
+                       ao.index=2;
+                       ao.mode=V4L2_AUDMODE_32BITS;
+                       em28xx_i2c_call_clients(dev, VIDIOC_S_AUDOUT, &ao);
+               } else
+                       dev->has_msp34xx=0;
+       }
+}
+
+EXPORT_SYMBOL(em28xx_boards);
+EXPORT_SYMBOL(em28xx_bcount);
+EXPORT_SYMBOL(em28xx_id_table);
+
+MODULE_DEVICE_TABLE (usb, em28xx_id_table);
diff --git a/drivers/media/video/em28xx/em28xx-core.c b/drivers/media/video/em28xx/em28xx-core.c
new file mode 100644 (file)
index 0000000..d54bc01
--- /dev/null
@@ -0,0 +1,817 @@
+/*
+   em28xx-core.c - driver for Empia EM2800/EM2820/2840 USB video capture devices
+
+   Copyright (C) 2005 Ludovico Cavedon <cavedon@sssup.it>
+                     Markus Rechberger <mrechberger@gmail.com>
+                     Mauro Carvalho Chehab <mchehab@brturbo.com.br>
+                     Sascha Sommer <saschasommer@freenet.de>
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 2 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software
+   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <linux/init.h>
+#include <linux/list.h>
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/usb.h>
+#include <linux/vmalloc.h>
+
+#include "em28xx.h"
+
+/* #define ENABLE_DEBUG_ISOC_FRAMES */
+
+unsigned int core_debug;
+module_param(core_debug,int,0644);
+MODULE_PARM_DESC(core_debug,"enable debug messages [core]");
+
+#define em28xx_coredbg(fmt, arg...) do {\
+       if (core_debug) \
+               printk(KERN_INFO "%s %s :"fmt, \
+                        dev->name, __FUNCTION__ , ##arg); } while (0)
+
+unsigned int reg_debug;
+module_param(reg_debug,int,0644);
+MODULE_PARM_DESC(reg_debug,"enable debug messages [URB reg]");
+
+#define em28xx_regdbg(fmt, arg...) do {\
+       if (reg_debug) \
+               printk(KERN_INFO "%s %s :"fmt, \
+                        dev->name, __FUNCTION__ , ##arg); } while (0)
+
+unsigned int isoc_debug;
+module_param(isoc_debug,int,0644);
+MODULE_PARM_DESC(isoc_debug,"enable debug messages [isoc transfers]");
+
+#define em28xx_isocdbg(fmt, arg...) do {\
+       if (isoc_debug) \
+               printk(KERN_INFO "%s %s :"fmt, \
+                        dev->name, __FUNCTION__ , ##arg); } while (0)
+
+static int alt = EM28XX_PINOUT;
+module_param(alt, int, 0644);
+MODULE_PARM_DESC(alt, "alternate setting to use for video endpoint");
+
+/* ------------------------------------------------------------------ */
+/* debug help functions                                               */
+
+static const char *v4l1_ioctls[] = {
+       "0", "CGAP", "GCHAN", "SCHAN", "GTUNER", "STUNER", "GPICT", "SPICT",
+       "CCAPTURE", "GWIN", "SWIN", "GFBUF", "SFBUF", "KEY", "GFREQ",
+       "SFREQ", "GAUDIO", "SAUDIO", "SYNC", "MCAPTURE", "GMBUF", "GUNIT",
+       "GCAPTURE", "SCAPTURE", "SPLAYMODE", "SWRITEMODE", "GPLAYINFO",
+       "SMICROCODE", "GVBIFMT", "SVBIFMT" };
+#define V4L1_IOCTLS ARRAY_SIZE(v4l1_ioctls)
+
+static const char *v4l2_ioctls[] = {
+       "QUERYCAP", "1", "ENUM_PIXFMT", "ENUM_FBUFFMT", "G_FMT", "S_FMT",
+       "G_COMP", "S_COMP", "REQBUFS", "QUERYBUF", "G_FBUF", "S_FBUF",
+       "G_WIN", "S_WIN", "PREVIEW", "QBUF", "16", "DQBUF", "STREAMON",
+       "STREAMOFF", "G_PERF", "G_PARM", "S_PARM", "G_STD", "S_STD",
+       "ENUMSTD", "ENUMINPUT", "G_CTRL", "S_CTRL", "G_TUNER", "S_TUNER",
+       "G_FREQ", "S_FREQ", "G_AUDIO", "S_AUDIO", "35", "QUERYCTRL",
+       "QUERYMENU", "G_INPUT", "S_INPUT", "ENUMCVT", "41", "42", "43",
+       "44", "45",  "G_OUTPUT", "S_OUTPUT", "ENUMOUTPUT", "G_AUDOUT",
+       "S_AUDOUT", "ENUMFX", "G_EFFECT", "S_EFFECT", "G_MODULATOR",
+       "S_MODULATOR"
+};
+#define V4L2_IOCTLS ARRAY_SIZE(v4l2_ioctls)
+
+void em28xx_print_ioctl(char *name, unsigned int cmd)
+{
+       char *dir;
+
+       switch (_IOC_DIR(cmd)) {
+       case _IOC_NONE:              dir = "--"; break;
+       case _IOC_READ:              dir = "r-"; break;
+       case _IOC_WRITE:             dir = "-w"; break;
+       case _IOC_READ | _IOC_WRITE: dir = "rw"; break;
+       default:                     dir = "??"; break;
+       }
+       switch (_IOC_TYPE(cmd)) {
+       case 'v':
+               printk(KERN_DEBUG "%s: ioctl 0x%08x (v4l1, %s, VIDIOC%s)\n",
+                      name, cmd, dir, (_IOC_NR(cmd) < V4L1_IOCTLS) ?
+                      v4l1_ioctls[_IOC_NR(cmd)] : "???");
+               break;
+       case 'V':
+               printk(KERN_DEBUG "%s: ioctl 0x%08x (v4l2, %s, VIDIOC_%s)\n",
+                      name, cmd, dir, (_IOC_NR(cmd) < V4L2_IOCTLS) ?
+                      v4l2_ioctls[_IOC_NR(cmd)] : "???");
+               break;
+       default:
+               printk(KERN_DEBUG "%s: ioctl 0x%08x (???, %s, #%d)\n",
+                      name, cmd, dir, _IOC_NR(cmd));
+       }
+}
+
+static void *rvmalloc(size_t size)
+{
+       void *mem;
+       unsigned long adr;
+
+       size = PAGE_ALIGN(size);
+
+       mem = vmalloc_32((unsigned long)size);
+       if (!mem)
+               return NULL;
+
+       memset(mem, 0, size);
+
+       adr = (unsigned long)mem;
+       while (size > 0) {
+               SetPageReserved(vmalloc_to_page((void *)adr));
+               adr += PAGE_SIZE;
+               size -= PAGE_SIZE;
+       }
+
+       return mem;
+}
+
+static void rvfree(void *mem, size_t size)
+{
+       unsigned long adr;
+
+       if (!mem)
+               return;
+
+       size = PAGE_ALIGN(size);
+
+       adr = (unsigned long)mem;
+       while (size > 0) {
+               ClearPageReserved(vmalloc_to_page((void *)adr));
+               adr += PAGE_SIZE;
+               size -= PAGE_SIZE;
+       }
+
+       vfree(mem);
+}
+
+/*
+ * em28xx_request_buffers()
+ * allocate a number of buffers
+ */
+u32 em28xx_request_buffers(struct em28xx *dev, u32 count)
+{
+       const size_t imagesize = PAGE_ALIGN(dev->frame_size);   /*needs to be page aligned cause the buffers can be mapped individually! */
+       void *buff = NULL;
+       u32 i;
+       em28xx_coredbg("requested %i buffers with size %i", count, imagesize);
+       if (count > EM28XX_NUM_FRAMES)
+               count = EM28XX_NUM_FRAMES;
+
+       dev->num_frames = count;
+       while (dev->num_frames > 0) {
+               if ((buff = rvmalloc(dev->num_frames * imagesize)))
+                       break;
+               dev->num_frames--;
+       }
+
+       for (i = 0; i < dev->num_frames; i++) {
+               dev->frame[i].bufmem = buff + i * imagesize;
+               dev->frame[i].buf.index = i;
+               dev->frame[i].buf.m.offset = i * imagesize;
+               dev->frame[i].buf.length = dev->frame_size;
+               dev->frame[i].buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+               dev->frame[i].buf.sequence = 0;
+               dev->frame[i].buf.field = V4L2_FIELD_NONE;
+               dev->frame[i].buf.memory = V4L2_MEMORY_MMAP;
+               dev->frame[i].buf.flags = 0;
+       }
+       return dev->num_frames;
+}
+
+/*
+ * em28xx_queue_unusedframes()
+ * add all frames that are not currently in use to the inbuffer queue
+ */
+void em28xx_queue_unusedframes(struct em28xx *dev)
+{
+       unsigned long lock_flags;
+       u32 i;
+
+       for (i = 0; i < dev->num_frames; i++)
+               if (dev->frame[i].state == F_UNUSED) {
+                       dev->frame[i].state = F_QUEUED;
+                       spin_lock_irqsave(&dev->queue_lock, lock_flags);
+                       list_add_tail(&dev->frame[i].frame, &dev->inqueue);
+                       spin_unlock_irqrestore(&dev->queue_lock, lock_flags);
+               }
+}
+
+/*
+ * em28xx_release_buffers()
+ * free frame buffers
+ */
+void em28xx_release_buffers(struct em28xx *dev)
+{
+       if (dev->num_frames) {
+               rvfree(dev->frame[0].bufmem,
+                      dev->num_frames * PAGE_ALIGN(dev->frame[0].buf.length));
+               dev->num_frames = 0;
+       }
+}
+
+/*
+ * em28xx_read_reg_req()
+ * reads data from the usb device specifying bRequest
+ */
+int em28xx_read_reg_req_len(struct em28xx *dev, u8 req, u16 reg,
+                                  char *buf, int len)
+{
+       int ret, byte;
+
+       em28xx_regdbg("req=%02x, reg=%02x ", req, reg);
+
+       ret = usb_control_msg(dev->udev, usb_rcvctrlpipe(dev->udev, 0), req,
+                             USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
+                             0x0000, reg, buf, len, HZ);
+
+       if (reg_debug){
+               printk(ret < 0 ? " failed!\n" : "%02x values: ", ret);
+               for (byte = 0; byte < len; byte++) {
+                       printk(" %02x", buf[byte]);
+               }
+               printk("\n");
+       }
+
+       return ret;
+}
+
+/*
+ * em28xx_read_reg_req()
+ * reads data from the usb device specifying bRequest
+ */
+int em28xx_read_reg_req(struct em28xx *dev, u8 req, u16 reg)
+{
+       u8 val;
+       int ret;
+
+       em28xx_regdbg("req=%02x, reg=%02x:", req, reg);
+
+       ret = usb_control_msg(dev->udev, usb_rcvctrlpipe(dev->udev, 0), req,
+                             USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
+                             0x0000, reg, &val, 1, HZ);
+
+       if (reg_debug)
+               printk(ret < 0 ? " failed!\n" : "%02x\n", val);
+
+       if (ret < 0)
+               return ret;
+
+       return val;
+}
+
+int em28xx_read_reg(struct em28xx *dev, u16 reg)
+{
+       return em28xx_read_reg_req(dev, USB_REQ_GET_STATUS, reg);
+}
+
+/*
+ * em28xx_write_regs_req()
+ * sends data to the usb device, specifying bRequest
+ */
+int em28xx_write_regs_req(struct em28xx *dev, u8 req, u16 reg, char *buf,
+                                int len)
+{
+       int ret;
+
+       /*usb_control_msg seems to expect a kmalloced buffer */
+       unsigned char *bufs = kmalloc(len, GFP_KERNEL);
+
+       em28xx_regdbg("req=%02x reg=%02x:", req, reg);
+
+       if (reg_debug) {
+               int i;
+               for (i = 0; i < len; ++i)
+                       printk (" %02x", (unsigned char)buf[i]);
+               printk ("\n");
+       }
+
+       if (!bufs)
+               return -ENOMEM;
+       memcpy(bufs, buf, len);
+       ret = usb_control_msg(dev->udev, usb_sndctrlpipe(dev->udev, 0), req,
+                             USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
+                             0x0000, reg, bufs, len, HZ);
+       mdelay(5);              /* FIXME: magic number */
+       kfree(bufs);
+       return ret;
+}
+
+int em28xx_write_regs(struct em28xx *dev, u16 reg, char *buf, int len)
+{
+       return em28xx_write_regs_req(dev, USB_REQ_GET_STATUS, reg, buf, len);
+}
+
+/*
+ * em28xx_write_reg_bits()
+ * sets only some bits (specified by bitmask) of a register, by first reading
+ * the actual value
+ */
+int em28xx_write_reg_bits(struct em28xx *dev, u16 reg, u8 val,
+                                u8 bitmask)
+{
+       int oldval;
+       u8 newval;
+       if ((oldval = em28xx_read_reg(dev, reg)) < 0)
+               return oldval;
+       newval = (((u8) oldval) & ~bitmask) | (val & bitmask);
+       return em28xx_write_regs(dev, reg, &newval, 1);
+}
+
+/*
+ * em28xx_write_ac97()
+ * write a 16 bit value to the specified AC97 address (LSB first!)
+ */
+int em28xx_write_ac97(struct em28xx *dev, u8 reg, u8 * val)
+{
+       int ret;
+       u8 addr = reg & 0x7f;
+       if ((ret = em28xx_write_regs(dev, AC97LSB_REG, val, 2)) < 0)
+               return ret;
+       if ((ret = em28xx_write_regs(dev, AC97ADDR_REG, &addr, 1)) < 0)
+               return ret;
+       if ((ret = em28xx_read_reg(dev, AC97BUSY_REG)) < 0)
+               return ret;
+       else if (((u8) ret) & 0x01) {
+               em28xx_warn ("AC97 command still being exectuted: not handled properly!\n");
+       }
+       return 0;
+}
+
+int em28xx_audio_analog_set(struct em28xx *dev)
+{
+       char s[2] = { 0x00, 0x00 };
+       s[0] |= 0x1f - dev->volume;
+       s[1] |= 0x1f - dev->volume;
+       if (dev->mute)
+               s[1] |= 0x80;
+       return em28xx_write_ac97(dev, MASTER_AC97, s);
+}
+
+
+int em28xx_colorlevels_set_default(struct em28xx *dev)
+{
+       em28xx_write_regs(dev, YGAIN_REG, "\x10", 1);   /* contrast */
+       em28xx_write_regs(dev, YOFFSET_REG, "\x00", 1); /* brightness */
+       em28xx_write_regs(dev, UVGAIN_REG, "\x10", 1);  /* saturation */
+       em28xx_write_regs(dev, UOFFSET_REG, "\x00", 1);
+       em28xx_write_regs(dev, VOFFSET_REG, "\x00", 1);
+       em28xx_write_regs(dev, SHARPNESS_REG, "\x00", 1);
+
+       em28xx_write_regs(dev, GAMMA_REG, "\x20", 1);
+       em28xx_write_regs(dev, RGAIN_REG, "\x20", 1);
+       em28xx_write_regs(dev, GGAIN_REG, "\x20", 1);
+       em28xx_write_regs(dev, BGAIN_REG, "\x20", 1);
+       em28xx_write_regs(dev, ROFFSET_REG, "\x00", 1);
+       em28xx_write_regs(dev, GOFFSET_REG, "\x00", 1);
+       return em28xx_write_regs(dev, BOFFSET_REG, "\x00", 1);
+}
+
+int em28xx_capture_start(struct em28xx *dev, int start)
+{
+       int ret;
+       /* FIXME: which is the best order? */
+       /* video registers are sampled by VREF */
+       if ((ret = em28xx_write_reg_bits(dev, USBSUSP_REG, start ? 0x10 : 0x00,
+                                         0x10)) < 0)
+               return ret;
+       /* enable video capture */
+       return em28xx_write_regs(dev, VINENABLE_REG, start ? "\x67" : "\x27", 1);
+}
+
+int em28xx_outfmt_set_yuv422(struct em28xx *dev)
+{
+       em28xx_write_regs(dev, OUTFMT_REG, "\x34", 1);
+       em28xx_write_regs(dev, VINMODE_REG, "\x10", 1);
+       return em28xx_write_regs(dev, VINCTRL_REG, "\x11", 1);
+}
+
+int em28xx_accumulator_set(struct em28xx *dev, u8 xmin, u8 xmax, u8 ymin,
+                                 u8 ymax)
+{
+       em28xx_coredbg("em28xx Scale: (%d,%d)-(%d,%d)\n", xmin, ymin, xmax, ymax);
+
+       em28xx_write_regs(dev, XMIN_REG, &xmin, 1);
+       em28xx_write_regs(dev, XMAX_REG, &xmax, 1);
+       em28xx_write_regs(dev, YMIN_REG, &ymin, 1);
+       return em28xx_write_regs(dev, YMAX_REG, &ymax, 1);
+}
+
+int em28xx_capture_area_set(struct em28xx *dev, u8 hstart, u8 vstart,
+                                  u16 width, u16 height)
+{
+       u8 cwidth = width;
+       u8 cheight = height;
+       u8 overflow = (height >> 7 & 0x02) | (width >> 8 & 0x01);
+
+       em28xx_coredbg("em28xx Area Set: (%d,%d)\n", (width | (overflow & 2) << 7),
+                       (height | (overflow & 1) << 8));
+
+       em28xx_write_regs(dev, HSTART_REG, &hstart, 1);
+       em28xx_write_regs(dev, VSTART_REG, &vstart, 1);
+       em28xx_write_regs(dev, CWIDTH_REG, &cwidth, 1);
+       em28xx_write_regs(dev, CHEIGHT_REG, &cheight, 1);
+       return em28xx_write_regs(dev, OFLOW_REG, &overflow, 1);
+}
+
+int em28xx_scaler_set(struct em28xx *dev, u16 h, u16 v)
+{
+       u8 mode;
+       /* the em2800 scaler only supports scaling down to 50% */
+       if(dev->is_em2800)
+               mode = (v ? 0x20 : 0x00) | (h ? 0x10 : 0x00);
+       else {
+               u8 buf[2];
+               buf[0] = h;
+               buf[1] = h >> 8;
+               em28xx_write_regs(dev, HSCALELOW_REG, (char *)buf, 2);
+               buf[0] = v;
+               buf[1] = v >> 8;
+               em28xx_write_regs(dev, VSCALELOW_REG, (char *)buf, 2);
+               /* it seems that both H and V scalers must be active to work correctly */
+               mode = (h || v)? 0x30: 0x00;
+       }
+       return em28xx_write_reg_bits(dev, COMPR_REG, mode, 0x30);
+}
+
+/* FIXME: this only function read values from dev */
+int em28xx_resolution_set(struct em28xx *dev)
+{
+       int width, height;
+       width = norm_maxw(dev);
+       height = norm_maxh(dev) >> 1;
+
+       em28xx_outfmt_set_yuv422(dev);
+       em28xx_accumulator_set(dev, 1, (width - 4) >> 2, 1, (height - 4) >> 2);
+       em28xx_capture_area_set(dev, 0, 0, width >> 2, height >> 2);
+       return em28xx_scaler_set(dev, dev->hscale, dev->vscale);
+}
+
+
+/******************* isoc transfer handling ****************************/
+
+#ifdef ENABLE_DEBUG_ISOC_FRAMES
+static void em28xx_isoc_dump(struct urb *urb, struct pt_regs *regs)
+{
+       int len = 0;
+       int ntrans = 0;
+       int i;
+
+       printk(KERN_DEBUG "isocIrq: sf=%d np=%d ec=%x\n",
+              urb->start_frame, urb->number_of_packets,
+              urb->error_count);
+       for (i = 0; i < urb->number_of_packets; i++) {
+               unsigned char *buf =
+                               urb->transfer_buffer +
+                               urb->iso_frame_desc[i].offset;
+               int alen = urb->iso_frame_desc[i].actual_length;
+               if (alen > 0) {
+                       if (buf[0] == 0x88) {
+                               ntrans++;
+                               len += alen;
+                       } else if (buf[0] == 0x22) {
+                               printk(KERN_DEBUG
+                                               "= l=%d nt=%d bpp=%d\n",
+                               len - 4 * ntrans, ntrans,
+                               ntrans == 0 ? 0 : len / ntrans);
+                               ntrans = 1;
+                               len = alen;
+                       } else
+                               printk(KERN_DEBUG "!\n");
+               }
+               printk(KERN_DEBUG "   n=%d s=%d al=%d %x\n", i,
+                      urb->iso_frame_desc[i].status,
+                      urb->iso_frame_desc[i].actual_length,
+                      (unsigned int)
+                                      *((unsigned char *)(urb->transfer_buffer +
+                                      urb->iso_frame_desc[i].
+                                      offset)));
+       }
+}
+#endif
+
+static inline int em28xx_isoc_video(struct em28xx *dev,struct em28xx_frame_t **f,
+                                   unsigned long *lock_flags, unsigned char buf)
+{
+       if (!(buf & 0x01)) {
+               if ((*f)->state == F_GRABBING) {
+                       /*previous frame is incomplete */
+                       if ((*f)->fieldbytesused < dev->field_size) {
+                               (*f)->state = F_ERROR;
+                               em28xx_isocdbg ("dropping incomplete bottom field (%i missing bytes)",
+                                        dev->field_size-(*f)->fieldbytesused);
+                       } else {
+                               (*f)->state = F_DONE;
+                               (*f)->buf.bytesused = dev->frame_size;
+                       }
+               }
+               if ((*f)->state == F_DONE || (*f)->state == F_ERROR) {
+                       /* move current frame to outqueue and get next free buffer from inqueue */
+                       spin_lock_irqsave(&dev-> queue_lock, *lock_flags);
+                       list_move_tail(&(*f)->frame, &dev->outqueue);
+                       if (!list_empty(&dev->inqueue))
+                               (*f) = list_entry(dev-> inqueue.next,
+                       struct em28xx_frame_t,frame);
+                       else
+                               (*f) = NULL;
+                       spin_unlock_irqrestore(&dev->queue_lock,*lock_flags);
+               }
+               if (!(*f)) {
+                       em28xx_isocdbg ("new frame but no buffer is free");
+                       return -1;
+               }
+               do_gettimeofday(&(*f)->buf.timestamp);
+               (*f)->buf.sequence = ++dev->frame_count;
+               (*f)->buf.field = V4L2_FIELD_INTERLACED;
+               (*f)->state = F_GRABBING;
+               (*f)->buf.bytesused = 0;
+               (*f)->top_field = 1;
+               (*f)->fieldbytesused = 0;
+       } else {
+                                       /* acquiring bottom field */
+               if ((*f)->state == F_GRABBING) {
+                       if (!(*f)->top_field) {
+                               (*f)->state = F_ERROR;
+                               em28xx_isocdbg ("unexpected begin of bottom field; discarding it");
+                       } else if ((*f)-> fieldbytesused < dev->field_size - 172) {
+                               (*f)->state = F_ERROR;
+                               em28xx_isocdbg ("dropping incomplete top field (%i missing bytes)",
+                                        dev->field_size-(*f)->fieldbytesused);
+                       } else {
+                               (*f)->top_field = 0;
+                               (*f)->fieldbytesused = 0;
+                       }
+               }
+       }
+       return (0);
+}
+
+static inline void em28xx_isoc_video_copy(struct em28xx *dev,
+                                         struct em28xx_frame_t **f, unsigned char *buf, int len)
+{
+       void *fieldstart, *startwrite, *startread;
+       int linesdone, currlinedone, offset, lencopy,remain;
+
+       if(dev->frame_size != (*f)->buf.length){
+               em28xx_err("frame_size %i and buf.length %i are different!!!\n",dev->frame_size,(*f)->buf.length);
+               return;
+       }
+
+       if ((*f)->fieldbytesused + len > dev->field_size)
+               len =dev->field_size - (*f)->fieldbytesused;
+
+       if (buf[0] != 0x88 && buf[0] != 0x22) {
+               em28xx_isocdbg("frame is not complete\n");
+               startread = buf;
+               len+=4;
+       } else
+               startread = buf + 4;
+
+       remain = len;
+
+       if ((*f)->top_field)
+               fieldstart = (*f)->bufmem;
+       else
+               fieldstart = (*f)->bufmem + dev->bytesperline;
+
+       linesdone = (*f)->fieldbytesused / dev->bytesperline;
+       currlinedone = (*f)->fieldbytesused % dev->bytesperline;
+       offset = linesdone * dev->bytesperline * 2 + currlinedone;
+       startwrite = fieldstart + offset;
+       lencopy = dev->bytesperline - currlinedone;
+       lencopy = lencopy > remain ? remain : lencopy;
+
+       memcpy(startwrite, startread, lencopy);
+       remain -= lencopy;
+
+       while (remain > 0) {
+               startwrite += lencopy + dev->bytesperline;
+               startread += lencopy;
+               if (dev->bytesperline > remain)
+                       lencopy = remain;
+               else
+                       lencopy = dev->bytesperline;
+
+               memcpy(startwrite, startread, lencopy);
+               remain -= lencopy;
+       }
+
+       (*f)->fieldbytesused += len;
+}
+
+/*
+ * em28xx_isoIrq()
+ * handles the incoming isoc urbs and fills the frames from our inqueue
+ */
+void em28xx_isocIrq(struct urb *urb, struct pt_regs *regs)
+{
+       struct em28xx *dev = urb->context;
+       int i, status;
+       struct em28xx_frame_t **f;
+       unsigned long lock_flags;
+
+       if (!dev)
+               return;
+#ifdef ENABLE_DEBUG_ISOC_FRAMES
+       if (isoc_debug>1)
+               em28xx_isoc_dump(urb, regs);
+#endif
+
+       if (urb->status == -ENOENT)
+               return;
+
+       f = &dev->frame_current;
+
+       if (dev->stream == STREAM_INTERRUPT) {
+               dev->stream = STREAM_OFF;
+               if ((*f))
+                       (*f)->state = F_QUEUED;
+               em28xx_isocdbg("stream interrupted");
+               wake_up_interruptible(&dev->wait_stream);
+       }
+
+       if ((dev->state & DEV_DISCONNECTED) || (dev->state & DEV_MISCONFIGURED))
+               return;
+
+       if (dev->stream == STREAM_ON && !list_empty(&dev->inqueue)) {
+               if (!(*f))
+                       (*f) = list_entry(dev->inqueue.next,
+               struct em28xx_frame_t, frame);
+
+               for (i = 0; i < urb->number_of_packets; i++) {
+                       unsigned char *buf = urb->transfer_buffer +
+                                       urb->iso_frame_desc[i].offset;
+                       int len = urb->iso_frame_desc[i].actual_length - 4;
+
+                       if (urb->iso_frame_desc[i].status) {
+                               em28xx_isocdbg("data error: [%d] len=%d, status=%d", i,
+                                       urb->iso_frame_desc[i].actual_length,
+                                       urb->iso_frame_desc[i].status);
+                               if (urb->iso_frame_desc[i].status != -EPROTO)
+                                       continue;
+                       }
+                       if (urb->iso_frame_desc[i].actual_length <= 0) {
+                               em28xx_isocdbg("packet %d is empty",i);
+                               continue;
+                       }
+                       if (urb->iso_frame_desc[i].actual_length >
+                                                dev->max_pkt_size) {
+                               em28xx_isocdbg("packet bigger than packet size");
+                               continue;
+                       }
+                       /*new frame */
+                       if (buf[0] == 0x22 && buf[1] == 0x5a) {
+                               em28xx_isocdbg("Video frame, length=%i!",len);
+
+                               if (em28xx_isoc_video(dev,f,&lock_flags,buf[2]))
+                               break;
+                       } else if (buf[0]==0x33 && buf[1]==0x95 && buf[2]==0x00) {
+                               em28xx_isocdbg("VBI HEADER!!!");
+                       }
+
+                       /* actual copying */
+                       if ((*f)->state == F_GRABBING) {
+                               em28xx_isoc_video_copy(dev,f,buf, len);
+                       }
+               }
+       }
+
+       for (i = 0; i < urb->number_of_packets; i++) {
+               urb->iso_frame_desc[i].status = 0;
+               urb->iso_frame_desc[i].actual_length = 0;
+       }
+
+       urb->status = 0;
+       if ((status = usb_submit_urb(urb, GFP_ATOMIC))) {
+               em28xx_errdev("resubmit of urb failed (error=%i)\n", status);
+               dev->state |= DEV_MISCONFIGURED;
+       }
+       wake_up_interruptible(&dev->wait_frame);
+       return;
+}
+
+/*
+ * em28xx_uninit_isoc()
+ * deallocates the buffers and urbs allocated during em28xx_init_iosc()
+ */
+void em28xx_uninit_isoc(struct em28xx *dev)
+{
+       int i;
+
+       for (i = 0; i < EM28XX_NUM_BUFS; i++) {
+               if (dev->urb[i]) {
+                       usb_kill_urb(dev->urb[i]);
+                       if (dev->transfer_buffer[i]){
+                               usb_buffer_free(dev->udev,(EM28XX_NUM_PACKETS*dev->max_pkt_size),dev->transfer_buffer[i],dev->urb[i]->transfer_dma);
+                       }
+                       usb_free_urb(dev->urb[i]);
+               }
+               dev->urb[i] = NULL;
+               dev->transfer_buffer[i] = NULL;
+       }
+       em28xx_capture_start(dev, 0);
+}
+
+/*
+ * em28xx_init_isoc()
+ * allocates transfer buffers and submits the urbs for isoc transfer
+ */
+int em28xx_init_isoc(struct em28xx *dev)
+{
+       /* change interface to 3 which allowes the biggest packet sizes */
+       int i, errCode;
+       const int sb_size = EM28XX_NUM_PACKETS * dev->max_pkt_size;
+
+       /* reset streaming vars */
+       dev->frame_current = NULL;
+       dev->frame_count = 0;
+
+       /* allocate urbs */
+       for (i = 0; i < EM28XX_NUM_BUFS; i++) {
+               struct urb *urb;
+               int j, k;
+               /* allocate transfer buffer */
+               urb = usb_alloc_urb(EM28XX_NUM_PACKETS, GFP_KERNEL);
+               if (!urb){
+                       em28xx_errdev("cannot alloc urb %i\n", i);
+                       em28xx_uninit_isoc(dev);
+                       return -ENOMEM;
+               }
+               dev->transfer_buffer[i] = usb_buffer_alloc(dev->udev, sb_size, GFP_KERNEL,&urb->transfer_dma);
+               if (!dev->transfer_buffer[i]) {
+                       em28xx_errdev
+                                       ("unable to allocate %i bytes for transfer buffer %i\n",
+                                        sb_size, i);
+                       em28xx_uninit_isoc(dev);
+                       return -ENOMEM;
+               }
+               memset(dev->transfer_buffer[i], 0, sb_size);
+               urb->dev = dev->udev;
+               urb->context = dev;
+               urb->pipe = usb_rcvisocpipe(dev->udev, 0x82);
+               urb->transfer_flags = URB_ISO_ASAP;
+               urb->interval = 1;
+               urb->transfer_buffer = dev->transfer_buffer[i];
+               urb->complete = em28xx_isocIrq;
+               urb->number_of_packets = EM28XX_NUM_PACKETS;
+               urb->transfer_buffer_length = sb_size;
+               for (j = k = 0; j < EM28XX_NUM_PACKETS;
+                               j++, k += dev->max_pkt_size) {
+                       urb->iso_frame_desc[j].offset = k;
+                       urb->iso_frame_desc[j].length =
+                               dev->max_pkt_size;
+               }
+               dev->urb[i] = urb;
+       }
+
+       /* submit urbs */
+       for (i = 0; i < EM28XX_NUM_BUFS; i++) {
+               errCode = usb_submit_urb(dev->urb[i], GFP_KERNEL);
+               if (errCode) {
+                       em28xx_errdev("submit of urb %i failed (error=%i)\n", i,
+                                     errCode);
+                       em28xx_uninit_isoc(dev);
+                       return errCode;
+               }
+       }
+
+       return 0;
+}
+
+int em28xx_set_alternate(struct em28xx *dev)
+{
+       int errCode, prev_alt = dev->alt;
+       dev->alt = alt;
+       if (dev->alt == 0) {
+               int i;
+               for(i=0;i< dev->num_alt; i++)
+                       if(dev->alt_max_pkt_size[i]>dev->alt_max_pkt_size[dev->alt])
+                               dev->alt=i;
+       }
+
+       if (dev->alt != prev_alt) {
+               dev->max_pkt_size = dev->alt_max_pkt_size[dev->alt];
+               em28xx_coredbg("setting alternate %d with wMaxPacketSize=%u\n", dev->alt,
+                      dev->max_pkt_size);
+               errCode = usb_set_interface(dev->udev, 0, dev->alt);
+               if (errCode < 0) {
+                       em28xx_errdev ("cannot change alternate number to %d (error=%i)\n",
+                                                       dev->alt, errCode);
+                       return errCode;
+               }
+       }
+       return 0;
+}
diff --git a/drivers/media/video/em28xx/em28xx-i2c.c b/drivers/media/video/em28xx/em28xx-i2c.c
new file mode 100644 (file)
index 0000000..b32d985
--- /dev/null
@@ -0,0 +1,586 @@
+/*
+   em28xx-i2c.c - driver for Empia EM2800/EM2820/2840 USB video capture devices
+
+   Copyright (C) 2005 Ludovico Cavedon <cavedon@sssup.it>
+                     Markus Rechberger <mrechberger@gmail.com>
+                     Mauro Carvalho Chehab <mchehab@brturbo.com.br>
+                     Sascha Sommer <saschasommer@freenet.de>
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 2 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software
+   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/usb.h>
+#include <linux/i2c.h>
+#include <linux/video_decoder.h>
+
+#include "em28xx.h"
+#include <media/tuner.h>
+
+/* ----------------------------------------------------------- */
+
+static unsigned int i2c_scan = 0;
+module_param(i2c_scan, int, 0444);
+MODULE_PARM_DESC(i2c_scan, "scan i2c bus at insmod time");
+
+static unsigned int i2c_debug = 0;
+module_param(i2c_debug, int, 0644);
+MODULE_PARM_DESC(i2c_debug, "enable debug messages [i2c]");
+
+#define dprintk1(lvl,fmt, args...) if (i2c_debug>=lvl) do {\
+                       printk(fmt , ##args); } while (0)
+#define dprintk2(lvl,fmt, args...) if (i2c_debug>=lvl) do{ \
+                       printk(KERN_DEBUG "%s at %s: " fmt, \
+                       dev->name, __FUNCTION__ , ##args); } while (0)
+
+/*
+ * em2800_i2c_send_max4()
+ * send up to 4 bytes to the i2c device
+ */
+static int em2800_i2c_send_max4(struct em28xx *dev, unsigned char addr,
+                               char *buf, int len)
+{
+       int ret;
+       int write_timeout;
+       unsigned char b2[6];
+       BUG_ON(len < 1 || len > 4);
+       b2[5] = 0x80 + len - 1;
+       b2[4] = addr;
+       b2[3] = buf[0];
+       if (len > 1)
+               b2[2] = buf[1];
+       if (len > 2)
+               b2[1] = buf[2];
+       if (len > 3)
+               b2[0] = buf[3];
+
+       ret = dev->em28xx_write_regs(dev, 4 - len, &b2[4 - len], 2 + len);
+       if (ret != 2 + len) {
+               em28xx_warn("writting to i2c device failed (error=%i)\n", ret);
+               return -EIO;
+       }
+       for (write_timeout = EM2800_I2C_WRITE_TIMEOUT; write_timeout > 0;
+            write_timeout -= 5) {
+               ret = dev->em28xx_read_reg(dev, 0x05);
+               if (ret == 0x80 + len - 1)
+                       return len;
+               mdelay(5);
+       }
+       em28xx_warn("i2c write timed out\n");
+       return -EIO;
+}
+
+/*
+ * em2800_i2c_send_bytes()
+ */
+static int em2800_i2c_send_bytes(void *data, unsigned char addr, char *buf,
+                                short len)
+{
+       char *bufPtr = buf;
+       int ret;
+       int wrcount = 0;
+       int count;
+       int maxLen = 4;
+       struct em28xx *dev = (struct em28xx *)data;
+       while (len > 0) {
+               count = (len > maxLen) ? maxLen : len;
+               ret = em2800_i2c_send_max4(dev, addr, bufPtr, count);
+               if (ret > 0) {
+                       len -= count;
+                       bufPtr += count;
+                       wrcount += count;
+               } else
+                       return (ret < 0) ? ret : -EFAULT;
+       }
+       return wrcount;
+}
+
+/*
+ * em2800_i2c_check_for_device()
+ * check if there is a i2c_device at the supplied address
+ */
+static int em2800_i2c_check_for_device(struct em28xx *dev, unsigned char addr)
+{
+       char msg;
+       int ret;
+       int write_timeout;
+       msg = addr;
+       ret = dev->em28xx_write_regs(dev, 0x04, &msg, 1);
+       if (ret < 0) {
+               em28xx_warn("setting i2c device address failed (error=%i)\n",
+                           ret);
+               return ret;
+       }
+       msg = 0x84;
+       ret = dev->em28xx_write_regs(dev, 0x05, &msg, 1);
+       if (ret < 0) {
+               em28xx_warn("preparing i2c read failed (error=%i)\n", ret);
+               return ret;
+       }
+       for (write_timeout = EM2800_I2C_WRITE_TIMEOUT; write_timeout > 0;
+            write_timeout -= 5) {
+               unsigned msg = dev->em28xx_read_reg(dev, 0x5);
+               if (msg == 0x94)
+                       return -ENODEV;
+               else if (msg == 0x84)
+                       return 0;
+               mdelay(5);
+       }
+       return -ENODEV;
+}
+
+/*
+ * em2800_i2c_recv_bytes()
+ * read from the i2c device
+ */
+static int em2800_i2c_recv_bytes(struct em28xx *dev, unsigned char addr,
+                                char *buf, int len)
+{
+       int ret;
+       /* check for the device and set i2c read address */
+       ret = em2800_i2c_check_for_device(dev, addr);
+       if (ret) {
+               em28xx_warn
+                   ("preparing read at i2c address 0x%x failed (error=%i)\n",
+                    addr, ret);
+               return ret;
+       }
+       ret = dev->em28xx_read_reg_req_len(dev, 0x0, 0x3, buf, len);
+       if (ret < 0) {
+               em28xx_warn("reading from i2c device at 0x%x failed (error=%i)",
+                           addr, ret);
+               return ret;
+       }
+       return ret;
+}
+
+/*
+ * em28xx_i2c_send_bytes()
+ * untested for more than 4 bytes
+ */
+static int em28xx_i2c_send_bytes(void *data, unsigned char addr, char *buf,
+                                short len, int stop)
+{
+       int wrcount = 0;
+       struct em28xx *dev = (struct em28xx *)data;
+
+       wrcount = dev->em28xx_write_regs_req(dev, stop ? 2 : 3, addr, buf, len);
+
+       return wrcount;
+}
+
+/*
+ * em28xx_i2c_recv_bytes()
+ * read a byte from the i2c device
+ */
+static int em28xx_i2c_recv_bytes(struct em28xx *dev, unsigned char addr,
+                                char *buf, int len)
+{
+       int ret;
+       ret = dev->em28xx_read_reg_req_len(dev, 2, addr, buf, len);
+       if (ret < 0) {
+               em28xx_warn("reading i2c device failed (error=%i)\n", ret);
+               return ret;
+       }
+       if (dev->em28xx_read_reg(dev, 0x5) != 0)
+               return -ENODEV;
+       return ret;
+}
+
+/*
+ * em28xx_i2c_check_for_device()
+ * check if there is a i2c_device at the supplied address
+ */
+static int em28xx_i2c_check_for_device(struct em28xx *dev, unsigned char addr)
+{
+       char msg;
+       int ret;
+       msg = addr;
+
+       ret = dev->em28xx_read_reg_req(dev, 2, addr);
+       if (ret < 0) {
+               em28xx_warn("reading from i2c device failed (error=%i)\n", ret);
+               return ret;
+       }
+       if (dev->em28xx_read_reg(dev, 0x5) != 0)
+               return -ENODEV;
+       return 0;
+}
+
+/*
+ * em28xx_i2c_xfer()
+ * the main i2c transfer function
+ */
+static int em28xx_i2c_xfer(struct i2c_adapter *i2c_adap,
+                          struct i2c_msg msgs[], int num)
+{
+       struct em28xx *dev = i2c_adap->algo_data;
+       int addr, rc, i, byte;
+
+       if (num <= 0)
+               return 0;
+       for (i = 0; i < num; i++) {
+               addr = msgs[i].addr << 1;
+               dprintk2(2,"%s %s addr=%x len=%d:",
+                        (msgs[i].flags & I2C_M_RD) ? "read" : "write",
+                        i == num - 1 ? "stop" : "nonstop", addr, msgs[i].len);
+               if (!msgs[i].len) {     /* no len: check only for device presence */
+                       if (dev->is_em2800)
+                               rc = em2800_i2c_check_for_device(dev, addr);
+                       else
+                               rc = em28xx_i2c_check_for_device(dev, addr);
+                       if (rc < 0) {
+                               dprintk2(2," no device\n");
+                               return rc;
+                       }
+
+               } else if (msgs[i].flags & I2C_M_RD) {
+                       /* read bytes */
+                       if (dev->is_em2800)
+                               rc = em2800_i2c_recv_bytes(dev, addr,
+                                                          msgs[i].buf,
+                                                          msgs[i].len);
+                       else
+                               rc = em28xx_i2c_recv_bytes(dev, addr,
+                                                          msgs[i].buf,
+                                                          msgs[i].len);
+                       if (i2c_debug>=2) {
+                               for (byte = 0; byte < msgs[i].len; byte++) {
+                                       printk(" %02x", msgs[i].buf[byte]);
+                               }
+                       }
+               } else {
+                       /* write bytes */
+                       if (i2c_debug>=2) {
+                               for (byte = 0; byte < msgs[i].len; byte++)
+                                       printk(" %02x", msgs[i].buf[byte]);
+                       }
+                       if (dev->is_em2800)
+                               rc = em2800_i2c_send_bytes(dev, addr,
+                                                          msgs[i].buf,
+                                                          msgs[i].len);
+                       else
+                               rc = em28xx_i2c_send_bytes(dev, addr,
+                                                          msgs[i].buf,
+                                                          msgs[i].len,
+                                                          i == num - 1);
+                       if (rc < 0)
+                               goto err;
+               }
+               if (i2c_debug>=2)
+                       printk("\n");
+       }
+
+       return num;
+      err:
+       dprintk2(2," ERROR: %i\n", rc);
+       return rc;
+}
+
+static int em28xx_i2c_eeprom(struct em28xx *dev, unsigned char *eedata, int len)
+{
+       unsigned char buf, *p = eedata;
+       struct em28xx_eeprom *em_eeprom = (void *)eedata;
+       int i, err, size = len, block;
+
+       dev->i2c_client.addr = 0xa0 >> 1;
+
+       /* Check if board has eeprom */
+       err = i2c_master_recv(&dev->i2c_client, &buf, 0);
+       if (err < 0)
+               return -1;
+
+       buf = 0;
+       if (1 != (err = i2c_master_send(&dev->i2c_client, &buf, 1))) {
+               printk(KERN_INFO "%s: Huh, no eeprom present (err=%d)?\n",
+                      dev->name, err);
+               return -1;
+       }
+       while (size > 0) {
+               if (size > 16)
+                       block = 16;
+               else
+                       block = size;
+
+               if (block !=
+                   (err = i2c_master_recv(&dev->i2c_client, p, block))) {
+                       printk(KERN_WARNING
+                              "%s: i2c eeprom read error (err=%d)\n",
+                              dev->name, err);
+                       return -1;
+               }
+               size -= block;
+               p += block;
+       }
+       for (i = 0; i < len; i++) {
+               if (0 == (i % 16))
+                       printk(KERN_INFO "%s: i2c eeprom %02x:", dev->name, i);
+               printk(" %02x", eedata[i]);
+               if (15 == (i % 16))
+                       printk("\n");
+       }
+
+       printk(KERN_INFO "EEPROM ID= 0x%08x\n", em_eeprom->id);
+       printk(KERN_INFO "Vendor/Product ID= %04x:%04x\n", em_eeprom->vendor_ID,
+              em_eeprom->product_ID);
+
+       switch (em_eeprom->chip_conf >> 4 & 0x3) {
+       case 0:
+               printk(KERN_INFO "No audio on board.\n");
+               break;
+       case 1:
+               printk(KERN_INFO "AC97 audio (5 sample rates)\n");
+               break;
+       case 2:
+               printk(KERN_INFO "I2S audio, sample rate=32k\n");
+               break;
+       case 3:
+               printk(KERN_INFO "I2S audio, 3 sample rates\n");
+               break;
+       }
+
+       if (em_eeprom->chip_conf & 1 << 3)
+               printk(KERN_INFO "USB Remote wakeup capable\n");
+
+       if (em_eeprom->chip_conf & 1 << 2)
+               printk(KERN_INFO "USB Self power capable\n");
+
+       switch (em_eeprom->chip_conf & 0x3) {
+       case 0:
+               printk(KERN_INFO "500mA max power\n");
+               break;
+       case 1:
+               printk(KERN_INFO "400mA max power\n");
+               break;
+       case 2:
+               printk(KERN_INFO "300mA max power\n");
+               break;
+       case 3:
+               printk(KERN_INFO "200mA max power\n");
+               break;
+       }
+       printk(KERN_INFO "Table at 0x%02x, strings=0x%04x, 0x%04x, 0x%04x\n",
+                               em_eeprom->string_idx_table,em_eeprom->string1,
+                               em_eeprom->string2,em_eeprom->string3);
+
+       return 0;
+}
+
+/* ----------------------------------------------------------- */
+
+/*
+ * algo_control()
+ */
+static int algo_control(struct i2c_adapter *adapter,
+                       unsigned int cmd, unsigned long arg)
+{
+       return 0;
+}
+
+/*
+ * functionality()
+ */
+static u32 functionality(struct i2c_adapter *adap)
+{
+       return I2C_FUNC_SMBUS_EMUL;
+}
+
+#ifndef I2C_PEC
+static void inc_use(struct i2c_adapter *adap)
+{
+       MOD_INC_USE_COUNT;
+}
+
+static void dec_use(struct i2c_adapter *adap)
+{
+       MOD_DEC_USE_COUNT;
+}
+#endif
+
+static int em28xx_set_tuner(int check_eeprom, struct i2c_client *client)
+{
+       struct em28xx *dev = client->adapter->algo_data;
+       struct tuner_setup tun_setup;
+
+       if (dev->has_tuner) {
+               tun_setup.mode_mask = T_ANALOG_TV | T_RADIO;
+               tun_setup.type = dev->tuner_type;
+               tun_setup.addr = dev->tuner_addr;
+
+               em28xx_i2c_call_clients(dev, TUNER_SET_TYPE_ADDR, &tun_setup);
+       }
+
+       return (0);
+}
+
+/*
+ * attach_inform()
+ * gets called when a device attaches to the i2c bus
+ * does some basic configuration
+ */
+static int attach_inform(struct i2c_client *client)
+{
+       struct em28xx *dev = client->adapter->algo_data;
+
+       switch (client->addr << 1) {
+               case 0x86:
+                       em28xx_i2c_call_clients(dev, TDA9887_SET_CONFIG, &dev->tda9887_conf);
+                       break;
+               case 0x42:
+                       dprintk1(1,"attach_inform: saa7114 detected.\n");
+                       break;
+               case 0x4a:
+                       dprintk1(1,"attach_inform: saa7113 detected.\n");
+                       break;
+               case 0xa0:
+                       dprintk1(1,"attach_inform: eeprom detected.\n");
+                       break;
+               case 0x60:
+               case 0x8e:
+               {
+                       struct IR_i2c *ir = i2c_get_clientdata(client);
+                       dprintk1(1,"attach_inform: IR detected (%s).\n",ir->phys);
+                       em28xx_set_ir(dev,ir);
+                       break;
+               }
+               case 0x80:
+               case 0x88:
+                       dprintk1(1,"attach_inform: msp34xx detected.\n");
+                       break;
+               case 0xb8:
+               case 0xba:
+                       dprintk1(1,"attach_inform: tvp5150 detected.\n");
+                       break;
+               default:
+                       dprintk1(1,"attach inform: detected I2C address %x\n", client->addr << 1);
+                       dev->tuner_addr = client->addr;
+                       em28xx_set_tuner(-1, client);
+       }
+
+       return 0;
+}
+
+static struct i2c_algorithm em28xx_algo = {
+       .master_xfer   = em28xx_i2c_xfer,
+       .algo_control  = algo_control,
+       .functionality = functionality,
+};
+
+static struct i2c_adapter em28xx_adap_template = {
+#ifdef I2C_PEC
+       .owner = THIS_MODULE,
+#else
+       .inc_use = inc_use,
+       .dec_use = dec_use,
+#endif
+#ifdef I2C_CLASS_TV_ANALOG
+       .class = I2C_CLASS_TV_ANALOG,
+#endif
+       .name = "em28xx",
+       .id = I2C_HW_B_EM28XX,
+       .algo = &em28xx_algo,
+       .client_register = attach_inform,
+};
+
+static struct i2c_client em28xx_client_template = {
+       .name = "em28xx internal",
+       .flags = I2C_CLIENT_ALLOW_USE,
+};
+
+/* ----------------------------------------------------------- */
+
+/*
+ * i2c_devs
+ * incomplete list of known devices
+ */
+static char *i2c_devs[128] = {
+       [0x4a >> 1] = "saa7113h",
+       [0x60 >> 1] = "remote IR sensor",
+       [0x8e >> 1] = "remote IR sensor",
+       [0x86 >> 1] = "tda9887",
+       [0x80 >> 1] = "msp34xx",
+       [0x88 >> 1] = "msp34xx",
+       [0xa0 >> 1] = "eeprom",
+       [0xb8 >> 1] = "tvp5150a",
+       [0xba >> 1] = "tvp5150a",
+       [0xc0 >> 1] = "tuner (analog)",
+       [0xc2 >> 1] = "tuner (analog)",
+       [0xc4 >> 1] = "tuner (analog)",
+       [0xc6 >> 1] = "tuner (analog)",
+};
+
+/*
+ * do_i2c_scan()
+ * check i2c address range for devices
+ */
+static void do_i2c_scan(char *name, struct i2c_client *c)
+{
+       unsigned char buf;
+       int i, rc;
+
+       for (i = 0; i < 128; i++) {
+               c->addr = i;
+               rc = i2c_master_recv(c, &buf, 0);
+               if (rc < 0)
+                       continue;
+               printk(KERN_INFO "%s: found i2c device @ 0x%x [%s]\n", name,
+                      i << 1, i2c_devs[i] ? i2c_devs[i] : "???");
+       }
+}
+
+/*
+ * em28xx_i2c_call_clients()
+ * send commands to all attached i2c devices
+ */
+void em28xx_i2c_call_clients(struct em28xx *dev, unsigned int cmd, void *arg)
+{
+       BUG_ON(NULL == dev->i2c_adap.algo_data);
+       i2c_clients_command(&dev->i2c_adap, cmd, arg);
+}
+
+/*
+ * em28xx_i2c_register()
+ * register i2c bus
+ */
+int em28xx_i2c_register(struct em28xx *dev)
+{
+       BUG_ON(!dev->em28xx_write_regs || !dev->em28xx_read_reg);
+       BUG_ON(!dev->em28xx_write_regs_req || !dev->em28xx_read_reg_req);
+       dev->i2c_adap = em28xx_adap_template;
+       dev->i2c_adap.dev.parent = &dev->udev->dev;
+       strcpy(dev->i2c_adap.name, dev->name);
+       dev->i2c_adap.algo_data = dev;
+       i2c_add_adapter(&dev->i2c_adap);
+
+       dev->i2c_client = em28xx_client_template;
+       dev->i2c_client.adapter = &dev->i2c_adap;
+
+       em28xx_i2c_eeprom(dev, dev->eedata, sizeof(dev->eedata));
+
+       if (i2c_scan)
+               do_i2c_scan(dev->name, &dev->i2c_client);
+       return 0;
+}
+
+/*
+ * em28xx_i2c_unregister()
+ * unregister i2c_bus
+ */
+int em28xx_i2c_unregister(struct em28xx *dev)
+{
+       i2c_del_adapter(&dev->i2c_adap);
+       return 0;
+}
diff --git a/drivers/media/video/em28xx/em28xx-input.c b/drivers/media/video/em28xx/em28xx-input.c
new file mode 100644 (file)
index 0000000..32c49df
--- /dev/null
@@ -0,0 +1,184 @@
+/*
+  handle em28xx IR remotes via linux kernel input layer.
+
+   Copyright (C) 2005 Ludovico Cavedon <cavedon@sssup.it>
+                     Markus Rechberger <mrechberger@gmail.com>
+                     Mauro Carvalho Chehab <mchehab@brturbo.com.br>
+                     Sascha Sommer <saschasommer@freenet.de>
+
+  This program is free software; you can redistribute it and/or modify
+  it under the terms of the GNU General Public License as published by
+  the Free Software Foundation; either version 2 of the License, or
+  (at your option) any later version.
+
+  This program is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+  GNU General Public License for more details.
+
+  You should have received a copy of the GNU General Public License
+  along with this program; if not, write to the Free Software
+  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/sched.h>
+#include <linux/interrupt.h>
+#include <linux/input.h>
+#include <linux/usb.h>
+
+#include "em28xx.h"
+
+static unsigned int disable_ir = 0;
+module_param(disable_ir, int, 0444);
+MODULE_PARM_DESC(disable_ir,"disable infrared remote support");
+
+static unsigned int ir_debug = 0;
+module_param(ir_debug, int, 0644);
+MODULE_PARM_DESC(ir_debug,"enable debug messages [IR]");
+
+#define dprintk(fmt, arg...)   if (ir_debug) \
+       printk(KERN_DEBUG "%s/ir: " fmt, ir->c.name , ## arg)
+
+/* ---------------------------------------------------------------------- */
+
+static IR_KEYTAB_TYPE ir_codes_em_terratec[IR_KEYTAB_SIZE] = {
+       [ 0x01 ] = KEY_CHANNEL,
+       [ 0x02 ] = KEY_SELECT,
+       [ 0x03 ] = KEY_MUTE,
+       [ 0x04 ] = KEY_POWER,
+       [ 0x05 ] = KEY_KP1,
+       [ 0x06 ] = KEY_KP2,
+       [ 0x07 ] = KEY_KP3,
+       [ 0x08 ] = KEY_CHANNELUP,
+       [ 0x09 ] = KEY_KP4,
+       [ 0x0a ] = KEY_KP5,
+       [ 0x0b ] = KEY_KP6,
+       [ 0x0c ] = KEY_CHANNELDOWN,
+       [ 0x0d ] = KEY_KP7,
+       [ 0x0e ] = KEY_KP8,
+       [ 0x0f ] = KEY_KP9,
+       [ 0x10 ] = KEY_VOLUMEUP,
+       [ 0x11 ] = KEY_KP0,
+       [ 0x12 ] = KEY_MENU,
+       [ 0x13 ] = KEY_PRINT,
+       [ 0x14 ] = KEY_VOLUMEDOWN,
+       [ 0x16 ] = KEY_PAUSE,
+       [ 0x18 ] = KEY_RECORD,
+       [ 0x19 ] = KEY_REWIND,
+       [ 0x1a ] = KEY_PLAY,
+       [ 0x1b ] = KEY_FORWARD,
+       [ 0x1c ] = KEY_BACKSPACE,
+       [ 0x1e ] = KEY_STOP,
+       [ 0x40 ] = KEY_ZOOM,
+};
+
+/* ----------------------------------------------------------------------- */
+
+static int get_key_terratec(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw)
+{
+       unsigned char b;
+
+       /* poll IR chip */
+       if (1 != i2c_master_recv(&ir->c,&b,1)) {
+               dprintk("read error\n");
+               return -EIO;
+       }
+
+       /* it seems that 0xFE indicates that a button is still hold
+          down, while 0xff indicates that no button is hold
+          down. 0xfe sequences are sometimes interrupted by 0xFF */
+
+       dprintk("key %02x\n", b);
+
+       if (b == 0xff)
+               return 0;
+
+       if (b == 0xfe)
+               /* keep old data */
+               return 1;
+
+       *ir_key = b;
+       *ir_raw = b;
+       return 1;
+}
+
+
+static int get_key_em_haup(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw)
+{
+       unsigned char buf[2];
+       unsigned char code;
+
+       /* poll IR chip */
+       if (2 != i2c_master_recv(&ir->c,buf,2))
+               return -EIO;
+
+       /* Does eliminate repeated parity code */
+       if (buf[1]==0xff)
+               return 0;
+
+       /* avoid fast reapeating */
+       if (buf[1]==ir->old)
+               return 0;
+       ir->old=buf[1];
+
+       /* Rearranges bits to the right order */
+       code=    ((buf[0]&0x01)<<5) | /* 0010 0000 */
+                ((buf[0]&0x02)<<3) | /* 0001 0000 */
+                ((buf[0]&0x04)<<1) | /* 0000 1000 */
+                ((buf[0]&0x08)>>1) | /* 0000 0100 */
+                ((buf[0]&0x10)>>3) | /* 0000 0010 */
+                ((buf[0]&0x20)>>5);  /* 0000 0001 */
+
+       dprintk("ir hauppauge (em2840): code=0x%02x (rcv=0x%02x)\n",code,buf[0]);
+
+       /* return key */
+       *ir_key = code;
+       *ir_raw = code;
+       return 1;
+}
+
+/* ----------------------------------------------------------------------- */
+void em28xx_set_ir(struct em28xx * dev,struct IR_i2c *ir)
+{
+       if (disable_ir) {
+               ir->get_key=NULL;
+               return ;
+       }
+
+       /* detect & configure */
+       switch (dev->model) {
+       case (EM2800_BOARD_UNKNOWN):
+               break;
+       case (EM2820_BOARD_UNKNOWN):
+               break;
+       case (EM2800_BOARD_TERRATEC_CINERGY_200):
+       case (EM2820_BOARD_TERRATEC_CINERGY_250):
+               ir->ir_codes = ir_codes_em_terratec;
+               ir->get_key = get_key_terratec;
+               snprintf(ir->c.name, sizeof(ir->c.name), "i2c IR (EM28XX Terratec)");
+               break;
+       case (EM2820_BOARD_PINNACLE_USB_2):
+               break;
+       case (EM2820_BOARD_HAUPPAUGE_WINTV_USB_2):
+               ir->ir_codes = ir_codes_hauppauge_new;
+               ir->get_key = get_key_em_haup;
+               snprintf(ir->c.name, sizeof(ir->c.name), "i2c IR (EM2840 Hauppauge)");
+               break;
+       case (EM2820_BOARD_MSI_VOX_USB_2):
+               break;
+       case (EM2800_BOARD_LEADTEK_WINFAST_USBII):
+               break;
+       case (EM2800_BOARD_KWORLD_USB2800):
+               break;
+       }
+}
+
+/* ----------------------------------------------------------------------
+ * Local variables:
+ * c-basic-offset: 8
+ * End:
+ */
diff --git a/drivers/media/video/em28xx/em28xx-video.c b/drivers/media/video/em28xx/em28xx-video.c
new file mode 100644 (file)
index 0000000..57c1826
--- /dev/null
@@ -0,0 +1,1933 @@
+/*
+   em28xx-video.c - driver for Empia EM2800/EM2820/2840 USB video capture devices
+
+   Copyright (C) 2005 Ludovico Cavedon <cavedon@sssup.it>
+                     Markus Rechberger <mrechberger@gmail.com>
+                     Mauro Carvalho Chehab <mchehab@brturbo.com.br>
+                     Sascha Sommer <saschasommer@freenet.de>
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 2 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software
+   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <linux/init.h>
+#include <linux/list.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/usb.h>
+#include <linux/i2c.h>
+#include <linux/version.h>
+#include <linux/video_decoder.h>
+
+#include "em28xx.h"
+#include <media/tuner.h>
+
+#define DRIVER_AUTHOR "Ludovico Cavedon <cavedon@sssup.it>, " \
+                     "Markus Rechberger <mrechberger@gmail.com>, " \
+                     "Mauro Carvalho Chehab <mchehab@brturbo.com.br>, " \
+                     "Sascha Sommer <saschasommer@freenet.de>"
+
+#define DRIVER_NAME         "em28xx"
+#define DRIVER_DESC         "Empia em28xx based USB video device driver"
+#define EM28XX_VERSION_CODE  KERNEL_VERSION(0, 0, 1)
+
+#define em28xx_videodbg(fmt, arg...) do {\
+       if (video_debug) \
+               printk(KERN_INFO "%s %s :"fmt, \
+                        dev->name, __FUNCTION__ , ##arg); } while (0)
+
+MODULE_AUTHOR(DRIVER_AUTHOR);
+MODULE_DESCRIPTION(DRIVER_DESC);
+MODULE_LICENSE("GPL");
+
+static LIST_HEAD(em28xx_devlist);
+
+static unsigned int card[]     = {[0 ... (EM28XX_MAXBOARDS - 1)] = UNSET };
+module_param_array(card,  int, NULL, 0444);
+MODULE_PARM_DESC(card,"card type");
+
+static int tuner = -1;
+module_param(tuner, int, 0444);
+MODULE_PARM_DESC(tuner, "tuner type");
+
+static unsigned int video_debug = 0;
+module_param(video_debug,int,0644);
+MODULE_PARM_DESC(video_debug,"enable debug messages [video]");
+
+/* supported tv norms */
+static struct em28xx_tvnorm tvnorms[] = {
+       {
+               .name = "PAL",
+               .id = V4L2_STD_PAL,
+               .mode = VIDEO_MODE_PAL,
+        }, {
+               .name = "NTSC",
+               .id = V4L2_STD_NTSC,
+               .mode = VIDEO_MODE_NTSC,
+       }, {
+                .name = "SECAM",
+                .id = V4L2_STD_SECAM,
+                .mode = VIDEO_MODE_SECAM,
+       }, {
+               .name = "PAL-M",
+               .id = V4L2_STD_PAL_M,
+               .mode = VIDEO_MODE_PAL,
+       }
+};
+
+static const unsigned char saa7114_i2c_init[] = {
+       0x00,0x00,0x01,0x08,0x02,0xc4,0x03,0x30,0x04,0x90,0x05,0x90,0x06,0xeb,0x07,0xe0,
+       0x08,0x88,0x09,0x40,0x0a,0x80,0x0b,0x44,0x0c,0x40,0x0d,0x00,0x0e,0x81,0x0f,0x2a,
+       0x10,0x06,0x11,0x00,0x12,0xc8,0x13,0x80,0x14,0x00,0x15,0x11,0x16,0x01,0x17,0x42,
+       0x18,0x40,0x19,0x80,0x40,0x00,0x41,0xff,0x42,0xff,0x43,0xff,0x44,0xff,0x45,0xff,
+       0x46,0xff,0x47,0xff,0x48,0xff,0x49,0xff,0x4a,0xff,0x4b,0xff,0x4c,0xff,0x4d,0xff,
+       0x4e,0xff,0x4f,0xff,0x50,0xff,0x51,0xff,0x52,0xff,0x53,0xff,0x54,0x5f,0x55,0xff,
+       0x56,0xff,0x57,0xff,0x58,0x00,0x59,0x47,0x5a,0x03,0x5b,0x03,0x5d,0x3e,0x5e,0x00,
+       0x80,0x1c,0x83,0x01,0x84,0xa5,0x85,0x10,0x86,0x45,0x87,0x41,0x88,0xf0,0x88,0x00,
+       0x88,0xf0,0x90,0x00,0x91,0x08,0x92,0x00,0x93,0x80,0x94,0x08,0x95,0x00,0x96,0xc0,
+       0x97,0x02,0x98,0x13,0x99,0x00,0x9a,0x38,0x9b,0x01,0x9c,0x80,0x9d,0x02,0x9e,0x06,
+       0x9f,0x01,0xa0,0x01,0xa1,0x00,0xa2,0x00,0xa4,0x80,0xa5,0x36,0xa6,0x36,0xa8,0x67,
+       0xa9,0x04,0xaa,0x00,0xac,0x33,0xad,0x02,0xae,0x00,0xb0,0xcd,0xb1,0x04,0xb2,0xcd,
+       0xb3,0x04,0xb4,0x01,0xb8,0x00,0xb9,0x00,0xba,0x00,0xbb,0x00,0xbc,0x00,0xbd,0x00,
+       0xbe,0x00,0xbf,0x00
+};
+
+#define TVNORMS ARRAY_SIZE(tvnorms)
+
+/* supported controls */
+static struct v4l2_queryctrl em28xx_qctrl[] = {
+       {
+               .id = V4L2_CID_BRIGHTNESS,
+               .type = V4L2_CTRL_TYPE_INTEGER,
+               .name = "Brightness",
+               .minimum = -128,
+               .maximum = 127,
+               .step = 1,
+               .default_value = 0,
+               .flags = 0,
+       },{
+               .id = V4L2_CID_CONTRAST,
+               .type = V4L2_CTRL_TYPE_INTEGER,
+               .name = "Contrast",
+               .minimum = 0x0,
+               .maximum = 0x1f,
+               .step = 0x1,
+               .default_value = 0x10,
+               .flags = 0,
+       },{
+               .id = V4L2_CID_SATURATION,
+               .type = V4L2_CTRL_TYPE_INTEGER,
+               .name = "Saturation",
+               .minimum = 0x0,
+               .maximum = 0x1f,
+               .step = 0x1,
+               .default_value = 0x10,
+               .flags = 0,
+       },{
+               .id = V4L2_CID_AUDIO_VOLUME,
+               .type = V4L2_CTRL_TYPE_INTEGER,
+               .name = "Volume",
+               .minimum = 0x0,
+               .maximum = 0x1f,
+               .step = 0x1,
+               .default_value = 0x1f,
+               .flags = 0,
+       },{
+               .id = V4L2_CID_AUDIO_MUTE,
+               .type = V4L2_CTRL_TYPE_BOOLEAN,
+               .name = "Mute",
+               .minimum = 0,
+               .maximum = 1,
+               .step = 1,
+               .default_value = 1,
+               .flags = 0,
+       },{
+               .id = V4L2_CID_RED_BALANCE,
+               .type = V4L2_CTRL_TYPE_INTEGER,
+               .name = "Red chroma balance",
+               .minimum = -128,
+               .maximum = 127,
+               .step = 1,
+               .default_value = 0,
+               .flags = 0,
+       },{
+               .id = V4L2_CID_BLUE_BALANCE,
+               .type = V4L2_CTRL_TYPE_INTEGER,
+               .name = "Blue chroma balance",
+               .minimum = -128,
+               .maximum = 127,
+               .step = 1,
+               .default_value = 0,
+               .flags = 0,
+       },{
+               .id = V4L2_CID_GAMMA,
+               .type = V4L2_CTRL_TYPE_INTEGER,
+               .name = "Gamma",
+               .minimum = 0x0,
+               .maximum = 0x3f,
+               .step = 0x1,
+               .default_value = 0x20,
+               .flags = 0,
+        }
+};
+
+static struct usb_driver em28xx_usb_driver;
+
+static DECLARE_MUTEX(em28xx_sysfs_lock);
+static DECLARE_RWSEM(em28xx_disconnect);
+
+/*********************  v4l2 interface  ******************************************/
+
+static inline unsigned long kvirt_to_pa(unsigned long adr)
+{
+       unsigned long kva, ret;
+
+       kva = (unsigned long)page_address(vmalloc_to_page((void *)adr));
+       kva |= adr & (PAGE_SIZE - 1);
+       ret = __pa(kva);
+       return ret;
+}
+
+/*
+ * em28xx_config()
+ * inits registers with sane defaults
+ */
+static int em28xx_config(struct em28xx *dev)
+{
+
+       /* Sets I2C speed to 100 KHz */
+       em28xx_write_regs_req(dev, 0x00, 0x06, "\x40", 1);
+
+       /* enable vbi capturing */
+       em28xx_audio_usb_mute(dev, 1);
+       dev->mute = 1;          /* maybe not the right place... */
+       dev->volume = 0x1f;
+       em28xx_audio_analog_set(dev);
+       em28xx_audio_analog_setup(dev);
+       em28xx_outfmt_set_yuv422(dev);
+       em28xx_colorlevels_set_default(dev);
+       em28xx_compression_disable(dev);
+
+       return 0;
+}
+
+/*
+ * em28xx_config_i2c()
+ * configure i2c attached devices
+ */
+void em28xx_config_i2c(struct em28xx *dev)
+{
+       struct v4l2_frequency f;
+       struct video_decoder_init em28xx_vdi = {.data = NULL };
+
+
+       /* configure decoder */
+       if(dev->model == EM2820_BOARD_MSI_VOX_USB_2){
+               em28xx_vdi.data=saa7114_i2c_init;
+               em28xx_vdi.len=sizeof(saa7114_i2c_init);
+       }
+
+
+       em28xx_i2c_call_clients(dev, DECODER_INIT, &em28xx_vdi);
+       em28xx_i2c_call_clients(dev, DECODER_SET_INPUT, &dev->ctl_input);
+/*     em28xx_i2c_call_clients(dev,DECODER_SET_PICTURE, &dev->vpic); */
+/*     em28xx_i2c_call_clients(dev,DECODER_SET_NORM,&dev->tvnorm->id); */
+/*     em28xx_i2c_call_clients(dev,DECODER_ENABLE_OUTPUT,&output); */
+/*     em28xx_i2c_call_clients(dev,DECODER_DUMP, NULL); */
+
+       /* configure tuner */
+       f.tuner = 0;
+       f.type = V4L2_TUNER_ANALOG_TV;
+       f.frequency = 9076;     /* FIXME:remove magic number */
+       dev->ctl_freq = f.frequency;
+       em28xx_i2c_call_clients(dev, VIDIOC_S_FREQUENCY, &f);
+
+       /* configure tda9887 */
+
+
+/*     em28xx_i2c_call_clients(dev,VIDIOC_S_STD,&dev->tvnorm->id); */
+}
+
+/*
+ * em28xx_empty_framequeues()
+ * prepare queues for incoming and outgoing frames
+ */
+static void em28xx_empty_framequeues(struct em28xx *dev)
+{
+       u32 i;
+
+       INIT_LIST_HEAD(&dev->inqueue);
+       INIT_LIST_HEAD(&dev->outqueue);
+
+       for (i = 0; i < EM28XX_NUM_FRAMES; i++) {
+               dev->frame[i].state = F_UNUSED;
+               dev->frame[i].buf.bytesused = 0;
+       }
+}
+
+static void video_mux(struct em28xx *dev, int index)
+{
+       int input, ainput;
+
+       input = INPUT(index)->vmux;
+       dev->ctl_input = index;
+       dev->ctl_ainput = INPUT(index)->amux;
+
+       em28xx_i2c_call_clients(dev, DECODER_SET_INPUT, &input);
+
+
+       em28xx_videodbg("Setting input index=%d, vmux=%d, amux=%d\n",index,input,dev->ctl_ainput);
+
+       if (dev->has_msp34xx) {
+               em28xx_i2c_call_clients(dev, VIDIOC_S_AUDIO, &dev->ctl_ainput);
+               ainput = EM28XX_AUDIO_SRC_TUNER;
+               em28xx_audio_source(dev, ainput);
+       } else {
+               switch (dev->ctl_ainput) {
+               case 0:
+                       ainput = EM28XX_AUDIO_SRC_TUNER;
+                       break;
+               default:
+                       ainput = EM28XX_AUDIO_SRC_LINE;
+               }
+               em28xx_audio_source(dev, ainput);
+       }
+}
+
+/*
+ * em28xx_v4l2_open()
+ * inits the device and starts isoc transfer
+ */
+static int em28xx_v4l2_open(struct inode *inode, struct file *filp)
+{
+       int minor = iminor(inode);
+       int errCode = 0;
+       struct em28xx *h,*dev = NULL;
+       struct list_head *list;
+
+       list_for_each(list,&em28xx_devlist) {
+               h = list_entry(list, struct em28xx, devlist);
+               if (h->vdev->minor == minor) {
+                       dev  = h;
+               }
+       }
+
+       filp->private_data=dev;
+
+
+       em28xx_videodbg("users=%d\n", dev->users);
+
+       if (!down_read_trylock(&em28xx_disconnect))
+               return -ERESTARTSYS;
+
+       if (dev->users) {
+               em28xx_warn("this driver can be opened only once\n");
+               up_read(&em28xx_disconnect);
+               return -EBUSY;
+       }
+
+/*     if(dev->vbi_dev->minor == minor){
+               dev->type=V4L2_BUF_TYPE_VBI_CAPTURE;
+       }*/
+       if (dev->vdev->minor == minor) {
+               dev->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+       }
+
+       init_MUTEX(&dev->fileop_lock);  /* to 1 == available */
+       spin_lock_init(&dev->queue_lock);
+       init_waitqueue_head(&dev->wait_frame);
+       init_waitqueue_head(&dev->wait_stream);
+
+       down(&dev->lock);
+
+       em28xx_set_alternate(dev);
+
+       dev->width = norm_maxw(dev);
+       dev->height = norm_maxh(dev);
+       dev->frame_size = dev->width * dev->height * 2;
+       dev->field_size = dev->frame_size >> 1; /*both_fileds ? dev->frame_size>>1 : dev->frame_size; */
+       dev->bytesperline = dev->width * 2;
+       dev->hscale = 0;
+       dev->vscale = 0;
+
+       em28xx_capture_start(dev, 1);
+       em28xx_resolution_set(dev);
+
+       /* start the transfer */
+       errCode = em28xx_init_isoc(dev);
+       if (errCode)
+               goto err;
+
+       dev->users++;
+       filp->private_data = dev;
+       dev->io = IO_NONE;
+       dev->stream = STREAM_OFF;
+       dev->num_frames = 0;
+
+       /* prepare queues */
+       em28xx_empty_framequeues(dev);
+
+       dev->state |= DEV_INITIALIZED;
+
+       video_mux(dev, 0);
+
+      err:
+       up(&dev->lock);
+       up_read(&em28xx_disconnect);
+       return errCode;
+}
+
+/*
+ * em28xx_realease_resources()
+ * unregisters the v4l2,i2c and usb devices
+ * called when the device gets disconected or at module unload
+*/
+static void em28xx_release_resources(struct em28xx *dev)
+{
+       down(&em28xx_sysfs_lock);
+
+       em28xx_info("V4L2 device /dev/video%d deregistered\n",
+                   dev->vdev->minor);
+       list_del(&dev->devlist);
+       video_unregister_device(dev->vdev);
+/*     video_unregister_device(dev->vbi_dev); */
+       em28xx_i2c_unregister(dev);
+       usb_put_dev(dev->udev);
+       up(&em28xx_sysfs_lock);
+}
+
+/*
+ * em28xx_v4l2_close()
+ * stops streaming and deallocates all resources allocated by the v4l2 calls and ioctls
+ */
+static int em28xx_v4l2_close(struct inode *inode, struct file *filp)
+{
+       int errCode;
+       struct em28xx *dev=filp->private_data;
+
+       em28xx_videodbg("users=%d\n", dev->users);
+
+       down(&dev->lock);
+
+       em28xx_uninit_isoc(dev);
+
+       em28xx_release_buffers(dev);
+
+       /* the device is already disconnect, free the remaining resources */
+       if (dev->state & DEV_DISCONNECTED) {
+               em28xx_release_resources(dev);
+               up(&dev->lock);
+               kfree(dev);
+               return 0;
+       }
+
+       /* set alternate 0 */
+       dev->alt = 0;
+       em28xx_videodbg("setting alternate 0\n");
+       errCode = usb_set_interface(dev->udev, 0, 0);
+       if (errCode < 0) {
+               em28xx_errdev ("cannot change alternate number to 0 (error=%i)\n",
+                    errCode);
+       }
+
+       dev->users--;
+       wake_up_interruptible_nr(&dev->open, 1);
+       up(&dev->lock);
+       return 0;
+}
+
+/*
+ * em28xx_v4l2_read()
+ * will allocate buffers when called for the first time
+ */
+static ssize_t
+em28xx_v4l2_read(struct file *filp, char __user * buf, size_t count,
+                loff_t * f_pos)
+{
+       struct em28xx_frame_t *f, *i;
+       unsigned long lock_flags;
+       int ret = 0;
+       struct em28xx *dev = filp->private_data;
+
+       if (down_interruptible(&dev->fileop_lock))
+               return -ERESTARTSYS;
+
+       if (dev->state & DEV_DISCONNECTED) {
+               em28xx_videodbg("device not present\n");
+               up(&dev->fileop_lock);
+               return -ENODEV;
+       }
+
+       if (dev->state & DEV_MISCONFIGURED) {
+               em28xx_videodbg("device misconfigured; close and open it again\n");
+               up(&dev->fileop_lock);
+               return -EIO;
+       }
+
+       if (dev->io == IO_MMAP) {
+               em28xx_videodbg ("IO method is set to mmap; close and open"
+                               " the device again to choose the read method\n");
+               up(&dev->fileop_lock);
+               return -EINVAL;
+       }
+
+       if (dev->io == IO_NONE) {
+               if (!em28xx_request_buffers(dev, EM28XX_NUM_READ_FRAMES)) {
+                       em28xx_errdev("read failed, not enough memory\n");
+                       up(&dev->fileop_lock);
+                       return -ENOMEM;
+               }
+               dev->io = IO_READ;
+               dev->stream = STREAM_ON;
+               em28xx_queue_unusedframes(dev);
+       }
+
+       if (!count) {
+               up(&dev->fileop_lock);
+               return 0;
+       }
+
+       if (list_empty(&dev->outqueue)) {
+               if (filp->f_flags & O_NONBLOCK) {
+                       up(&dev->fileop_lock);
+                       return -EAGAIN;
+               }
+               ret = wait_event_interruptible
+                   (dev->wait_frame,
+                    (!list_empty(&dev->outqueue)) ||
+                    (dev->state & DEV_DISCONNECTED));
+               if (ret) {
+                       up(&dev->fileop_lock);
+                       return ret;
+               }
+               if (dev->state & DEV_DISCONNECTED) {
+                       up(&dev->fileop_lock);
+                       return -ENODEV;
+               }
+       }
+
+       f = list_entry(dev->outqueue.prev, struct em28xx_frame_t, frame);
+
+       spin_lock_irqsave(&dev->queue_lock, lock_flags);
+       list_for_each_entry(i, &dev->outqueue, frame)
+           i->state = F_UNUSED;
+       INIT_LIST_HEAD(&dev->outqueue);
+       spin_unlock_irqrestore(&dev->queue_lock, lock_flags);
+
+       em28xx_queue_unusedframes(dev);
+
+       if (count > f->buf.length)
+               count = f->buf.length;
+
+       if (copy_to_user(buf, f->bufmem, count)) {
+               up(&dev->fileop_lock);
+               return -EFAULT;
+       }
+       *f_pos += count;
+
+       up(&dev->fileop_lock);
+
+       return count;
+}
+
+/*
+ * em28xx_v4l2_poll()
+ * will allocate buffers when called for the first time
+ */
+static unsigned int em28xx_v4l2_poll(struct file *filp, poll_table * wait)
+{
+       unsigned int mask = 0;
+       struct em28xx *dev = filp->private_data;
+
+       if (down_interruptible(&dev->fileop_lock))
+               return POLLERR;
+
+       if (dev->state & DEV_DISCONNECTED) {
+               em28xx_videodbg("device not present\n");
+       } else if (dev->state & DEV_MISCONFIGURED) {
+               em28xx_videodbg("device is misconfigured; close and open it again\n");
+       } else {
+               if (dev->io == IO_NONE) {
+                       if (!em28xx_request_buffers
+                           (dev, EM28XX_NUM_READ_FRAMES)) {
+                               em28xx_warn
+                                   ("poll() failed, not enough memory\n");
+                       } else {
+                               dev->io = IO_READ;
+                               dev->stream = STREAM_ON;
+                       }
+               }
+
+               if (dev->io == IO_READ) {
+                       em28xx_queue_unusedframes(dev);
+                       poll_wait(filp, &dev->wait_frame, wait);
+
+                       if (!list_empty(&dev->outqueue))
+                               mask |= POLLIN | POLLRDNORM;
+
+                       up(&dev->fileop_lock);
+
+                       return mask;
+               }
+       }
+
+       up(&dev->fileop_lock);
+       return POLLERR;
+}
+
+/*
+ * em28xx_vm_open()
+ */
+static void em28xx_vm_open(struct vm_area_struct *vma)
+{
+       struct em28xx_frame_t *f = vma->vm_private_data;
+       f->vma_use_count++;
+}
+
+/*
+ * em28xx_vm_close()
+ */
+static void em28xx_vm_close(struct vm_area_struct *vma)
+{
+       /* NOTE: buffers are not freed here */
+       struct em28xx_frame_t *f = vma->vm_private_data;
+       f->vma_use_count--;
+}
+
+static struct vm_operations_struct em28xx_vm_ops = {
+       .open = em28xx_vm_open,
+       .close = em28xx_vm_close,
+};
+
+/*
+ * em28xx_v4l2_mmap()
+ */
+static int em28xx_v4l2_mmap(struct file *filp, struct vm_area_struct *vma)
+{
+       unsigned long size = vma->vm_end - vma->vm_start,
+           start = vma->vm_start, pos, page;
+       u32 i;
+
+       struct em28xx *dev = filp->private_data;
+
+       if (down_interruptible(&dev->fileop_lock))
+               return -ERESTARTSYS;
+
+       if (dev->state & DEV_DISCONNECTED) {
+               em28xx_videodbg("mmap: device not present\n");
+               up(&dev->fileop_lock);
+               return -ENODEV;
+       }
+
+       if (dev->state & DEV_MISCONFIGURED) {
+               em28xx_videodbg ("mmap: Device is misconfigured; close and "
+                                               "open it again\n");
+               up(&dev->fileop_lock);
+               return -EIO;
+       }
+
+       if (dev->io != IO_MMAP || !(vma->vm_flags & VM_WRITE) ||
+           size != PAGE_ALIGN(dev->frame[0].buf.length)) {
+               up(&dev->fileop_lock);
+               return -EINVAL;
+       }
+
+       for (i = 0; i < dev->num_frames; i++) {
+               if ((dev->frame[i].buf.m.offset >> PAGE_SHIFT) == vma->vm_pgoff)
+                       break;
+       }
+       if (i == dev->num_frames) {
+               em28xx_videodbg("mmap: user supplied mapping address is out of range\n");
+               up(&dev->fileop_lock);
+               return -EINVAL;
+       }
+
+       /* VM_IO is eventually going to replace PageReserved altogether */
+       vma->vm_flags |= VM_IO;
+       vma->vm_flags |= VM_RESERVED;   /* avoid to swap out this VMA */
+
+       pos = (unsigned long)dev->frame[i].bufmem;
+       while (size > 0) {      /* size is page-aligned */
+               page = vmalloc_to_pfn((void *)pos);
+               if (remap_pfn_range(vma, start, page, PAGE_SIZE,
+                                   vma->vm_page_prot)) {
+                       em28xx_videodbg("mmap: rename page map failed\n");
+                       up(&dev->fileop_lock);
+                       return -EAGAIN;
+               }
+               start += PAGE_SIZE;
+               pos += PAGE_SIZE;
+               size -= PAGE_SIZE;
+       }
+
+       vma->vm_ops = &em28xx_vm_ops;
+       vma->vm_private_data = &dev->frame[i];
+
+       em28xx_vm_open(vma);
+       up(&dev->fileop_lock);
+       return 0;
+}
+
+/*
+ * em28xx_get_ctrl()
+ * return the current saturation, brightness or contrast, mute state
+ */
+static int em28xx_get_ctrl(struct em28xx *dev, struct v4l2_control *ctrl)
+{
+       s32 tmp;
+       switch (ctrl->id) {
+       case V4L2_CID_AUDIO_MUTE:
+               ctrl->value = dev->mute;
+               return 0;
+       case V4L2_CID_AUDIO_VOLUME:
+               ctrl->value = dev->volume;
+               return 0;
+       case V4L2_CID_BRIGHTNESS:
+               if ((tmp = em28xx_brightness_get(dev)) < 0)
+                       return -EIO;
+               ctrl->value = (s32) ((s8) tmp); /* FIXME: clenaer way to extend sign? */
+               return 0;
+       case V4L2_CID_CONTRAST:
+               if ((ctrl->value = em28xx_contrast_get(dev)) < 0)
+                       return -EIO;
+               return 0;
+       case V4L2_CID_SATURATION:
+               if ((ctrl->value = em28xx_saturation_get(dev)) < 0)
+                       return -EIO;
+               return 0;
+       case V4L2_CID_RED_BALANCE:
+               if ((tmp = em28xx_v_balance_get(dev)) < 0)
+                       return -EIO;
+               ctrl->value = (s32) ((s8) tmp); /* FIXME: clenaer way to extend sign? */
+               return 0;
+       case V4L2_CID_BLUE_BALANCE:
+               if ((tmp = em28xx_u_balance_get(dev)) < 0)
+                       return -EIO;
+               ctrl->value = (s32) ((s8) tmp); /* FIXME: clenaer way to extend sign? */
+               return 0;
+       case V4L2_CID_GAMMA:
+               if ((ctrl->value = em28xx_gamma_get(dev)) < 0)
+                       return -EIO;
+               return 0;
+       default:
+               return -EINVAL;
+       }
+}
+
+/*
+ * em28xx_set_ctrl()
+ * mute or set new saturation, brightness or contrast
+ */
+static int em28xx_set_ctrl(struct em28xx *dev, const struct v4l2_control *ctrl)
+{
+       switch (ctrl->id) {
+       case V4L2_CID_AUDIO_MUTE:
+               if (ctrl->value != dev->mute) {
+                       dev->mute = ctrl->value;
+                       em28xx_audio_usb_mute(dev, ctrl->value);
+                       return em28xx_audio_analog_set(dev);
+               }
+               return 0;
+       case V4L2_CID_AUDIO_VOLUME:
+               dev->volume = ctrl->value;
+               return em28xx_audio_analog_set(dev);
+       case V4L2_CID_BRIGHTNESS:
+               return em28xx_brightness_set(dev, ctrl->value);
+       case V4L2_CID_CONTRAST:
+               return em28xx_contrast_set(dev, ctrl->value);
+       case V4L2_CID_SATURATION:
+               return em28xx_saturation_set(dev, ctrl->value);
+       case V4L2_CID_RED_BALANCE:
+               return em28xx_v_balance_set(dev, ctrl->value);
+       case V4L2_CID_BLUE_BALANCE:
+               return em28xx_u_balance_set(dev, ctrl->value);
+       case V4L2_CID_GAMMA:
+               return em28xx_gamma_set(dev, ctrl->value);
+       default:
+               return -EINVAL;
+       }
+}
+
+/*
+ * em28xx_stream_interrupt()
+ * stops streaming
+ */
+static int em28xx_stream_interrupt(struct em28xx *dev)
+{
+       int ret = 0;
+
+       /* stop reading from the device */
+
+       dev->stream = STREAM_INTERRUPT;
+       ret = wait_event_timeout(dev->wait_stream,
+                                (dev->stream == STREAM_OFF) ||
+                                (dev->state & DEV_DISCONNECTED),
+                                EM28XX_URB_TIMEOUT);
+       if (dev->state & DEV_DISCONNECTED)
+               return -ENODEV;
+       else if (ret) {
+               dev->state |= DEV_MISCONFIGURED;
+               em28xx_videodbg("device is misconfigured; close and "
+                       "open /dev/video%d again\n", dev->vdev->minor);
+               return ret;
+       }
+
+       return 0;
+}
+
+static int em28xx_set_norm(struct em28xx *dev, int width, int height)
+{
+       unsigned int hscale, vscale;
+       unsigned int maxh, maxw;
+
+       maxw = norm_maxw(dev);
+       maxh = norm_maxh(dev);
+
+       /* width must even because of the YUYV format */
+       /* height must be even because of interlacing */
+       height &= 0xfffe;
+       width &= 0xfffe;
+
+       if (height < 32)
+               height = 32;
+       if (height > maxh)
+               height = maxh;
+       if (width < 48)
+               width = 48;
+       if (width > maxw)
+               width = maxw;
+
+       if ((hscale = (((unsigned long)maxw) << 12) / width - 4096L) >= 0x4000)
+               hscale = 0x3fff;
+       width = (((unsigned long)maxw) << 12) / (hscale + 4096L);
+
+       if ((vscale = (((unsigned long)maxh) << 12) / height - 4096L) >= 0x4000)
+               vscale = 0x3fff;
+       height = (((unsigned long)maxh) << 12) / (vscale + 4096L);
+
+       /* set new image size */
+       dev->width = width;
+       dev->height = height;
+       dev->frame_size = dev->width * dev->height * 2;
+       dev->field_size = dev->frame_size >> 1; /*both_fileds ? dev->frame_size>>1 : dev->frame_size; */
+       dev->bytesperline = dev->width * 2;
+       dev->hscale = hscale;
+       dev->vscale = vscale;
+
+       em28xx_resolution_set(dev);
+
+       return 0;
+}
+
+/*
+ * em28xx_v4l2_do_ioctl()
+ * This function is _not_ called directly, but from
+ * em28xx_v4l2_ioctl. Userspace
+ * copying is done already, arg is a kernel pointer.
+ */
+static int em28xx_do_ioctl(struct inode *inode, struct file *filp,
+                          struct em28xx *dev, unsigned int cmd, void *arg,
+                          v4l2_kioctl driver_ioctl)
+{
+       int ret;
+
+       switch (cmd) {
+               /* ---------- tv norms ---------- */
+       case VIDIOC_ENUMSTD:
+               {
+                       struct v4l2_standard *e = arg;
+                       unsigned int i;
+
+                       i = e->index;
+                       if (i >= TVNORMS)
+                               return -EINVAL;
+                       ret = v4l2_video_std_construct(e, tvnorms[e->index].id,
+                                                      tvnorms[e->index].name);
+                       e->index = i;
+                       if (ret < 0)
+                               return ret;
+                       return 0;
+               }
+       case VIDIOC_G_STD:
+               {
+                       v4l2_std_id *id = arg;
+
+                       *id = dev->tvnorm->id;
+                       return 0;
+               }
+       case VIDIOC_S_STD:
+               {
+                       v4l2_std_id *id = arg;
+                       unsigned int i;
+
+                       for (i = 0; i < TVNORMS; i++)
+                               if (*id == tvnorms[i].id)
+                                       break;
+                       if (i == TVNORMS)
+                               for (i = 0; i < TVNORMS; i++)
+                                       if (*id & tvnorms[i].id)
+                                               break;
+                       if (i == TVNORMS)
+                               return -EINVAL;
+
+                       down(&dev->lock);
+                       dev->tvnorm = &tvnorms[i];
+
+                       em28xx_set_norm(dev, dev->width, dev->height);
+
+/*
+               dev->width=norm_maxw(dev);
+               dev->height=norm_maxh(dev);
+               dev->frame_size=dev->width*dev->height*2;
+               dev->field_size=dev->frame_size>>1;
+               dev->bytesperline=dev->width*2;
+               dev->hscale=0;
+               dev->vscale=0;
+
+               em28xx_resolution_set(dev);
+*/
+/*
+               em28xx_uninit_isoc(dev);
+               em28xx_set_alternate(dev);
+               em28xx_capture_start(dev, 1);
+               em28xx_resolution_set(dev);
+               em28xx_init_isoc(dev);
+*/
+                       em28xx_i2c_call_clients(dev, DECODER_SET_NORM,
+                                               &tvnorms[i].mode);
+                       em28xx_i2c_call_clients(dev, VIDIOC_S_STD,
+                                               &dev->tvnorm->id);
+
+                       up(&dev->lock);
+
+                       return 0;
+               }
+
+               /* ------ input switching ---------- */
+       case VIDIOC_ENUMINPUT:
+               {
+                       struct v4l2_input *i = arg;
+                       unsigned int n;
+                       static const char *iname[] = {
+                               [EM28XX_VMUX_COMPOSITE1] = "Composite1",
+                               [EM28XX_VMUX_COMPOSITE2] = "Composite2",
+                               [EM28XX_VMUX_COMPOSITE3] = "Composite3",
+                               [EM28XX_VMUX_COMPOSITE4] = "Composite4",
+                               [EM28XX_VMUX_SVIDEO] = "S-Video",
+                               [EM28XX_VMUX_TELEVISION] = "Television",
+                               [EM28XX_VMUX_CABLE] = "Cable TV",
+                               [EM28XX_VMUX_DVB] = "DVB",
+                               [EM28XX_VMUX_DEBUG] = "for debug only",
+                       };
+
+                       n = i->index;
+                       if (n >= MAX_EM28XX_INPUT)
+                               return -EINVAL;
+                       if (0 == INPUT(n)->type)
+                               return -EINVAL;
+                       memset(i, 0, sizeof(*i));
+                       i->index = n;
+                       i->type = V4L2_INPUT_TYPE_CAMERA;
+                       strcpy(i->name, iname[INPUT(n)->type]);
+                       if ((EM28XX_VMUX_TELEVISION == INPUT(n)->type) ||
+                           (EM28XX_VMUX_CABLE == INPUT(n)->type))
+                               i->type = V4L2_INPUT_TYPE_TUNER;
+                       for (n = 0; n < ARRAY_SIZE(tvnorms); n++)
+                               i->std |= tvnorms[n].id;
+                       return 0;
+               }
+
+       case VIDIOC_G_INPUT:
+               {
+                       int *i = arg;
+                       *i = dev->ctl_input;
+
+                       return 0;
+               }
+
+       case VIDIOC_S_INPUT:
+               {
+                       int *index = arg;
+
+                       if (*index >= MAX_EM28XX_INPUT)
+                               return -EINVAL;
+                       if (0 == INPUT(*index)->type)
+                               return -EINVAL;
+
+                       down(&dev->lock);
+                       video_mux(dev, *index);
+                       up(&dev->lock);
+
+                       return 0;
+               }
+
+       case VIDIOC_G_AUDIO:
+               {
+                       struct v4l2_audio *a = arg;
+                       unsigned int index = a->index;
+
+                       if (a->index > 1)
+                               return -EINVAL;
+                       memset(a, 0, sizeof(*a));
+                       index = dev->ctl_ainput;
+
+                       if (index == 0) {
+                               strcpy(a->name, "Television");
+                       } else {
+                               strcpy(a->name, "Line In");
+                       }
+                       a->capability = V4L2_AUDCAP_STEREO;
+                       a->index = index;
+                       return 0;
+               }
+
+       case VIDIOC_S_AUDIO:
+               {
+                       struct v4l2_audio *a = arg;
+                       if (a->index != dev->ctl_ainput)
+                               return -EINVAL;
+
+                       return 0;
+               }
+
+               /* --- controls ---------------------------------------------- */
+       case VIDIOC_QUERYCTRL:
+               {
+                       struct v4l2_queryctrl *qc = arg;
+                       u8 i, n;
+                       n = sizeof(em28xx_qctrl) / sizeof(em28xx_qctrl[0]);
+                       for (i = 0; i < n; i++)
+                               if (qc->id && qc->id == em28xx_qctrl[i].id) {
+                                       memcpy(qc, &(em28xx_qctrl[i]),
+                                              sizeof(*qc));
+                                       return 0;
+                               }
+
+                       return -EINVAL;
+               }
+
+       case VIDIOC_G_CTRL:
+               {
+                       struct v4l2_control *ctrl = arg;
+
+
+                       return em28xx_get_ctrl(dev, ctrl);
+               }
+
+       case VIDIOC_S_CTRL_OLD: /* ??? */
+       case VIDIOC_S_CTRL:
+               {
+                       struct v4l2_control *ctrl = arg;
+                       u8 i, n;
+
+
+                       n = sizeof(em28xx_qctrl) / sizeof(em28xx_qctrl[0]);
+                       for (i = 0; i < n; i++)
+                               if (ctrl->id == em28xx_qctrl[i].id) {
+                                       if (ctrl->value <
+                                           em28xx_qctrl[i].minimum
+                                           || ctrl->value >
+                                           em28xx_qctrl[i].maximum)
+                                               return -ERANGE;
+
+                                       return em28xx_set_ctrl(dev, ctrl);
+                               }
+                       return -EINVAL;
+               }
+
+               /* --- tuner ioctls ------------------------------------------ */
+       case VIDIOC_G_TUNER:
+               {
+                       struct v4l2_tuner *t = arg;
+                       int status = 0;
+
+                       if (0 != t->index)
+                               return -EINVAL;
+
+                       memset(t, 0, sizeof(*t));
+                       strcpy(t->name, "Tuner");
+                       t->type = V4L2_TUNER_ANALOG_TV;
+                       t->capability = V4L2_TUNER_CAP_NORM;
+                       t->rangehigh = 0xffffffffUL;    /* FIXME: set correct range */
+/*             t->signal = 0xffff;*/
+/*             em28xx_i2c_call_clients(dev,VIDIOC_G_TUNER,t);*/
+                       /* No way to get signal strength? */
+                       down(&dev->lock);
+                       em28xx_i2c_call_clients(dev, DECODER_GET_STATUS,
+                                               &status);
+                       up(&dev->lock);
+                       t->signal =
+                           (status & DECODER_STATUS_GOOD) != 0 ? 0xffff : 0;
+
+                       em28xx_videodbg("VIDIO_G_TUNER: signal=%x, afc=%x\n", t->signal,
+                                t->afc);
+                       return 0;
+               }
+       case VIDIOC_S_TUNER:
+               {
+                       struct v4l2_tuner *t = arg;
+                       int status = 0;
+
+                       if (0 != t->index)
+                               return -EINVAL;
+                       memset(t, 0, sizeof(*t));
+                       strcpy(t->name, "Tuner");
+                       t->type = V4L2_TUNER_ANALOG_TV;
+                       t->capability = V4L2_TUNER_CAP_NORM;
+                       t->rangehigh = 0xffffffffUL;    /* FIXME: set correct range */
+/*             t->signal = 0xffff; */
+                       /* No way to get signal strength? */
+                       down(&dev->lock);
+                       em28xx_i2c_call_clients(dev, DECODER_GET_STATUS,
+                                               &status);
+                       up(&dev->lock);
+                       t->signal =
+                           (status & DECODER_STATUS_GOOD) != 0 ? 0xffff : 0;
+
+                       em28xx_videodbg("VIDIO_S_TUNER: signal=%x, afc=%x\n",
+                                t->signal, t->afc);
+                       return 0;
+               }
+       case VIDIOC_G_FREQUENCY:
+               {
+                       struct v4l2_frequency *f = arg;
+
+                       memset(f, 0, sizeof(*f));
+                       f->type = V4L2_TUNER_ANALOG_TV;
+                       f->frequency = dev->ctl_freq;
+
+                       return 0;
+               }
+       case VIDIOC_S_FREQUENCY:
+               {
+                       struct v4l2_frequency *f = arg;
+
+                       if (0 != f->tuner)
+                               return -EINVAL;
+
+                       if (V4L2_TUNER_ANALOG_TV != f->type)
+                               return -EINVAL;
+
+                       down(&dev->lock);
+                       dev->ctl_freq = f->frequency;
+                       em28xx_i2c_call_clients(dev, VIDIOC_S_FREQUENCY, f);
+                       up(&dev->lock);
+                       return 0;
+               }
+
+       case VIDIOC_CROPCAP:
+               {
+                       struct v4l2_cropcap *cc = arg;
+
+                       if (cc->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+                               return -EINVAL;
+                       cc->bounds.left = 0;
+                       cc->bounds.top = 0;
+                       cc->bounds.width = dev->width;
+                       cc->bounds.height = dev->height;
+                       cc->defrect = cc->bounds;
+                       cc->pixelaspect.numerator = 54; /* 4:3 FIXME: remove magic numbers */
+                       cc->pixelaspect.denominator = 59;
+                       return 0;
+               }
+       case VIDIOC_STREAMON:
+               {
+                       int *type = arg;
+
+                       if (*type != V4L2_BUF_TYPE_VIDEO_CAPTURE
+                           || dev->io != IO_MMAP)
+                               return -EINVAL;
+
+                       if (list_empty(&dev->inqueue))
+                               return -EINVAL;
+
+                       dev->stream = STREAM_ON;        /* FIXME: Start video capture here? */
+
+                       em28xx_videodbg("VIDIOC_STREAMON: starting stream\n");
+
+                       return 0;
+               }
+       case VIDIOC_STREAMOFF:
+               {
+                       int *type = arg;
+                       int ret;
+
+                       if (*type != V4L2_BUF_TYPE_VIDEO_CAPTURE
+                           || dev->io != IO_MMAP)
+                               return -EINVAL;
+
+                       if (dev->stream == STREAM_ON) {
+                               em28xx_videodbg ("VIDIOC_STREAMOFF: interrupting stream\n");
+                               if ((ret = em28xx_stream_interrupt(dev)))
+                                       return ret;
+                       }
+                       em28xx_empty_framequeues(dev);
+
+                       return 0;
+               }
+       default:
+               return v4l_compat_translate_ioctl(inode, filp, cmd, arg,
+                                                 driver_ioctl);
+       }
+       return 0;
+}
+
+/*
+ * em28xx_v4l2_do_ioctl()
+ * This function is _not_ called directly, but from
+ * em28xx_v4l2_ioctl. Userspace
+ * copying is done already, arg is a kernel pointer.
+ */
+static int em28xx_video_do_ioctl(struct inode *inode, struct file *filp,
+                                unsigned int cmd, void *arg)
+{
+       struct em28xx *dev = filp->private_data;
+
+       if (!dev)
+               return -ENODEV;
+
+       if (video_debug > 1)
+               em28xx_print_ioctl(dev->name,cmd);
+
+       switch (cmd) {
+
+               /* --- capabilities ------------------------------------------ */
+       case VIDIOC_QUERYCAP:
+               {
+                       struct v4l2_capability *cap = arg;
+
+                       memset(cap, 0, sizeof(*cap));
+                       strlcpy(cap->driver, "em28xx", sizeof(cap->driver));
+                       strlcpy(cap->card, em28xx_boards[dev->model].name,
+                               sizeof(cap->card));
+                       strlcpy(cap->bus_info, dev->udev->dev.bus_id,
+                               sizeof(cap->bus_info));
+                       cap->version = EM28XX_VERSION_CODE;
+                       cap->capabilities =
+                           V4L2_CAP_VIDEO_CAPTURE |
+                           V4L2_CAP_AUDIO |
+                           V4L2_CAP_READWRITE | V4L2_CAP_STREAMING;
+                       if (dev->has_tuner)
+                               cap->capabilities |= V4L2_CAP_TUNER;
+                       return 0;
+               }
+
+               /* --- capture ioctls ---------------------------------------- */
+       case VIDIOC_ENUM_FMT:
+               {
+                       struct v4l2_fmtdesc *fmtd = arg;
+
+                       if (fmtd->index != 0)
+                               return -EINVAL;
+                       memset(fmtd, 0, sizeof(*fmtd));
+                       fmtd->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+                       strcpy(fmtd->description, "Packed YUY2");
+                       fmtd->pixelformat = V4L2_PIX_FMT_YUYV;
+                       memset(fmtd->reserved, 0, sizeof(fmtd->reserved));
+                       return 0;
+               }
+
+       case VIDIOC_G_FMT:
+               {
+                       struct v4l2_format *format = arg;
+
+                       em28xx_videodbg("VIDIOC_G_FMT: type=%s\n",
+                                format->type ==
+                                V4L2_BUF_TYPE_VIDEO_CAPTURE ?
+                                "V4L2_BUF_TYPE_VIDEO_CAPTURE" : format->type ==
+                                V4L2_BUF_TYPE_VBI_CAPTURE ?
+                                "V4L2_BUF_TYPE_VBI_CAPTURE " :
+                                "not supported");
+
+                       if (format->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+                               return -EINVAL;
+
+                       format->fmt.pix.width = dev->width;
+                       format->fmt.pix.height = dev->height;
+                       format->fmt.pix.pixelformat = V4L2_PIX_FMT_YUYV;
+                       format->fmt.pix.bytesperline = dev->bytesperline;
+                       format->fmt.pix.sizeimage = dev->frame_size;
+                       format->fmt.pix.colorspace = V4L2_COLORSPACE_SMPTE170M;
+                       format->fmt.pix.field = dev->interlaced ? V4L2_FIELD_INTERLACED : V4L2_FIELD_TOP;       /* FIXME: TOP? NONE? BOTTOM? ALTENATE? */
+
+                       em28xx_videodbg("VIDIOC_G_FMT: %dx%d\n", dev->width,
+                                dev->height);
+                       return 0;
+               }
+
+       case VIDIOC_TRY_FMT:
+       case VIDIOC_S_FMT:
+               {
+                       struct v4l2_format *format = arg;
+                       u32 i;
+                       int ret = 0;
+                       int width = format->fmt.pix.width;
+                       int height = format->fmt.pix.height;
+                       unsigned int hscale, vscale;
+                       unsigned int maxh, maxw;
+
+                       maxw = norm_maxw(dev);
+                       maxh = norm_maxh(dev);
+
+/*             int both_fields; */
+
+                       em28xx_videodbg("%s: type=%s\n",
+                                cmd ==
+                                VIDIOC_TRY_FMT ? "VIDIOC_TRY_FMT" :
+                                "VIDIOC_S_FMT",
+                                format->type ==
+                                V4L2_BUF_TYPE_VIDEO_CAPTURE ?
+                                "V4L2_BUF_TYPE_VIDEO_CAPTURE" : format->type ==
+                                V4L2_BUF_TYPE_VBI_CAPTURE ?
+                                "V4L2_BUF_TYPE_VBI_CAPTURE " :
+                                "not supported");
+
+                       if (format->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+                               return -EINVAL;
+
+                       em28xx_videodbg("%s: requested %dx%d\n",
+                                cmd ==
+                                VIDIOC_TRY_FMT ? "VIDIOC_TRY_FMT" :
+                                "VIDIOC_S_FMT", format->fmt.pix.width,
+                                format->fmt.pix.height);
+
+                       /* FIXME: Move some code away from here */
+                       /* width must even because of the YUYV format */
+                       /* height must be even because of interlacing */
+                       height &= 0xfffe;
+                       width &= 0xfffe;
+
+                       if (height < 32)
+                               height = 32;
+                       if (height > maxh)
+                               height = maxh;
+                       if (width < 48)
+                               width = 48;
+                       if (width > maxw)
+                               width = maxw;
+
+                       if(dev->is_em2800){
+                               /* the em2800 can only scale down to 50% */
+                               if(height % (maxh / 2))
+                                       height=maxh;
+                               if(width % (maxw / 2))
+                                       width=maxw;
+                               /* according to empiatech support */
+                               /* the MaxPacketSize is to small to support */
+                               /* framesizes larger than 640x480 @ 30 fps */
+                               /* or 640x576 @ 25 fps. As this would cut */
+                               /* of a part of the image we prefer */
+                               /* 360x576 or 360x480 for now */
+                               if(width == maxw && height == maxh)
+                                       width /= 2;
+                       }
+
+                       if ((hscale =
+                            (((unsigned long)maxw) << 12) / width - 4096L) >=
+                           0x4000)
+                               hscale = 0x3fff;
+                       width =
+                           (((unsigned long)maxw) << 12) / (hscale + 4096L);
+
+                       if ((vscale =
+                            (((unsigned long)maxh) << 12) / height - 4096L) >=
+                           0x4000)
+                               vscale = 0x3fff;
+                       height =
+                           (((unsigned long)maxh) << 12) / (vscale + 4096L);
+
+                       format->fmt.pix.width = width;
+                       format->fmt.pix.height = height;
+                       format->fmt.pix.pixelformat = V4L2_PIX_FMT_YUYV;
+                       format->fmt.pix.bytesperline = width * 2;
+                       format->fmt.pix.sizeimage = width * 2 * height;
+                       format->fmt.pix.colorspace = V4L2_COLORSPACE_SMPTE170M;
+                       format->fmt.pix.field = V4L2_FIELD_INTERLACED;
+
+                       em28xx_videodbg("%s: returned %dx%d (%d, %d)\n",
+                                cmd ==
+                                VIDIOC_TRY_FMT ? "VIDIOC_TRY_FMT" :
+                                "VIDIOC_S_FMT", format->fmt.pix.width,
+                                format->fmt.pix.height, hscale, vscale);
+
+                       if (cmd == VIDIOC_TRY_FMT)
+                               return 0;
+
+                       for (i = 0; i < dev->num_frames; i++)
+                               if (dev->frame[i].vma_use_count) {
+                                       em28xx_videodbg("VIDIOC_S_FMT failed. "
+                                               "Unmap the buffers first.\n");
+                                       return -EINVAL;
+                               }
+
+                       /* stop io in case it is already in progress */
+                       if (dev->stream == STREAM_ON) {
+                               em28xx_videodbg("VIDIOC_SET_FMT: interupting stream\n");
+                               if ((ret = em28xx_stream_interrupt(dev)))
+                                       return ret;
+                       }
+
+                       em28xx_release_buffers(dev);
+                       dev->io = IO_NONE;
+
+                       /* set new image size */
+                       dev->width = width;
+                       dev->height = height;
+                       dev->frame_size = dev->width * dev->height * 2;
+                       dev->field_size = dev->frame_size >> 1; /*both_fileds ? dev->frame_size>>1 : dev->frame_size; */
+                       dev->bytesperline = dev->width * 2;
+                       dev->hscale = hscale;
+                       dev->vscale = vscale;
+/*                     dev->both_fileds = both_fileds; */
+                       em28xx_uninit_isoc(dev);
+                       em28xx_set_alternate(dev);
+                       em28xx_capture_start(dev, 1);
+                       em28xx_resolution_set(dev);
+                       em28xx_init_isoc(dev);
+
+                       return 0;
+               }
+
+               /* --- streaming capture ------------------------------------- */
+       case VIDIOC_REQBUFS:
+               {
+                       struct v4l2_requestbuffers *rb = arg;
+                       u32 i;
+                       int ret;
+
+                       if (rb->type != V4L2_BUF_TYPE_VIDEO_CAPTURE ||
+                           rb->memory != V4L2_MEMORY_MMAP)
+                               return -EINVAL;
+
+                       if (dev->io == IO_READ) {
+                               em28xx_videodbg ("method is set to read;"
+                                       " close and open the device again to"
+                                       " choose the mmap I/O method\n");
+                               return -EINVAL;
+                       }
+
+                       for (i = 0; i < dev->num_frames; i++)
+                               if (dev->frame[i].vma_use_count) {
+                                       em28xx_videodbg ("VIDIOC_REQBUFS failed; previous buffers are still mapped\n");
+                                       return -EINVAL;
+                               }
+
+                       if (dev->stream == STREAM_ON) {
+                               em28xx_videodbg("VIDIOC_REQBUFS: interrupting stream\n");
+                               if ((ret = em28xx_stream_interrupt(dev)))
+                                       return ret;
+                       }
+
+                       em28xx_empty_framequeues(dev);
+
+                       em28xx_release_buffers(dev);
+                       if (rb->count)
+                               rb->count =
+                                   em28xx_request_buffers(dev, rb->count);
+
+                       dev->frame_current = NULL;
+
+                       em28xx_videodbg ("VIDIOC_REQBUFS: setting io method to mmap: num bufs %i\n",
+                                                    rb->count);
+                       dev->io = rb->count ? IO_MMAP : IO_NONE;
+                       return 0;
+               }
+
+       case VIDIOC_QUERYBUF:
+               {
+                       struct v4l2_buffer *b = arg;
+
+                       if (b->type != V4L2_BUF_TYPE_VIDEO_CAPTURE ||
+                           b->index >= dev->num_frames || dev->io != IO_MMAP)
+                               return -EINVAL;
+
+                       memcpy(b, &dev->frame[b->index].buf, sizeof(*b));
+
+                       if (dev->frame[b->index].vma_use_count) {
+                               b->flags |= V4L2_BUF_FLAG_MAPPED;
+                       }
+                       if (dev->frame[b->index].state == F_DONE)
+                               b->flags |= V4L2_BUF_FLAG_DONE;
+                       else if (dev->frame[b->index].state != F_UNUSED)
+                               b->flags |= V4L2_BUF_FLAG_QUEUED;
+                       return 0;
+               }
+       case VIDIOC_QBUF:
+               {
+                       struct v4l2_buffer *b = arg;
+                       unsigned long lock_flags;
+
+                       if (b->type != V4L2_BUF_TYPE_VIDEO_CAPTURE ||
+                           b->index >= dev->num_frames || dev->io != IO_MMAP) {
+                               return -EINVAL;
+                       }
+
+                       if (dev->frame[b->index].state != F_UNUSED) {
+                               return -EAGAIN;
+                       }
+                       dev->frame[b->index].state = F_QUEUED;
+
+                       /* add frame to fifo */
+                       spin_lock_irqsave(&dev->queue_lock, lock_flags);
+                       list_add_tail(&dev->frame[b->index].frame,
+                                     &dev->inqueue);
+                       spin_unlock_irqrestore(&dev->queue_lock, lock_flags);
+
+                       return 0;
+               }
+       case VIDIOC_DQBUF:
+               {
+                       struct v4l2_buffer *b = arg;
+                       struct em28xx_frame_t *f;
+                       unsigned long lock_flags;
+                       int ret = 0;
+
+                       if (b->type != V4L2_BUF_TYPE_VIDEO_CAPTURE
+                           || dev->io != IO_MMAP)
+                               return -EINVAL;
+
+                       if (list_empty(&dev->outqueue)) {
+                               if (dev->stream == STREAM_OFF)
+                                       return -EINVAL;
+                               if (filp->f_flags & O_NONBLOCK)
+                                       return -EAGAIN;
+                               ret = wait_event_interruptible
+                                   (dev->wait_frame,
+                                    (!list_empty(&dev->outqueue)) ||
+                                    (dev->state & DEV_DISCONNECTED));
+                               if (ret)
+                                       return ret;
+                               if (dev->state & DEV_DISCONNECTED)
+                                       return -ENODEV;
+                       }
+
+                       spin_lock_irqsave(&dev->queue_lock, lock_flags);
+                       f = list_entry(dev->outqueue.next,
+                                      struct em28xx_frame_t, frame);
+                       list_del(dev->outqueue.next);
+                       spin_unlock_irqrestore(&dev->queue_lock, lock_flags);
+
+                       f->state = F_UNUSED;
+                       memcpy(b, &f->buf, sizeof(*b));
+
+                       if (f->vma_use_count)
+                               b->flags |= V4L2_BUF_FLAG_MAPPED;
+
+                       return 0;
+               }
+       default:
+               return em28xx_do_ioctl(inode, filp, dev, cmd, arg,
+                                      em28xx_video_do_ioctl);
+       }
+       return 0;
+}
+
+/*
+ * em28xx_v4l2_ioctl()
+ * handle v4l2 ioctl the main action happens in em28xx_v4l2_do_ioctl()
+ */
+static int em28xx_v4l2_ioctl(struct inode *inode, struct file *filp,
+                            unsigned int cmd, unsigned long arg)
+{
+       int ret = 0;
+       struct em28xx *dev = filp->private_data;
+
+       if (down_interruptible(&dev->fileop_lock))
+               return -ERESTARTSYS;
+
+       if (dev->state & DEV_DISCONNECTED) {
+               em28xx_errdev("v4l2 ioctl: device not present\n");
+               up(&dev->fileop_lock);
+               return -ENODEV;
+       }
+
+       if (dev->state & DEV_MISCONFIGURED) {
+               em28xx_errdev
+                   ("v4l2 ioctl: device is misconfigured; close and open it again\n");
+               up(&dev->fileop_lock);
+               return -EIO;
+       }
+
+       ret = video_usercopy(inode, filp, cmd, arg, em28xx_video_do_ioctl);
+
+       up(&dev->fileop_lock);
+
+       return ret;
+}
+
+static struct file_operations em28xx_v4l_fops = {
+       .owner = THIS_MODULE,
+       .open = em28xx_v4l2_open,
+       .release = em28xx_v4l2_close,
+       .ioctl = em28xx_v4l2_ioctl,
+       .read = em28xx_v4l2_read,
+       .poll = em28xx_v4l2_poll,
+       .mmap = em28xx_v4l2_mmap,
+       .llseek = no_llseek,
+};
+
+/******************************** usb interface *****************************************/
+
+/*
+ * em28xx_init_dev()
+ * allocates and inits the device structs, registers i2c bus and v4l device
+ */
+static int em28xx_init_dev(struct em28xx **devhandle, struct usb_device *udev,
+                          int minor, int model)
+{
+       struct em28xx *dev = *devhandle;
+       int retval = -ENOMEM;
+       int errCode, i;
+       unsigned int maxh, maxw;
+
+       dev->udev = udev;
+       dev->model = model;
+       init_MUTEX(&dev->lock);
+       init_waitqueue_head(&dev->open);
+
+       dev->em28xx_write_regs = em28xx_write_regs;
+       dev->em28xx_read_reg = em28xx_read_reg;
+       dev->em28xx_read_reg_req_len = em28xx_read_reg_req_len;
+       dev->em28xx_write_regs_req = em28xx_write_regs_req;
+       dev->em28xx_read_reg_req = em28xx_read_reg_req;
+       dev->is_em2800 = em28xx_boards[model].is_em2800;
+       dev->has_tuner = em28xx_boards[model].has_tuner;
+       dev->has_msp34xx = em28xx_boards[model].has_msp34xx;
+       dev->tda9887_conf = em28xx_boards[model].tda9887_conf;
+       dev->decoder = em28xx_boards[model].decoder;
+
+       if (tuner >= 0)
+               dev->tuner_type = tuner;
+       else
+               dev->tuner_type = em28xx_boards[model].tuner_type;
+
+       dev->video_inputs = em28xx_boards[model].vchannels;
+
+       for (i = 0; i < TVNORMS; i++)
+               if (em28xx_boards[model].norm == tvnorms[i].mode)
+                       break;
+       if (i == TVNORMS)
+               i = 0;
+
+       dev->tvnorm = &tvnorms[i];      /* set default norm */
+
+       em28xx_videodbg("tvnorm=%s\n", dev->tvnorm->name);
+
+       maxw = norm_maxw(dev);
+       maxh = norm_maxh(dev);
+
+       /* set default image size */
+       dev->width = maxw;
+       dev->height = maxh;
+       dev->interlaced = EM28XX_INTERLACED_DEFAULT;
+       dev->field_size = dev->width * dev->height;
+       dev->frame_size =
+           dev->interlaced ? dev->field_size << 1 : dev->field_size;
+       dev->bytesperline = dev->width * 2;
+       dev->hscale = 0;
+       dev->vscale = 0;
+       dev->ctl_input = 2;
+
+       /* setup video picture settings for saa7113h */
+       memset(&dev->vpic, 0, sizeof(dev->vpic));
+       dev->vpic.colour = 128 << 8;
+       dev->vpic.hue = 128 << 8;
+       dev->vpic.brightness = 128 << 8;
+       dev->vpic.contrast = 192 << 8;
+       dev->vpic.whiteness = 128 << 8; /* This one isn't used */
+       dev->vpic.depth = 16;
+       dev->vpic.palette = VIDEO_PALETTE_YUV422;
+
+#ifdef CONFIG_MODULES
+       /* request some modules */
+       if (dev->decoder == EM28XX_SAA7113 || dev->decoder == EM28XX_SAA7114)
+               request_module("saa711x");
+       if (dev->decoder == EM28XX_TVP5150)
+               request_module("tvp5150");
+       if (dev->has_tuner)
+               request_module("tuner");
+       if (dev->tda9887_conf)
+               request_module("tda9887");
+#endif
+       errCode = em28xx_config(dev);
+       if (errCode) {
+               em28xx_errdev("error configuring device\n");
+               kfree(dev);
+               return -ENOMEM;
+       }
+
+       down(&dev->lock);
+       /* register i2c bus */
+       em28xx_i2c_register(dev);
+
+       /* Do board specific init and eeprom reading */
+       em28xx_card_setup(dev);
+
+       /* configure the device */
+       em28xx_config_i2c(dev);
+
+       up(&dev->lock);
+
+       errCode = em28xx_config(dev);
+
+#ifdef CONFIG_MODULES
+       if (dev->has_msp34xx)
+               request_module("msp3400");
+#endif
+       /* allocate and fill v4l2 device struct */
+       dev->vdev = video_device_alloc();
+       if (NULL == dev->vdev) {
+               em28xx_errdev("cannot allocate video_device.\n");
+               kfree(dev);
+               return -ENOMEM;
+       }
+
+       dev->vdev->type = VID_TYPE_CAPTURE;
+       if (dev->has_tuner)
+               dev->vdev->type |= VID_TYPE_TUNER;
+       dev->vdev->hardware = 0;
+       dev->vdev->fops = &em28xx_v4l_fops;
+       dev->vdev->minor = -1;
+       dev->vdev->dev = &dev->udev->dev;
+       dev->vdev->release = video_device_release;
+       snprintf(dev->vdev->name, sizeof(dev->vdev->name), "%s",
+                "em28xx video");
+       list_add_tail(&dev->devlist,&em28xx_devlist);
+
+       /* register v4l2 device */
+       down(&dev->lock);
+       if ((retval = video_register_device(dev->vdev, VFL_TYPE_GRABBER, -1))) {
+               em28xx_errdev("unable to register video device (error=%i).\n",
+                             retval);
+               up(&dev->lock);
+               list_del(&dev->devlist);
+               video_device_release(dev->vdev);
+               kfree(dev);
+               return -ENODEV;
+       }
+       if (dev->has_msp34xx) {
+               /* Send a reset to other chips via gpio */
+               em28xx_write_regs_req(dev, 0x00, 0x08, "\xf7", 1);
+               udelay(2500);
+               em28xx_write_regs_req(dev, 0x00, 0x08, "\xff", 1);
+               udelay(2500);
+
+       }
+       video_mux(dev, 0);
+
+       up(&dev->lock);
+
+       em28xx_info("V4L2 device registered as /dev/video%d\n",
+                   dev->vdev->minor);
+
+       return 0;
+}
+
+/*
+ * em28xx_usb_probe()
+ * checks for supported devices
+ */
+static int em28xx_usb_probe(struct usb_interface *interface,
+                           const struct usb_device_id *id)
+{
+       const struct usb_endpoint_descriptor *endpoint;
+       struct usb_device *udev;
+       struct usb_interface *uif;
+       struct em28xx *dev = NULL;
+       int retval = -ENODEV;
+       int model,i,nr,ifnum;
+
+       udev = usb_get_dev(interface_to_usbdev(interface));
+       ifnum = interface->altsetting[0].desc.bInterfaceNumber;
+
+
+       /* Don't register audio interfaces */
+       if (interface->altsetting[0].desc.bInterfaceClass == USB_CLASS_AUDIO) {
+               em28xx_err(DRIVER_NAME " audio device (%04x:%04x): interface %i, class %i\n",
+                               udev->descriptor.idVendor,udev->descriptor.idProduct,
+                               ifnum,
+                               interface->altsetting[0].desc.bInterfaceClass);
+               return -ENODEV;
+       }
+
+       em28xx_err(DRIVER_NAME " new video device (%04x:%04x): interface %i, class %i\n",
+                       udev->descriptor.idVendor,udev->descriptor.idProduct,
+                       ifnum,
+                       interface->altsetting[0].desc.bInterfaceClass);
+
+       endpoint = &interface->cur_altsetting->endpoint[1].desc;
+
+       /* check if the the device has the iso in endpoint at the correct place */
+       if ((endpoint->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) !=
+           USB_ENDPOINT_XFER_ISOC) {
+               em28xx_err(DRIVER_NAME " probing error: endpoint is non-ISO endpoint!\n");
+               return -ENODEV;
+       }
+       if ((endpoint->bEndpointAddress & USB_ENDPOINT_DIR_MASK) == USB_DIR_OUT) {
+               em28xx_err(DRIVER_NAME " probing error: endpoint is ISO OUT endpoint!\n");
+               return -ENODEV;
+       }
+
+       model=id->driver_info;
+       nr=interface->minor;
+
+       if (nr>EM28XX_MAXBOARDS) {
+               printk (DRIVER_NAME ": Supports only %i em28xx boards.\n",EM28XX_MAXBOARDS);
+               return -ENOMEM;
+       }
+
+       /* allocate memory for our device state and initialize it */
+       dev = kmalloc(sizeof(*dev), GFP_KERNEL);
+       if (dev == NULL) {
+               em28xx_err(DRIVER_NAME ": out of memory!\n");
+               return -ENOMEM;
+       }
+       memset(dev, 0, sizeof(*dev));
+
+       /* compute alternate max packet sizes */
+       uif = udev->actconfig->interface[0];
+
+       dev->num_alt=uif->num_altsetting;
+       printk(DRIVER_NAME ": Alternate settings: %i\n",dev->num_alt);
+//     dev->alt_max_pkt_size = kmalloc(sizeof(*dev->alt_max_pkt_size)*
+       dev->alt_max_pkt_size = kmalloc(32*
+                                               dev->num_alt,GFP_KERNEL);
+       if (dev->alt_max_pkt_size == NULL) {
+               em28xx_err(DRIVER_NAME ": out of memory!\n");
+               return -ENOMEM;
+       }
+
+       for (i = 0; i < dev->num_alt ; i++) {
+               u16 tmp = le16_to_cpu(uif->altsetting[i].endpoint[1].desc.
+                                                       wMaxPacketSize);
+               dev->alt_max_pkt_size[i] =
+                   (tmp & 0x07ff) * (((tmp & 0x1800) >> 11) + 1);
+               printk(DRIVER_NAME ": Alternate setting %i, max size= %i\n",i,
+                                                       dev->alt_max_pkt_size[i]);
+       }
+
+       snprintf(dev->name, 29, "em28xx #%d", nr);
+
+       if ((card[nr]>=0)&&(card[nr]<em28xx_bcount))
+               model=card[nr];
+
+       if ((model==EM2800_BOARD_UNKNOWN)||(model==EM2820_BOARD_UNKNOWN)) {
+               printk( "%s: Your board has no eeprom inside it and thus can't\n"
+                       "%s: be autodetected.  Please pass card=<n> insmod option to\n"
+                       "%s: workaround that.  Redirect complaints to the vendor of\n"
+                       "%s: the TV card.  Best regards,\n"
+                       "%s:         -- tux\n",
+                       dev->name,dev->name,dev->name,dev->name,dev->name);
+               printk("%s: Here is a list of valid choices for the card=<n> insmod option:\n",
+                       dev->name);
+               for (i = 0; i < em28xx_bcount; i++) {
+                       printk("%s:    card=%d -> %s\n",
+                               dev->name, i, em28xx_boards[i].name);
+               }
+       }
+
+       /* allocate device struct */
+       retval = em28xx_init_dev(&dev, udev, nr, model);
+       if (retval)
+               return retval;
+
+       em28xx_info("Found %s\n", em28xx_boards[model].name);
+
+       /* save our data pointer in this interface device */
+       usb_set_intfdata(interface, dev);
+       return 0;
+}
+
+/*
+ * em28xx_usb_disconnect()
+ * called when the device gets diconencted
+ * video device will be unregistered on v4l2_close in case it is still open
+ */
+static void em28xx_usb_disconnect(struct usb_interface *interface)
+{
+       struct em28xx *dev = usb_get_intfdata(interface);
+       usb_set_intfdata(interface, NULL);
+
+       if (!dev)
+               return;
+
+       down_write(&em28xx_disconnect);
+
+       down(&dev->lock);
+
+       em28xx_info("disconnecting %s\n", dev->vdev->name);
+
+       wake_up_interruptible_all(&dev->open);
+
+       if (dev->users) {
+               em28xx_warn
+                   ("device /dev/video%d is open! Deregistration and memory "
+                    "deallocation are deferred on close.\n", dev->vdev->minor);
+               dev->state |= DEV_MISCONFIGURED;
+               em28xx_uninit_isoc(dev);
+               dev->state |= DEV_DISCONNECTED;
+               wake_up_interruptible(&dev->wait_frame);
+               wake_up_interruptible(&dev->wait_stream);
+       } else {
+               dev->state |= DEV_DISCONNECTED;
+               em28xx_release_resources(dev);
+       }
+
+       up(&dev->lock);
+
+       if (!dev->users) {
+               kfree(dev->alt_max_pkt_size);
+               kfree(dev);
+       }
+
+       up_write(&em28xx_disconnect);
+}
+
+static struct usb_driver em28xx_usb_driver = {
+       .owner = THIS_MODULE,
+       .name = "em28xx",
+       .probe = em28xx_usb_probe,
+       .disconnect = em28xx_usb_disconnect,
+       .id_table = em28xx_id_table,
+};
+
+static int __init em28xx_module_init(void)
+{
+       int result;
+
+       printk(KERN_INFO DRIVER_NAME " v4l2 driver version %d.%d.%d loaded\n",
+              (EM28XX_VERSION_CODE >> 16) & 0xff,
+              (EM28XX_VERSION_CODE >> 8) & 0xff, EM28XX_VERSION_CODE & 0xff);
+#ifdef SNAPSHOT
+       printk(KERN_INFO DRIVER_NAME " snapshot date %04d-%02d-%02d\n",
+              SNAPSHOT / 10000, (SNAPSHOT / 100) % 100, SNAPSHOT % 100);
+#endif
+
+       /* register this driver with the USB subsystem */
+       result = usb_register(&em28xx_usb_driver);
+       if (result)
+               em28xx_err(DRIVER_NAME
+                          " usb_register failed. Error number %d.\n", result);
+
+       return result;
+}
+
+static void __exit em28xx_module_exit(void)
+{
+       /* deregister this driver with the USB subsystem */
+       usb_deregister(&em28xx_usb_driver);
+}
+
+module_init(em28xx_module_init);
+module_exit(em28xx_module_exit);
diff --git a/drivers/media/video/em28xx/em28xx.h b/drivers/media/video/em28xx/em28xx.h
new file mode 100644 (file)
index 0000000..5c7a41c
--- /dev/null
@@ -0,0 +1,513 @@
+/*
+   em28xx-cards.c - driver for Empia EM2800/EM2820/2840 USB video capture devices
+
+   Copyright (C) 2005 Markus Rechberger <mrechberger@gmail.com>
+                     Ludovico Cavedon <cavedon@sssup.it>
+                     Mauro Carvalho Chehab <mchehab@brturbo.com.br>
+
+   Based on the em2800 driver from Sascha Sommer <saschasommer@freenet.de>
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 2 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software
+   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#ifndef _EM28XX_H
+#define _EM28XX_H
+
+#include <linux/videodev.h>
+#include <linux/i2c.h>
+#include <media/ir-kbd-i2c.h>
+
+/* Boards supported by driver */
+
+#define EM2800_BOARD_UNKNOWN                   0
+#define EM2820_BOARD_UNKNOWN                   1
+#define EM2820_BOARD_TERRATEC_CINERGY_250      2
+#define EM2820_BOARD_PINNACLE_USB_2            3
+#define EM2820_BOARD_HAUPPAUGE_WINTV_USB_2      4
+#define EM2820_BOARD_MSI_VOX_USB_2              5
+#define EM2800_BOARD_TERRATEC_CINERGY_200       6
+#define EM2800_BOARD_LEADTEK_WINFAST_USBII      7
+#define EM2800_BOARD_KWORLD_USB2800             8
+#define EM2820_BOARD_PINNACLE_DVC_90           9
+
+#define UNSET -1
+
+/* maximum number of em28xx boards */
+#define EM28XX_MAXBOARDS 1 /*FIXME: should be bigger */
+
+/* maximum number of frames that can be queued */
+#define EM28XX_NUM_FRAMES 5
+/* number of frames that get used for v4l2_read() */
+#define EM28XX_NUM_READ_FRAMES 2
+
+/* number of buffers for isoc transfers */
+#define EM28XX_NUM_BUFS 5
+
+/* number of packets for each buffer
+   windows requests only 40 packets .. so we better do the same
+   this is what I found out for all alternate numbers there!
+ */
+#define EM28XX_NUM_PACKETS 40
+
+/* default alternate; 0 means choose the best */
+#define EM28XX_PINOUT 0
+
+#define EM28XX_INTERLACED_DEFAULT 1
+
+/*
+#define (use usbview if you want to get the other alternate number infos)
+#define
+#define alternate number 2
+#define                        Endpoint Address: 82
+                       Direction: in
+                       Attribute: 1
+                       Type: Isoc
+                       Max Packet Size: 1448
+                       Interval: 125us
+
+  alternate number 7
+
+                       Endpoint Address: 82
+                       Direction: in
+                       Attribute: 1
+                       Type: Isoc
+                       Max Packet Size: 3072
+                       Interval: 125us
+*/
+
+/* time to wait when stopping the isoc transfer */
+#define EM28XX_URB_TIMEOUT       msecs_to_jiffies(EM28XX_NUM_BUFS * EM28XX_NUM_PACKETS)
+
+/* time in msecs to wait for i2c writes to finish */
+#define EM2800_I2C_WRITE_TIMEOUT 20
+
+/* the various frame states */
+enum em28xx_frame_state {
+       F_UNUSED = 0,
+       F_QUEUED,
+       F_GRABBING,
+       F_DONE,
+       F_ERROR,
+};
+
+/* stream states */
+enum em28xx_stream_state {
+       STREAM_OFF,
+       STREAM_INTERRUPT,
+       STREAM_ON,
+};
+
+/* frames */
+struct em28xx_frame_t {
+       void *bufmem;
+       struct v4l2_buffer buf;
+       enum em28xx_frame_state state;
+       struct list_head frame;
+       unsigned long vma_use_count;
+       int top_field;
+       int fieldbytesused;
+};
+
+/* io methods */
+enum em28xx_io_method {
+       IO_NONE,
+       IO_READ,
+       IO_MMAP,
+};
+
+/* inputs */
+
+#define MAX_EM28XX_INPUT 4
+enum enum28xx_itype {
+       EM28XX_VMUX_COMPOSITE1 = 1,
+       EM28XX_VMUX_COMPOSITE2,
+       EM28XX_VMUX_COMPOSITE3,
+       EM28XX_VMUX_COMPOSITE4,
+       EM28XX_VMUX_SVIDEO,
+       EM28XX_VMUX_TELEVISION,
+       EM28XX_VMUX_CABLE,
+       EM28XX_VMUX_DVB,
+       EM28XX_VMUX_DEBUG,
+       EM28XX_RADIO,
+};
+
+struct em28xx_input {
+       enum enum28xx_itype type;
+       unsigned int vmux;
+       unsigned int amux;
+};
+
+#define INPUT(nr) (&em28xx_boards[dev->model].input[nr])
+
+enum em28xx_decoder {
+       EM28XX_TVP5150,
+       EM28XX_SAA7113,
+       EM28XX_SAA7114
+};
+
+struct em28xx_board {
+       char *name;
+       int vchannels;
+       int norm;
+       int tuner_type;
+
+       /* i2c flags */
+       unsigned int is_em2800;
+       unsigned int tda9887_conf;
+
+       unsigned int has_tuner:1;
+       unsigned int has_msp34xx:1;
+
+       enum em28xx_decoder decoder;
+
+       struct em28xx_input       input[MAX_EM28XX_INPUT];
+};
+
+struct em28xx_eeprom {
+       u32 id;                 /* 0x9567eb1a */
+       u16 vendor_ID;
+       u16 product_ID;
+
+       u16 chip_conf;
+
+       u16 board_conf;
+
+       u16 string1, string2, string3;
+
+       u8 string_idx_table;
+};
+
+/* device states */
+enum em28xx_dev_state {
+       DEV_INITIALIZED = 0x01,
+       DEV_DISCONNECTED = 0x02,
+       DEV_MISCONFIGURED = 0x04,
+};
+
+/* tvnorms */
+struct em28xx_tvnorm {
+       char *name;
+       v4l2_std_id id;
+       /* mode for saa7113h */
+       int mode;
+};
+
+/* main device struct */
+struct em28xx {
+       /* generic device properties */
+       char name[30];          /* name (including minor) of the device */
+       int model;              /* index in the device_data struct */
+       unsigned int is_em2800;
+       int video_inputs;       /* number of video inputs */
+       struct list_head        devlist;
+       unsigned int has_tuner:1;
+       unsigned int has_msp34xx:1;
+       unsigned int has_tda9887:1;
+
+       enum em28xx_decoder decoder;
+
+       int tuner_type;         /* type of the tuner */
+       int tuner_addr;         /* tuner address */
+       int tda9887_conf;
+       /* i2c i/o */
+       struct i2c_adapter i2c_adap;
+       struct i2c_client i2c_client;
+       /* video for linux */
+       int users;              /* user count for exclusive use */
+       struct video_device *vdev;      /* video for linux device struct */
+       struct video_picture vpic;      /* picture settings only used to init saa7113h */
+       struct em28xx_tvnorm *tvnorm;   /* selected tv norm */
+       int ctl_freq;           /* selected frequency */
+       unsigned int ctl_input; /* selected input */
+       unsigned int ctl_ainput;        /* slected audio input */
+       int mute;
+       int volume;
+       /* frame properties */
+       struct em28xx_frame_t frame[EM28XX_NUM_FRAMES]; /* list of frames */
+       int num_frames;         /* number of frames currently in use */
+       unsigned int frame_count;       /* total number of transfered frames */
+       struct em28xx_frame_t *frame_current;   /* the frame that is being filled */
+       int width;              /* current frame width */
+       int height;             /* current frame height */
+       int frame_size;         /* current frame size */
+       int field_size;         /* current field size */
+       int bytesperline;
+       int hscale;             /* horizontal scale factor (see datasheet) */
+       int vscale;             /* vertical scale factor (see datasheet) */
+       int interlaced;         /* 1=interlace fileds, 0=just top fileds */
+       int type;
+
+       /* states */
+       enum em28xx_dev_state state;
+       enum em28xx_stream_state stream;
+       enum em28xx_io_method io;
+       /* locks */
+       struct semaphore lock, fileop_lock;
+       spinlock_t queue_lock;
+       struct list_head inqueue, outqueue;
+       wait_queue_head_t open, wait_frame, wait_stream;
+       struct video_device *vbi_dev;
+
+       unsigned char eedata[256];
+
+       /* usb transfer */
+       struct usb_device *udev;        /* the usb device */
+       int alt;                /* alternate */
+       int max_pkt_size;       /* max packet size of isoc transaction */
+       int num_alt;            /* Number of alternative settings */
+       unsigned int *alt_max_pkt_size; /* array of wMaxPacketSize */
+       struct urb *urb[EM28XX_NUM_BUFS];       /* urb for isoc transfers */
+       char *transfer_buffer[EM28XX_NUM_BUFS]; /* transfer buffers for isoc transfer */
+       /* helper funcs that call usb_control_msg */
+       int (*em28xx_write_regs) (struct em28xx * dev, u16 reg, char *buf,
+                                 int len);
+       int (*em28xx_read_reg) (struct em28xx * dev, u16 reg);
+       int (*em28xx_read_reg_req_len) (struct em28xx * dev, u8 req, u16 reg,
+                                       char *buf, int len);
+       int (*em28xx_write_regs_req) (struct em28xx * dev, u8 req, u16 reg,
+                                     char *buf, int len);
+       int (*em28xx_read_reg_req) (struct em28xx * dev, u8 req, u16 reg);
+};
+
+/* Provided by em28xx-i2c.c */
+
+void em28xx_i2c_call_clients(struct em28xx *dev, unsigned int cmd, void *arg);
+int em28xx_i2c_register(struct em28xx *dev);
+int em28xx_i2c_unregister(struct em28xx *dev);
+
+/* Provided by em28xx-input.c */
+
+void em28xx_set_ir(struct em28xx * dev,struct IR_i2c *ir);
+
+/* Provided by em28xx-core.c */
+
+void em28xx_print_ioctl(char *name, unsigned int cmd);
+
+u32 em28xx_request_buffers(struct em28xx *dev, u32 count);
+void em28xx_queue_unusedframes(struct em28xx *dev);
+void em28xx_release_buffers(struct em28xx *dev);
+
+int em28xx_read_reg_req_len(struct em28xx *dev, u8 req, u16 reg,
+                           char *buf, int len);
+int em28xx_read_reg_req(struct em28xx *dev, u8 req, u16 reg);
+int em28xx_read_reg(struct em28xx *dev, u16 reg);
+int em28xx_write_regs_req(struct em28xx *dev, u8 req, u16 reg, char *buf,
+                         int len);
+int em28xx_write_regs(struct em28xx *dev, u16 reg, char *buf, int len);
+int em28xx_write_reg_bits(struct em28xx *dev, u16 reg, u8 val,
+                         u8 bitmask);
+int em28xx_write_ac97(struct em28xx *dev, u8 reg, u8 * val);
+int em28xx_audio_analog_set(struct em28xx *dev);
+int em28xx_colorlevels_set_default(struct em28xx *dev);
+int em28xx_capture_start(struct em28xx *dev, int start);
+int em28xx_outfmt_set_yuv422(struct em28xx *dev);
+int em28xx_accumulator_set(struct em28xx *dev, u8 xmin, u8 xmax, u8 ymin,
+                          u8 ymax);
+int em28xx_capture_area_set(struct em28xx *dev, u8 hstart, u8 vstart,
+                           u16 width, u16 height);
+int em28xx_scaler_set(struct em28xx *dev, u16 h, u16 v);
+int em28xx_resolution_set(struct em28xx *dev);
+void em28xx_isocIrq(struct urb *urb, struct pt_regs *regs);
+int em28xx_init_isoc(struct em28xx *dev);
+void em28xx_uninit_isoc(struct em28xx *dev);
+int em28xx_set_alternate(struct em28xx *dev);
+
+/* Provided by em28xx-cards.c */
+extern int em2800_variant_detect(struct usb_device* udev,int model);
+extern void em28xx_card_setup(struct em28xx *dev);
+extern struct em28xx_board em28xx_boards[];
+extern struct usb_device_id em28xx_id_table[];
+extern const unsigned int em28xx_bcount;
+
+/* em28xx registers */
+#define CHIPID_REG     0x0a
+#define USBSUSP_REG    0x0c    /* */
+
+#define AUDIOSRC_REG   0x0e
+#define XCLK_REG       0x0f
+
+#define VINMODE_REG    0x10
+#define VINCTRL_REG    0x11
+#define VINENABLE_REG  0x12    /* */
+
+#define GAMMA_REG      0x14
+#define RGAIN_REG      0x15
+#define GGAIN_REG      0x16
+#define BGAIN_REG      0x17
+#define ROFFSET_REG    0x18
+#define GOFFSET_REG    0x19
+#define BOFFSET_REG    0x1a
+
+#define OFLOW_REG      0x1b
+#define HSTART_REG     0x1c
+#define VSTART_REG     0x1d
+#define CWIDTH_REG     0x1e
+#define CHEIGHT_REG    0x1f
+
+#define YGAIN_REG      0x20
+#define YOFFSET_REG    0x21
+#define UVGAIN_REG     0x22
+#define UOFFSET_REG    0x23
+#define VOFFSET_REG    0x24
+#define SHARPNESS_REG  0x25
+
+#define COMPR_REG      0x26
+#define OUTFMT_REG     0x27
+
+#define XMIN_REG       0x28
+#define XMAX_REG       0x29
+#define YMIN_REG       0x2a
+#define YMAX_REG       0x2b
+
+#define HSCALELOW_REG  0x30
+#define HSCALEHIGH_REG 0x31
+#define VSCALELOW_REG  0x32
+#define VSCALEHIGH_REG 0x33
+
+#define AC97LSB_REG    0x40
+#define AC97MSB_REG    0x41
+#define AC97ADDR_REG   0x42
+#define AC97BUSY_REG   0x43
+
+/* em202 registers */
+#define MASTER_AC97    0x02
+#define VIDEO_AC97     0x14
+
+/* register settings */
+#define EM28XX_AUDIO_SRC_TUNER 0xc0
+#define EM28XX_AUDIO_SRC_LINE  0x80
+
+/* printk macros */
+
+#define em28xx_err(fmt, arg...) do {\
+       printk(KERN_ERR fmt , ##arg); } while (0)
+
+#define em28xx_errdev(fmt, arg...) do {\
+       printk(KERN_ERR "%s: "fmt,\
+                       dev->name , ##arg); } while (0)
+
+#define em28xx_info(fmt, arg...) do {\
+       printk(KERN_INFO "%s: "fmt,\
+                       dev->name , ##arg); } while (0)
+#define em28xx_warn(fmt, arg...) do {\
+       printk(KERN_WARNING "%s: "fmt,\
+                       dev->name , ##arg); } while (0)
+
+inline static int em28xx_audio_source(struct em28xx *dev, int input)
+{
+       return em28xx_write_reg_bits(dev, AUDIOSRC_REG, input, 0xc0);
+}
+
+inline static int em28xx_audio_usb_mute(struct em28xx *dev, int mute)
+{
+       return em28xx_write_reg_bits(dev, XCLK_REG, mute ? 0x00 : 0x80, 0x80);
+}
+
+inline static int em28xx_audio_analog_setup(struct em28xx *dev)
+{
+       /* unmute video mixer with default volume level */
+       return em28xx_write_ac97(dev, VIDEO_AC97, "\x08\x08");
+}
+
+inline static int em28xx_compression_disable(struct em28xx *dev)
+{
+       /* side effect of disabling scaler and mixer */
+       return em28xx_write_regs(dev, COMPR_REG, "\x00", 1);
+}
+
+inline static int em28xx_contrast_get(struct em28xx *dev)
+{
+       return em28xx_read_reg(dev, YGAIN_REG) & 0x1f;
+}
+
+inline static int em28xx_brightness_get(struct em28xx *dev)
+{
+       return em28xx_read_reg(dev, YOFFSET_REG);
+}
+
+inline static int em28xx_saturation_get(struct em28xx *dev)
+{
+       return em28xx_read_reg(dev, UVGAIN_REG) & 0x1f;
+}
+
+inline static int em28xx_u_balance_get(struct em28xx *dev)
+{
+       return em28xx_read_reg(dev, UOFFSET_REG);
+}
+
+inline static int em28xx_v_balance_get(struct em28xx *dev)
+{
+       return em28xx_read_reg(dev, VOFFSET_REG);
+}
+
+inline static int em28xx_gamma_get(struct em28xx *dev)
+{
+       return em28xx_read_reg(dev, GAMMA_REG) & 0x3f;
+}
+
+inline static int em28xx_contrast_set(struct em28xx *dev, s32 val)
+{
+       u8 tmp = (u8) val;
+       return em28xx_write_regs(dev, YGAIN_REG, &tmp, 1);
+}
+
+inline static int em28xx_brightness_set(struct em28xx *dev, s32 val)
+{
+       u8 tmp = (u8) val;
+       return em28xx_write_regs(dev, YOFFSET_REG, &tmp, 1);
+}
+
+inline static int em28xx_saturation_set(struct em28xx *dev, s32 val)
+{
+       u8 tmp = (u8) val;
+       return em28xx_write_regs(dev, UVGAIN_REG, &tmp, 1);
+}
+
+inline static int em28xx_u_balance_set(struct em28xx *dev, s32 val)
+{
+       u8 tmp = (u8) val;
+       return em28xx_write_regs(dev, UOFFSET_REG, &tmp, 1);
+}
+
+inline static int em28xx_v_balance_set(struct em28xx *dev, s32 val)
+{
+       u8 tmp = (u8) val;
+       return em28xx_write_regs(dev, VOFFSET_REG, &tmp, 1);
+}
+
+inline static int em28xx_gamma_set(struct em28xx *dev, s32 val)
+{
+       u8 tmp = (u8) val;
+       return em28xx_write_regs(dev, GAMMA_REG, &tmp, 1);
+}
+
+/*FIXME: maxw should be dependent of alt mode */
+inline static unsigned int norm_maxw(struct em28xx *dev)
+{
+       switch(dev->model){
+               case (EM2820_BOARD_MSI_VOX_USB_2): return(640);
+               default: return(720);
+       }
+}
+
+inline static unsigned int norm_maxh(struct em28xx *dev)
+{
+       switch(dev->model){
+               case (EM2820_BOARD_MSI_VOX_USB_2): return(480);
+               default: return (dev->tvnorm->id & V4L2_STD_625_50) ? 576 : 480;
+       }
+}
+
+#endif
index 234151e48edc40ea73c383cc8796dd3e48ba0c98..ed81934ef3cdde8b9fa9b5ab27bf613c73817f12 100644 (file)
@@ -156,6 +156,71 @@ static IR_KEYTAB_TYPE ir_codes_apac_viewcomp[IR_KEYTAB_SIZE] = {
 
 /* ---------------------------------------------------------------------- */
 
+/* Ricardo Cerqueira <v4l@cerqueira.org> */
+/* Weird matching, since the remote has "uncommon" keys */
+
+static IR_KEYTAB_TYPE ir_codes_conceptronic[IR_KEYTAB_SIZE] = {
+
+       [ 30 ] = KEY_POWER,       // power
+       [ 7  ] = KEY_MEDIA,       // source
+       [ 28 ] = KEY_SEARCH,      // scan
+
+/* FIXME: duplicate keycodes?
+ *
+ * These four keys seem to share the same GPIO as CH+, CH-, <<< and >>>
+ * The GPIO values are
+ * 6397fb for both "Scan <" and "CH -",
+ * 639ffb for "Scan >" and "CH+",
+ * 6384fb for "Tune <" and "<<<",
+ * 638cfb for "Tune >" and ">>>", regardless of the mask.
+ *
+ *     [ 23 ] = KEY_BACK,        // fm scan <<
+ *     [ 31 ] = KEY_FORWARD,     // fm scan >>
+ *
+ *     [ 4  ] = KEY_LEFT,        // fm tuning <
+ *     [ 12 ] = KEY_RIGHT,       // fm tuning >
+ *
+ * For now, these four keys are disabled. Pressing them will generate
+ * the CH+/CH-/<<</>>> events
+ */
+
+       [ 3  ] = KEY_TUNER,       // TV/FM
+
+       [ 0  ] = KEY_RECORD,
+       [ 8  ] = KEY_STOP,
+       [ 17 ] = KEY_PLAY,
+
+       [ 26 ] = KEY_PLAYPAUSE,   // freeze
+       [ 25 ] = KEY_ZOOM,        // zoom
+       [ 15 ] = KEY_TEXT,        // min
+
+       [ 1  ] = KEY_KP1,
+       [ 11 ] = KEY_KP2,
+       [ 27 ] = KEY_KP3,
+       [ 5  ] = KEY_KP4,
+       [ 9  ] = KEY_KP5,
+       [ 21 ] = KEY_KP6,
+       [ 6  ] = KEY_KP7,
+       [ 10 ] = KEY_KP8,
+       [ 18 ] = KEY_KP9,
+       [ 2  ] = KEY_KP0,
+       [ 16 ] = KEY_LAST,        // +100
+       [ 19 ] = KEY_LIST,        // recall
+
+       [ 31 ] = KEY_CHANNELUP,   // chn down
+       [ 23 ] = KEY_CHANNELDOWN, // chn up
+       [ 22 ] = KEY_VOLUMEUP,    // vol down
+       [ 20 ] = KEY_VOLUMEDOWN,  // vol up
+
+       [ 4  ] = KEY_KPMINUS,     // <<<
+       [ 14 ] = KEY_SETUP,       // function
+       [ 12 ] = KEY_KPPLUS,      // >>>
+
+       [ 13 ] = KEY_GOTO,        // mts
+       [ 29 ] = KEY_REFRESH,     // reset
+       [ 24 ] = KEY_MUTE         // mute/unmute
+};
+
 struct IR {
        struct bttv_sub_device  *sub;
        struct input_dev        *input;
@@ -282,53 +347,59 @@ static int ir_probe(struct device *dev)
 
        /* detect & configure */
        switch (sub->core->type) {
-       case BTTV_AVERMEDIA:
-       case BTTV_AVPHONE98:
-       case BTTV_AVERMEDIA98:
+       case BTTV_BOARD_AVERMEDIA:
+       case BTTV_BOARD_AVPHONE98:
+       case BTTV_BOARD_AVERMEDIA98:
                ir_codes         = ir_codes_avermedia;
                ir->mask_keycode = 0xf88000;
                ir->mask_keydown = 0x010000;
                ir->polling      = 50; // ms
                break;
 
-       case BTTV_AVDVBT_761:
-       case BTTV_AVDVBT_771:
+       case BTTV_BOARD_AVDVBT_761:
+       case BTTV_BOARD_AVDVBT_771:
                ir_codes         = ir_codes_avermedia_dvbt;
                ir->mask_keycode = 0x0f00c0;
                ir->mask_keydown = 0x000020;
                ir->polling      = 50; // ms
                break;
 
-       case BTTV_PXELVWPLTVPAK:
+       case BTTV_BOARD_PXELVWPLTVPAK:
                ir_codes         = ir_codes_pixelview;
                ir->mask_keycode = 0x003e00;
                ir->mask_keyup   = 0x010000;
                ir->polling      = 50; // ms
-                break;
-       case BTTV_PV_BT878P_9B:
-       case BTTV_PV_BT878P_PLUS:
+               break;
+       case BTTV_BOARD_PV_BT878P_9B:
+       case BTTV_BOARD_PV_BT878P_PLUS:
                ir_codes         = ir_codes_pixelview;
                ir->mask_keycode = 0x001f00;
                ir->mask_keyup   = 0x008000;
                ir->polling      = 50; // ms
-                break;
+               break;
 
-       case BTTV_WINFAST2000:
+       case BTTV_BOARD_WINFAST2000:
                ir_codes         = ir_codes_winfast;
                ir->mask_keycode = 0x1f8;
                break;
-       case BTTV_MAGICTVIEW061:
-       case BTTV_MAGICTVIEW063:
+       case BTTV_BOARD_MAGICTVIEW061:
+       case BTTV_BOARD_MAGICTVIEW063:
                ir_codes         = ir_codes_winfast;
                ir->mask_keycode = 0x0008e000;
                ir->mask_keydown = 0x00200000;
                break;
-       case BTTV_APAC_VIEWCOMP:
+       case BTTV_BOARD_APAC_VIEWCOMP:
                ir_codes         = ir_codes_apac_viewcomp;
                ir->mask_keycode = 0x001f00;
                ir->mask_keyup   = 0x008000;
                ir->polling      = 50; // ms
                break;
+       case BTTV_BOARD_CONCEPTRONIC_CTVFMI2:
+               ir_codes         = ir_codes_conceptronic;
+               ir->mask_keycode = 0x001F00;
+               ir->mask_keyup   = 0x006000;
+               ir->polling      = 50; // ms
+               break;
        }
        if (NULL == ir_codes) {
                kfree(ir);
index 9703d3d351f94309b651b49a53fa9ab2cdee1e6b..0085567a1421d3fb5c06b145b0c302ec96a05895 100644 (file)
@@ -8,6 +8,8 @@
  *      Christoph Bartelmus <lirc@bartelmus.de>
  * modified for KNC ONE TV Station/Anubis Typhoon TView Tuner by
  *      Ulrich Mueller <ulrich.mueller42@web.de>
+ * modified for em2820 based USB TV tuners by
+ *      Markus Rechberger <mrechberger@gmail.com>
  *
  *  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
 #include <linux/slab.h>
 #include <linux/i2c.h>
 #include <linux/workqueue.h>
-
 #include <asm/semaphore.h>
-
 #include <media/ir-common.h>
+#include <media/ir-kbd-i2c.h>
 
 /* Mark Phalan <phalanm@o2.ie> */
 static IR_KEYTAB_TYPE ir_codes_pv951[IR_KEYTAB_SIZE] = {
@@ -81,57 +82,6 @@ static IR_KEYTAB_TYPE ir_codes_pv951[IR_KEYTAB_SIZE] = {
        [ 28 ] = KEY_MEDIA,             /* PC/TV */
 };
 
-static IR_KEYTAB_TYPE ir_codes_purpletv[IR_KEYTAB_SIZE] = {
-       [ 0x3  ] = KEY_POWER,
-       [ 0x6f ] = KEY_MUTE,
-       [ 0x10 ] = KEY_BACKSPACE,       /* Recall */
-
-       [ 0x11 ] = KEY_KP0,
-       [ 0x4  ] = KEY_KP1,
-       [ 0x5  ] = KEY_KP2,
-       [ 0x6  ] = KEY_KP3,
-       [ 0x8  ] = KEY_KP4,
-       [ 0x9  ] = KEY_KP5,
-       [ 0xa  ] = KEY_KP6,
-       [ 0xc  ] = KEY_KP7,
-       [ 0xd  ] = KEY_KP8,
-       [ 0xe  ] = KEY_KP9,
-       [ 0x12 ] = KEY_KPDOT,           /* 100+ */
-
-       [ 0x7  ] = KEY_VOLUMEUP,
-       [ 0xb  ] = KEY_VOLUMEDOWN,
-       [ 0x1a ] = KEY_KPPLUS,
-       [ 0x18 ] = KEY_KPMINUS,
-       [ 0x15 ] = KEY_UP,
-       [ 0x1d ] = KEY_DOWN,
-       [ 0xf  ] = KEY_CHANNELUP,
-       [ 0x13 ] = KEY_CHANNELDOWN,
-       [ 0x48 ] = KEY_ZOOM,
-
-       [ 0x1b ] = KEY_VIDEO,           /* Video source */
-       [ 0x49 ] = KEY_LANGUAGE,        /* MTS Select */
-       [ 0x19 ] = KEY_SEARCH,          /* Auto Scan */
-
-       [ 0x4b ] = KEY_RECORD,
-       [ 0x46 ] = KEY_PLAY,
-       [ 0x45 ] = KEY_PAUSE,           /* Pause */
-       [ 0x44 ] = KEY_STOP,
-       [ 0x40 ] = KEY_FORWARD,         /* Forward ? */
-       [ 0x42 ] = KEY_REWIND,          /* Backward ? */
-
-};
-
-struct IR {
-       struct i2c_client      c;
-       struct input_dev       *input;
-       struct ir_input_state  ir;
-
-       struct work_struct     work;
-       struct timer_list      timer;
-       char                   phys[32];
-       int                    (*get_key)(struct IR*, u32*, u32*);
-};
-
 /* ----------------------------------------------------------------------- */
 /* insmod parameters                                                       */
 
@@ -144,7 +94,7 @@ module_param(debug, int, 0644);    /* debug level (0,1,2) */
 
 /* ----------------------------------------------------------------------- */
 
-static int get_key_haup(struct IR *ir, u32 *ir_key, u32 *ir_raw)
+static int get_key_haup(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw)
 {
        unsigned char buf[3];
        int start, toggle, dev, code;
@@ -171,9 +121,9 @@ static int get_key_haup(struct IR *ir, u32 *ir_key, u32 *ir_raw)
        return 1;
 }
 
-static int get_key_pixelview(struct IR *ir, u32 *ir_key, u32 *ir_raw)
+static int get_key_pixelview(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw)
 {
-        unsigned char b;
+       unsigned char b;
 
        /* poll IR chip */
        if (1 != i2c_master_recv(&ir->c,&b,1)) {
@@ -185,9 +135,9 @@ static int get_key_pixelview(struct IR *ir, u32 *ir_key, u32 *ir_raw)
        return 1;
 }
 
-static int get_key_pv951(struct IR *ir, u32 *ir_key, u32 *ir_raw)
+static int get_key_pv951(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw)
 {
-        unsigned char b;
+       unsigned char b;
 
        /* poll IR chip */
        if (1 != i2c_master_recv(&ir->c,&b,1)) {
@@ -205,7 +155,7 @@ static int get_key_pv951(struct IR *ir, u32 *ir_key, u32 *ir_raw)
        return 1;
 }
 
-static int get_key_knc1(struct IR *ir, u32 *ir_key, u32 *ir_raw)
+static int get_key_knc1(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw)
 {
        unsigned char b;
 
@@ -216,15 +166,15 @@ static int get_key_knc1(struct IR *ir, u32 *ir_key, u32 *ir_raw)
        }
 
        /* it seems that 0xFE indicates that a button is still hold
-          down, while 0xFF indicates that no button is hold
-          down. 0xFE sequences are sometimes interrupted by 0xFF */
+          down, while 0xff indicates that no button is hold
+          down. 0xfe sequences are sometimes interrupted by 0xFF */
 
        dprintk(2,"key %02x\n", b);
 
-       if (b == 0xFF)
+       if (b == 0xff)
                return 0;
 
-       if (b == 0xFE)
+       if (b == 0xfe)
                /* keep old data */
                return 1;
 
@@ -233,31 +183,9 @@ static int get_key_knc1(struct IR *ir, u32 *ir_key, u32 *ir_raw)
        return 1;
 }
 
-static int get_key_purpletv(struct IR *ir, u32 *ir_key, u32 *ir_raw)
-{
-        unsigned char b;
-
-       /* poll IR chip */
-       if (1 != i2c_master_recv(&ir->c,&b,1)) {
-               dprintk(1,"read error\n");
-               return -EIO;
-       }
-
-       /* no button press */
-       if (b==0)
-               return 0;
-
-       /* repeating */
-       if (b & 0x80)
-               return 1;
-
-       *ir_key = b;
-       *ir_raw = b;
-       return 1;
-}
 /* ----------------------------------------------------------------------- */
 
-static void ir_key_poll(struct IR *ir)
+static void ir_key_poll(struct IR_i2c *ir)
 {
        static u32 ir_key, ir_raw;
        int rc;
@@ -278,13 +206,13 @@ static void ir_key_poll(struct IR *ir)
 
 static void ir_timer(unsigned long data)
 {
-       struct IR *ir = (struct IR*)data;
+       struct IR_i2c *ir = (struct IR_i2c*)data;
        schedule_work(&ir->work);
 }
 
 static void ir_work(void *data)
 {
-       struct IR *ir = data;
+       struct IR_i2c *ir = data;
        ir_key_poll(ir);
        mod_timer(&ir->timer, jiffies+HZ/10);
 }
@@ -297,17 +225,17 @@ static int ir_detach(struct i2c_client *client);
 static int ir_probe(struct i2c_adapter *adap);
 
 static struct i2c_driver driver = {
-        .name           = "ir remote kbd driver",
-        .id             = I2C_DRIVERID_EXP3, /* FIXME */
-        .flags          = I2C_DF_NOTIFY,
-        .attach_adapter = ir_probe,
-        .detach_client  = ir_detach,
+       .name           = "ir remote kbd driver",
+       .id             = I2C_DRIVERID_EXP3, /* FIXME */
+       .flags          = I2C_DF_NOTIFY,
+       .attach_adapter = ir_probe,
+       .detach_client  = ir_detach,
 };
 
 static struct i2c_client client_template =
 {
-        .name = "unset",
-        .driver = &driver
+       .name = "unset",
+       .driver = &driver
 };
 
 static int ir_attach(struct i2c_adapter *adap, int addr,
@@ -316,10 +244,10 @@ static int ir_attach(struct i2c_adapter *adap, int addr,
        IR_KEYTAB_TYPE *ir_codes = NULL;
        char *name;
        int ir_type;
-        struct IR *ir;
+        struct IR_i2c *ir;
        struct input_dev *input_dev;
 
-       ir = kzalloc(sizeof(struct IR), GFP_KERNEL);
+       ir = kzalloc(sizeof(struct IR_i2c), GFP_KERNEL);
        input_dev = input_allocate_device();
        if (!ir || !input_dev) {
                kfree(ir);
@@ -361,10 +289,10 @@ static int ir_attach(struct i2c_adapter *adap, int addr,
                ir_codes    = ir_codes_empty;
                break;
        case 0x7a:
-               name        = "Purple TV";
-               ir->get_key = get_key_purpletv;
+       case 0x47:
+               /* Handled by saa7134-input */
+               name        = "SAA713x remote";
                ir_type     = IR_TYPE_OTHER;
-               ir_codes    = ir_codes_purpletv;
                break;
        default:
                /* shouldn't happen */
@@ -373,9 +301,24 @@ static int ir_attach(struct i2c_adapter *adap, int addr,
                return -1;
        }
 
-       /* register i2c device */
-       i2c_attach_client(&ir->c);
+       /* Sets name */
        snprintf(ir->c.name, sizeof(ir->c.name), "i2c IR (%s)", name);
+       ir->ir_codes=ir_codes;
+
+       /* register i2c device
+        * At device register, IR codes may be changed to be
+        * board dependent.
+       */
+       i2c_attach_client(&ir->c);
+
+       /* If IR not supported or disabled, unregisters driver */
+       if (ir->get_key == NULL) {
+               i2c_detach_client(&ir->c);
+               kfree(ir);
+               return -1;
+       }
+
+       /* Phys addr can only be set after attaching (for ir->c.dev.bus_id) */
        snprintf(ir->phys, sizeof(ir->phys), "%s/%s/ir0",
                 ir->c.adapter->dev.bus_id,
                 ir->c.dev.bus_id);
@@ -386,6 +329,7 @@ static int ir_attach(struct i2c_adapter *adap, int addr,
        input_dev->name         = ir->c.name;
        input_dev->phys         = ir->phys;
 
+       /* register event device */
        input_register_device(ir->input);
 
        /* start polling via eventd */
@@ -400,7 +344,7 @@ static int ir_attach(struct i2c_adapter *adap, int addr,
 
 static int ir_detach(struct i2c_client *client)
 {
-        struct IR *ir = i2c_get_clientdata(client);
+       struct IR_i2c *ir = i2c_get_clientdata(client);
 
        /* kill outstanding polls */
        del_timer(&ir->timer);
@@ -428,9 +372,12 @@ static int ir_probe(struct i2c_adapter *adap)
        */
 
        static const int probe_bttv[] = { 0x1a, 0x18, 0x4b, 0x64, 0x30, -1};
-       static const int probe_saa7134[] = { 0x7a, -1 };
+       static const int probe_saa7134[] = { 0x7a, 0x47, -1 };
+       static const int probe_em28XX[] = { 0x30, 0x47, -1 };
        const int *probe = NULL;
-       struct i2c_client c; char buf; int i,rc;
+       struct i2c_client c;
+       unsigned char buf;
+       int i,rc;
 
        switch (adap->id) {
        case I2C_HW_B_BT848:
@@ -439,6 +386,9 @@ static int ir_probe(struct i2c_adapter *adap)
        case I2C_HW_SAA7134:
                probe = probe_saa7134;
                break;
+       case I2C_HW_B_EM28XX:
+               probe = probe_em28XX;
+               break;
        }
        if (NULL == probe)
                return 0;
@@ -447,11 +397,11 @@ static int ir_probe(struct i2c_adapter *adap)
        c.adapter = adap;
        for (i = 0; -1 != probe[i]; i++) {
                c.addr = probe[i];
-               rc = i2c_master_recv(&c,&buf,1);
+               rc = i2c_master_recv(&c,&buf,0);
                dprintk(1,"probe 0x%02x @ %s: %s\n",
                        probe[i], adap->name,
-                       (1 == rc) ? "yes" : "no");
-               if (1 == rc) {
+                       (0 == rc) ? "yes" : "no");
+               if (0 == rc) {
                        ir_attach(adap,probe[i],0,0);
                        break;
                }
index e75e7948fd9d84b32ea51642beadf9c676f6b113..a23fb0338986c553aa70ababe45d0bbc5051825f 100644 (file)
 #include <asm/pgtable.h>
 
 #include <media/audiochip.h>
-#include <media/id.h>
 #include "msp3400.h"
 
+#define msp3400_dbg(fmt, arg...) \
+       do { \
+               if (debug) \
+                       printk(KERN_INFO "%s debug %d-%04x: " fmt, client->driver->name, \
+                              i2c_adapter_id(client->adapter), client->addr , ## arg); \
+       } while (0)
+
+/* Medium volume debug. */
+#define msp3400_dbg_mediumvol(fmt, arg...) \
+       do { \
+               if (debug >= 2) \
+                       printk(KERN_INFO "%s debug %d-%04x: " fmt, client->driver->name, \
+                               i2c_adapter_id(client->adapter), client->addr , ## arg); \
+       } while (0)
+
+/* High volume debug. Use with care. */
+#define msp3400_dbg_highvol(fmt, arg...) \
+       do { \
+               if (debug >= 16) \
+                       printk(KERN_INFO "%s debug %d-%04x: " fmt, client->driver->name, \
+                               i2c_adapter_id(client->adapter), client->addr , ## arg); \
+       } while (0)
+
+#define msp3400_err(fmt, arg...) do { \
+       printk(KERN_ERR "%s %d-%04x: " fmt, client->driver->name, \
+               i2c_adapter_id(client->adapter), client->addr , ## arg); } while (0)
+#define msp3400_warn(fmt, arg...) do { \
+       printk(KERN_WARNING "%s %d-%04x: " fmt, client->driver->name, \
+               i2c_adapter_id(client->adapter), client->addr , ## arg); } while (0)
+#define msp3400_info(fmt, arg...) do { \
+       printk(KERN_INFO "%s %d-%04x: " fmt, client->driver->name, \
+               i2c_adapter_id(client->adapter), client->addr , ## arg); } while (0)
+
 #define OPMODE_AUTO    -1
 #define OPMODE_MANUAL   0
 #define OPMODE_SIMPLE   1   /* use short programming (>= msp3410 only) */
@@ -73,15 +105,26 @@ static int dolby    = 0;
 
 static int stereo_threshold = 0x190; /* a2 threshold for stereo/bilingual
                                        (msp34xxg only) 0x00a0-0x03c0 */
+#define DFP_COUNT 0x41
+static const int bl_dfp[] = {
+       0x00, 0x01, 0x02, 0x03, 0x06, 0x08, 0x09, 0x0a,
+       0x0b, 0x0d, 0x0e, 0x10
+};
+
+#define IS_MSP34XX_G(msp) ((msp)->opmode==2)
 
 struct msp3400c {
        int rev1,rev2;
 
        int opmode;
+       int nicam;
        int mode;
        int norm;
+       int stereo;
        int nicam_on;
        int acb;
+       int in_scart;
+       int i2s_mode;
        int main, second;       /* sound carrier */
        int input;
        int source;             /* see msp34xxg_set_source */
@@ -91,9 +134,12 @@ struct msp3400c {
        int rxsubchans;
 
        int muted;
-       int volume, balance;
+       int left, right;        /* volume */
        int bass, treble;
 
+       /* shadow register set */
+       int dfp_regs[DFP_COUNT];
+
        /* thread */
        struct task_struct   *kthread;
        wait_queue_head_t    wq;
@@ -101,6 +147,8 @@ struct msp3400c {
        int                  watch_stereo:1;
 };
 
+#define MIN(a,b) (((a)>(b))?(b):(a))
+#define MAX(a,b) (((a)>(b))?(a):(b))
 #define HAVE_NICAM(msp)   (((msp->rev2>>8) & 0xff) != 00)
 #define HAVE_SIMPLE(msp)  ((msp->rev1      & 0xff) >= 'D'-'@')
 #define HAVE_SIMPLER(msp) ((msp->rev1      & 0xff) >= 'G'-'@')
@@ -110,9 +158,6 @@ struct msp3400c {
 
 /* ---------------------------------------------------------------------- */
 
-#define dprintk      if (debug >= 1) printk
-#define d2printk     if (debug >= 2) printk
-
 /* read-only */
 module_param(opmode,           int, 0444);
 
@@ -132,11 +177,6 @@ MODULE_PARM_DESC(standard, "Specify audio standard: 32 = NTSC, 64 = radio, Defau
 MODULE_PARM_DESC(amsound, "Hardwire AM sound at 6.5Hz (France), FM can autoscan");
 MODULE_PARM_DESC(dolby, "Activates Dolby processsing");
 
-
-MODULE_DESCRIPTION("device driver for msp34xx TV sound processor");
-MODULE_AUTHOR("Gerd Knorr");
-MODULE_LICENSE("Dual BSD/GPL"); /* FreeBSD uses this too */
-
 /* ---------------------------------------------------------------------- */
 
 #define I2C_MSP3400C       0x80
@@ -153,6 +193,10 @@ static unsigned short normal_i2c[] = {
 };
 I2C_CLIENT_INSMOD;
 
+MODULE_DESCRIPTION("device driver for msp34xx TV sound processor");
+MODULE_AUTHOR("Gerd Knorr");
+MODULE_LICENSE("GPL");
+
 /* ----------------------------------------------------------------------- */
 /* functions for talking to the MSP3400C Sound processor                   */
 
@@ -172,68 +216,73 @@ static int msp3400c_reset(struct i2c_client *client)
                { client->addr, I2C_M_RD, 2, read  },
        };
 
+       msp3400_dbg_highvol("msp3400c_reset\n");
        if ( (1 != i2c_transfer(client->adapter,&reset[0],1)) ||
             (1 != i2c_transfer(client->adapter,&reset[1],1)) ||
             (2 != i2c_transfer(client->adapter,test,2)) ) {
-               printk(KERN_ERR "msp3400: chip reset failed\n");
+               msp3400_err("chip reset failed\n");
                return -1;
-        }
+       }
        return 0;
 }
 
-static int
-msp3400c_read(struct i2c_client *client, int dev, int addr)
+static int msp3400c_read(struct i2c_client *client, int dev, int addr)
 {
-       int err;
+       int err,retval;
+
+       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  }
+       };
 
-        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;
+       write[0] = dev+1;
+       write[1] = addr >> 8;
+       write[2] = addr & 0xff;
 
        for (err = 0; err < 3;) {
                if (2 == i2c_transfer(client->adapter,msgs,2))
                        break;
                err++;
-               printk(KERN_WARNING "msp34xx: I/O error #%d (read 0x%02x/0x%02x)\n",
-                      err, dev, addr);
-               msleep(10);
+               msp3400_warn("I/O error #%d (read 0x%02x/0x%02x)\n", err,
+                      dev, addr);
+               current->state = TASK_INTERRUPTIBLE;
+               schedule_timeout(msecs_to_jiffies(10));
        }
        if (3 == err) {
-               printk(KERN_WARNING "msp34xx: giving up, reseting chip. Sound will go off, sorry folks :-|\n");
+               msp3400_warn("giving up, resetting chip. Sound will go off, sorry folks :-|\n");
                msp3400c_reset(client);
                return -1;
        }
-       return read[0] << 8 | read[1];
+       retval = read[0] << 8 | read[1];
+       msp3400_dbg_highvol("msp3400c_read(0x%x, 0x%x): 0x%x\n", dev, addr, retval);
+       return retval;
 }
 
-static int
-msp3400c_write(struct i2c_client *client, int dev, int addr, int val)
+static int msp3400c_write(struct i2c_client *client, int dev, int addr, int val)
 {
        int err;
-        unsigned char buffer[5];
+       unsigned char buffer[5];
 
-        buffer[0] = dev;
-        buffer[1] = addr >> 8;
-        buffer[2] = addr &  0xff;
-        buffer[3] = val  >> 8;
-        buffer[4] = val  &  0xff;
+       buffer[0] = dev;
+       buffer[1] = addr >> 8;
+       buffer[2] = addr &  0xff;
+       buffer[3] = val  >> 8;
+       buffer[4] = val  &  0xff;
 
+       msp3400_dbg_highvol("msp3400c_write(0x%x, 0x%x, 0x%x)\n", dev, addr, val);
        for (err = 0; err < 3;) {
                if (5 == i2c_master_send(client, buffer, 5))
                        break;
                err++;
-               printk(KERN_WARNING "msp34xx: I/O error #%d (write 0x%02x/0x%02x)\n",
-                      err, dev, addr);
-               msleep(10);
+               msp3400_warn("I/O error #%d (write 0x%02x/0x%02x)\n", err,
+                      dev, addr);
+               current->state = TASK_INTERRUPTIBLE;
+               schedule_timeout(msecs_to_jiffies(10));
        }
        if (3 == err) {
-               printk(KERN_WARNING "msp34xx: giving up, reseting chip. Sound will go off, sorry folks :-|\n");
+               msp3400_warn("giving up, reseting chip. Sound will go off, sorry folks :-|\n");
                msp3400c_reset(client);
                return -1;
        }
@@ -266,45 +315,47 @@ static struct MSP_INIT_DATA_DEM {
        int dfp_src;
        int dfp_matrix;
 } msp_init_data[] = {
-       /* AM (for carrier detect / msp3400) */
-       { { 75, 19, 36, 35, 39, 40 }, { 75, 19, 36, 35, 39, 40 },
-         MSP_CARRIER(5.5), MSP_CARRIER(5.5),
-         0x00d0, 0x0500,   0x0020, 0x3000},
-
-       /* AM (for carrier detect / msp3410) */
-       { { -1, -1, -8, 2, 59, 126 }, { -1, -1, -8, 2, 59, 126 },
-         MSP_CARRIER(5.5), MSP_CARRIER(5.5),
-         0x00d0, 0x0100,   0x0020, 0x3000},
-
-       /* FM Radio */
-       { { -8, -8, 4, 6, 78, 107 }, { -8, -8, 4, 6, 78, 107 },
-         MSP_CARRIER(10.7), MSP_CARRIER(10.7),
-         0x00d0, 0x0480, 0x0020, 0x3000 },
-
-       /* Terrestial FM-mono + FM-stereo */
-       { {  3, 18, 27, 48, 66, 72 }, {  3, 18, 27, 48, 66, 72 },
-         MSP_CARRIER(5.5), MSP_CARRIER(5.5),
-         0x00d0, 0x0480,   0x0030, 0x3000},
-
-       /* Sat FM-mono */
-       { {  1,  9, 14, 24, 33, 37 }, {  3, 18, 27, 48, 66, 72 },
-         MSP_CARRIER(6.5), MSP_CARRIER(6.5),
-         0x00c6, 0x0480,   0x0000, 0x3000},
-
-       /* 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/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, 0x7c03},
+       {       /* AM (for carrier detect / msp3400) */
+               {75, 19, 36, 35, 39, 40},
+               {75, 19, 36, 35, 39, 40},
+               MSP_CARRIER(5.5), MSP_CARRIER(5.5),
+               0x00d0, 0x0500, 0x0020, 0x3000
+       },{     /* AM (for carrier detect / msp3410) */
+               {-1, -1, -8, 2, 59, 126},
+               {-1, -1, -8, 2, 59, 126},
+               MSP_CARRIER(5.5), MSP_CARRIER(5.5),
+               0x00d0, 0x0100, 0x0020, 0x3000
+       },{     /* FM Radio */
+               {-8, -8, 4, 6, 78, 107},
+               {-8, -8, 4, 6, 78, 107},
+               MSP_CARRIER(10.7), MSP_CARRIER(10.7),
+               0x00d0, 0x0480, 0x0020, 0x3000
+       },{     /* Terrestial FM-mono + FM-stereo */
+               {3, 18, 27, 48, 66, 72},
+               {3, 18, 27, 48, 66, 72},
+               MSP_CARRIER(5.5), MSP_CARRIER(5.5),
+               0x00d0, 0x0480, 0x0030, 0x3000
+       },{     /* Sat FM-mono */
+               { 1, 9, 14, 24, 33, 37},
+               { 3, 18, 27, 48, 66, 72},
+               MSP_CARRIER(6.5), MSP_CARRIER(6.5),
+               0x00c6, 0x0480, 0x0000, 0x3000
+       },{     /* 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/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, 0x7c03
+       },
 };
 
 struct CARRIER_DETECT {
@@ -338,32 +389,68 @@ static struct CARRIER_DETECT carrier_detect_65[] = {
 
 #define CARRIER_COUNT(x) (sizeof(x)/sizeof(struct CARRIER_DETECT))
 
-/* ----------------------------------------------------------------------- */
+/* ----------------------------------------------------------------------- *
+ * bits  9  8  5 - SCART DSP input Select:
+ *       0  0  0 - SCART 1 to DSP input (reset position)
+ *       0  1  0 - MONO to DSP input
+ *       1  0  0 - SCART 2 to DSP input
+ *       1  1  1 - Mute DSP input
+ *
+ * bits 11 10  6 - SCART 1 Output Select:
+ *       0  0  0 - undefined (reset position)
+ *       0  1  0 - SCART 2 Input to SCART 1 Output (for devices with 2 SCARTS)
+ *       1  0  0 - MONO input to SCART 1 Output
+ *       1  1  0 - SCART 1 DA to SCART 1 Output
+ *       0  0  1 - SCART 2 DA to SCART 1 Output
+ *       0  1  1 - SCART 1 Input to SCART 1 Output
+ *       1  1  1 - Mute SCART 1 Output
+ *
+ * bits 13 12  7 - SCART 2 Output Select (for devices with 2 Output SCART):
+ *       0  0  0 - SCART 1 DA to SCART 2 Output (reset position)
+ *       0  1  0 - SCART 1 Input to SCART 2 Output
+ *       1  0  0 - MONO input to SCART 2 Output
+ *       0  0  1 - SCART 2 DA to SCART 2 Output
+ *       0  1  1 - SCART 2 Input to SCART 2 Output
+ *       1  1  0 - Mute SCART 2 Output
+ *
+ * Bits 4 to 0 should be zero.
+ * ----------------------------------------------------------------------- */
 
 static int scarts[3][9] = {
-  /* MASK    IN1     IN2     IN1_DA  IN2_DA  IN3     IN4     MONO    MUTE   */
-  {  0x0320, 0x0000, 0x0200, -1,     -1,     0x0300, 0x0020, 0x0100, 0x0320 },
-  {  0x0c40, 0x0440, 0x0400, 0x0c00, 0x0040, 0x0000, 0x0840, 0x0800, 0x0c40 },
-  {  0x3080, 0x1000, 0x1080, 0x0000, 0x0080, 0x2080, 0x3080, 0x2000, 0x3000 },
+       /* MASK    IN1     IN2     IN1_DA  IN2_DA  IN3     IN4     MONO    MUTE   */
+       /* SCART DSP Input select */
+       { 0x0320, 0x0000, 0x0200, -1,     -1,     0x0300, 0x0020, 0x0100, 0x0320 },
+       /* SCART1 Output select */
+       { 0x0c40, 0x0440, 0x0400, 0x0c00, 0x0040, 0x0000, 0x0840, 0x0800, 0x0c40 },
+       /* SCART2 Output select */
+       { 0x3080, 0x1000, 0x1080, 0x0000, 0x0080, 0x2080, 0x3080, 0x2000, 0x3000 },
 };
 
 static char *scart_names[] = {
-  "mask", "in1", "in2", "in1 da", "in2 da", "in3", "in4", "mono", "mute"
+       "mask", "in1", "in2", "in1 da", "in2 da", "in3", "in4", "mono", "mute"
 };
 
-static void
-msp3400c_set_scart(struct i2c_client *client, int in, int out)
+static void msp3400c_set_scart(struct i2c_client *client, int in, int out)
 {
        struct msp3400c *msp = i2c_get_clientdata(client);
 
-       if (-1 == scarts[out][in])
-               return;
+       msp->in_scart=in;
+
+       if (in >= 1 && in <= 8 && out >= 0 && out <= 2) {
+               if (-1 == scarts[out][in])
+                       return;
 
-       dprintk(KERN_DEBUG
-               "msp34xx: scart switch: %s => %d\n",scart_names[in],out);
-       msp->acb &= ~scarts[out][SCART_MASK];
-       msp->acb |=  scarts[out][in];
-       msp3400c_write(client,I2C_MSP3400C_DFP, 0x0013, msp->acb);
+               msp->acb &= ~scarts[out][SCART_MASK];
+               msp->acb |=  scarts[out][in];
+       } else
+               msp->acb = 0xf60; /* Mute Input and SCART 1 Output */
+
+       msp3400_dbg("scart switch: %s => %d (ACB=0x%04x)\n",
+                                               scart_names[in], out, msp->acb);
+       msp3400c_write(client,I2C_MSP3400C_DFP, 0x13, msp->acb);
+
+       /* Sets I2S speed 0 = 1.024 Mbps, 1 = 2.048 Mbps */
+       msp3400c_write(client,I2C_MSP3400C_DEM, 0x40, msp->i2s_mode);
 }
 
 /* ------------------------------------------------------------------------ */
@@ -378,33 +465,34 @@ static void msp3400c_setcarrier(struct i2c_client *client, int cdo1, int cdo2)
 }
 
 static void msp3400c_setvolume(struct i2c_client *client,
-                              int muted, int volume, int balance)
-{
-       int val = 0, bal = 0;
+                              int muted, int left, int right)
+ {
+       int vol = 0, val = 0, balance = 0;
 
        if (!muted) {
                /* 0x7f instead if 0x73 here has sound quality issues,
                 * probably due to overmodulation + clipping ... */
-               val = (volume * 0x73 / 65535) << 8;
+               vol = (left > right) ? left : right;
+               val = (vol * 0x73 / 65535) << 8;
        }
-       if (val) {
-               bal = (balance / 256) - 128;
+       if (vol > 0) {
+               balance = ((right - left) * 127) / vol;
        }
-       dprintk(KERN_DEBUG
-               "msp34xx: setvolume: mute=%s %d:%d  v=0x%02x b=0x%02x\n",
-               muted ? "on" : "off", volume, balance, val>>8, bal);
+
+       msp3400_dbg("setvolume: mute=%s %d:%d  v=0x%02x b=0x%02x\n",
+               muted ? "on" : "off", left, right, val >> 8, balance);
        msp3400c_write(client,I2C_MSP3400C_DFP, 0x0000, val); /* loudspeaker */
        msp3400c_write(client,I2C_MSP3400C_DFP, 0x0006, val); /* headphones  */
        msp3400c_write(client,I2C_MSP3400C_DFP, 0x0007,
-                      muted ? 0x01 : (val | 0x01));
-       msp3400c_write(client,I2C_MSP3400C_DFP, 0x0001, bal << 8);
+                                       muted ? 0x1 : (val | 0x1));
+       msp3400c_write(client, I2C_MSP3400C_DFP, 0x0001, balance << 8);
 }
 
 static void msp3400c_setbass(struct i2c_client *client, int bass)
 {
        int val = ((bass-32768) * 0x60 / 65535) << 8;
 
-       dprintk(KERN_DEBUG "msp34xx: setbass: %d 0x%02x\n",bass, val>>8);
+       msp3400_dbg("setbass: %d 0x%02x\n", bass, val >> 8);
        msp3400c_write(client,I2C_MSP3400C_DFP, 0x0002, val); /* loudspeaker */
 }
 
@@ -412,7 +500,7 @@ static void msp3400c_settreble(struct i2c_client *client, int treble)
 {
        int val = ((treble-32768) * 0x60 / 65535) << 8;
 
-       dprintk(KERN_DEBUG "msp34xx: settreble: %d 0x%02x\n",treble, val>>8);
+       msp3400_dbg("settreble: %d 0x%02x\n",treble, val>>8);
        msp3400c_write(client,I2C_MSP3400C_DFP, 0x0003, val); /* loudspeaker */
 }
 
@@ -421,7 +509,7 @@ static void msp3400c_setmode(struct i2c_client *client, int type)
        struct msp3400c *msp = i2c_get_clientdata(client);
        int i;
 
-       dprintk(KERN_DEBUG "msp3400: setmode: %d\n",type);
+       msp3400_dbg("setmode: %d\n",type);
        msp->mode       = type;
        msp->audmode    = V4L2_TUNER_MODE_MONO;
        msp->rxsubchans = V4L2_TUNER_SUB_MONO;
@@ -474,7 +562,8 @@ static void msp3400c_setmode(struct i2c_client *client, int type)
        }
 }
 
-static int best_audio_mode(int rxsubchans)
+/* given a bitmask of VIDEO_SOUND_XXX returns the "best" in the bitmask */
+static int best_video_sound(int rxsubchans)
 {
        if (rxsubchans & V4L2_TUNER_SUB_STEREO)
                return V4L2_TUNER_MODE_STEREO;
@@ -486,31 +575,31 @@ static int best_audio_mode(int rxsubchans)
 }
 
 /* turn on/off nicam + stereo */
-static void msp3400c_set_audmode(struct i2c_client *client, int audmode)
+static void msp3400c_setstereo(struct i2c_client *client, int mode)
 {
-       static char *strmode[16] = {
-#if __GNUC__ >= 3
-               [ 0 ... 15 ]               = "invalid",
-#endif
-               [ V4L2_TUNER_MODE_MONO   ] = "mono",
-               [ V4L2_TUNER_MODE_STEREO ] = "stereo",
-               [ V4L2_TUNER_MODE_LANG1  ] = "lang1",
-               [ V4L2_TUNER_MODE_LANG2  ] = "lang2",
+       static char *strmode[] = { "0", "mono", "stereo", "3",
+               "lang1", "5", "6", "7", "lang2"
        };
        struct msp3400c *msp = i2c_get_clientdata(client);
-       int nicam=0; /* channel source: FM/AM or nicam */
-       int src=0;
+       int nicam = 0;          /* channel source: FM/AM or nicam */
+       int src = 0;
 
-       BUG_ON(msp->opmode == OPMODE_SIMPLER);
-       msp->audmode = audmode;
+       if (IS_MSP34XX_G(msp)) {
+               /* this method would break everything, let's make sure
+                * it's never called
+                */
+               msp3400_dbg
+                   ("DEBUG WARNING setstereo called with mode=%d instead of set_source (ignored)\n",
+                    mode);
+               return;
+       }
 
        /* switch demodulator */
        switch (msp->mode) {
        case MSP_MODE_FM_TERRA:
-               dprintk(KERN_DEBUG "msp3400: FM setstereo: %s\n",
-                       strmode[audmode]);
+               msp3400_dbg("FM setstereo: %s\n", strmode[mode]);
                msp3400c_setcarrier(client,msp->second,msp->main);
-               switch (audmode) {
+               switch (mode) {
                case V4L2_TUNER_MODE_STEREO:
                        msp3400c_write(client,I2C_MSP3400C_DFP, 0x000e, 0x3001);
                        break;
@@ -522,9 +611,8 @@ static void msp3400c_set_audmode(struct i2c_client *client, int audmode)
                }
                break;
        case MSP_MODE_FM_SAT:
-               dprintk(KERN_DEBUG "msp3400: SAT setstereo: %s\n",
-                       strmode[audmode]);
-               switch (audmode) {
+               msp3400_dbg("SAT setstereo: %s\n", strmode[mode]);
+               switch (mode) {
                case V4L2_TUNER_MODE_MONO:
                        msp3400c_setcarrier(client, MSP_CARRIER(6.5), MSP_CARRIER(6.5));
                        break;
@@ -542,39 +630,35 @@ static void msp3400c_set_audmode(struct i2c_client *client, int audmode)
        case MSP_MODE_FM_NICAM1:
        case MSP_MODE_FM_NICAM2:
        case MSP_MODE_AM_NICAM:
-               dprintk(KERN_DEBUG "msp3400: NICAM setstereo: %s\n",
-                       strmode[audmode]);
+               msp3400_dbg("NICAM setstereo: %s\n",strmode[mode]);
                msp3400c_setcarrier(client,msp->second,msp->main);
                if (msp->nicam_on)
                        nicam=0x0100;
                break;
        case MSP_MODE_BTSC:
-               dprintk(KERN_DEBUG "msp3400: BTSC setstereo: %s\n",
-                       strmode[audmode]);
+               msp3400_dbg("BTSC setstereo: %s\n",strmode[mode]);
                nicam=0x0300;
                break;
        case MSP_MODE_EXTERN:
-               dprintk(KERN_DEBUG "msp3400: extern setstereo: %s\n",
-                       strmode[audmode]);
+               msp3400_dbg("extern setstereo: %s\n",strmode[mode]);
                nicam = 0x0200;
                break;
        case MSP_MODE_FM_RADIO:
-               dprintk(KERN_DEBUG "msp3400: FM-Radio setstereo: %s\n",
-                       strmode[audmode]);
+               msp3400_dbg("FM-Radio setstereo: %s\n",strmode[mode]);
                break;
        default:
-               dprintk(KERN_DEBUG "msp3400: mono setstereo\n");
+               msp3400_dbg("mono setstereo\n");
                return;
        }
 
        /* switch audio */
-       switch (audmode) {
+       switch (best_video_sound(mode)) {
        case V4L2_TUNER_MODE_STEREO:
                src = 0x0020 | nicam;
                break;
        case V4L2_TUNER_MODE_MONO:
                if (msp->mode == MSP_MODE_AM_NICAM) {
-                       dprintk("msp3400: switching to AM mono\n");
+                       msp3400_dbg("switching to AM mono\n");
                        /* AM mono decoding is handled by tuner, not MSP chip */
                        /* SCART switching control register */
                        msp3400c_set_scart(client,SCART_MONO,0);
@@ -588,8 +672,7 @@ static void msp3400c_set_audmode(struct i2c_client *client, int audmode)
                src = 0x0010 | nicam;
                break;
        }
-       dprintk(KERN_DEBUG
-               "msp3400: setstereo final source/matrix = 0x%x\n", src);
+       msp3400_dbg("setstereo final source/matrix = 0x%x\n", src);
 
        if (dolby) {
                msp3400c_write(client,I2C_MSP3400C_DFP, 0x0008,0x0520);
@@ -605,29 +688,55 @@ static void msp3400c_set_audmode(struct i2c_client *client, int audmode)
 }
 
 static void
-msp3400c_print_mode(struct msp3400c *msp)
+msp3400c_print_mode(struct i2c_client *client)
 {
+       struct msp3400c *msp = i2c_get_clientdata(client);
+
        if (msp->main == msp->second) {
-               printk(KERN_DEBUG "msp3400: mono sound carrier: %d.%03d MHz\n",
+               msp3400_dbg("mono sound carrier: %d.%03d MHz\n",
                       msp->main/910000,(msp->main/910)%1000);
        } else {
-               printk(KERN_DEBUG "msp3400: main sound carrier: %d.%03d MHz\n",
+               msp3400_dbg("main sound carrier: %d.%03d MHz\n",
                       msp->main/910000,(msp->main/910)%1000);
        }
-       if (msp->mode == MSP_MODE_FM_NICAM1 ||
-           msp->mode == MSP_MODE_FM_NICAM2)
-               printk(KERN_DEBUG "msp3400: NICAM/FM carrier   : %d.%03d MHz\n",
+       if (msp->mode == MSP_MODE_FM_NICAM1 || msp->mode == MSP_MODE_FM_NICAM2)
+               msp3400_dbg("NICAM/FM carrier   : %d.%03d MHz\n",
                       msp->second/910000,(msp->second/910)%1000);
        if (msp->mode == MSP_MODE_AM_NICAM)
-               printk(KERN_DEBUG "msp3400: NICAM/AM carrier   : %d.%03d MHz\n",
+               msp3400_dbg("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) {
-               printk(KERN_DEBUG "msp3400: FM-stereo carrier : %d.%03d MHz\n",
+               msp3400_dbg("FM-stereo carrier : %d.%03d MHz\n",
                       msp->second/910000,(msp->second/910)%1000);
        }
 }
 
+#define MSP3400_MAX 4
+static struct i2c_client *msps[MSP3400_MAX];
+static void msp3400c_restore_dfp(struct i2c_client *client)
+{
+       struct msp3400c *msp = i2c_get_clientdata(client);
+       int i;
+
+       for (i = 0; i < DFP_COUNT; i++) {
+               if (-1 == msp->dfp_regs[i])
+                       continue;
+               msp3400c_write(client, I2C_MSP3400C_DFP, i, msp->dfp_regs[i]);
+       }
+}
+
+/* if the dfp_regs is set, set what's in there. Otherwise, set the default value */
+static int msp3400c_write_dfp_with_default(struct i2c_client *client,
+                                       int addr, int default_value)
+{
+       struct msp3400c *msp = i2c_get_clientdata(client);
+       int value = default_value;
+       if (addr < DFP_COUNT && -1 != msp->dfp_regs[addr])
+               value = msp->dfp_regs[addr];
+       return msp3400c_write(client, I2C_MSP3400C_DFP, addr, value);
+}
+
 /* ----------------------------------------------------------------------- */
 
 struct REGISTER_DUMP {
@@ -635,8 +744,15 @@ struct REGISTER_DUMP {
        char *name;
 };
 
-static int
-autodetect_stereo(struct i2c_client *client)
+struct REGISTER_DUMP d1[] = {
+       {0x007e, "autodetect"},
+       {0x0023, "C_AD_BITS "},
+       {0x0038, "ADD_BITS  "},
+       {0x003e, "CIB_BITS  "},
+       {0x0057, "ERROR_RATE"},
+};
+
+static int autodetect_stereo(struct i2c_client *client)
 {
        struct msp3400c *msp = i2c_get_clientdata(client);
        int val;
@@ -649,8 +765,7 @@ autodetect_stereo(struct i2c_client *client)
                val = msp3400c_read(client, I2C_MSP3400C_DFP, 0x18);
                if (val > 32767)
                        val -= 65536;
-               dprintk(KERN_DEBUG
-                       "msp34xx: stereo detect register: %d\n",val);
+               msp3400_dbg("stereo detect register: %d\n",val);
                if (val > 4096) {
                        rxsubchans = V4L2_TUNER_SUB_STEREO | V4L2_TUNER_SUB_MONO;
                } else if (val < -4096) {
@@ -664,8 +779,7 @@ autodetect_stereo(struct i2c_client *client)
        case MSP_MODE_FM_NICAM2:
        case MSP_MODE_AM_NICAM:
                val = msp3400c_read(client, I2C_MSP3400C_DEM, 0x23);
-               dprintk(KERN_DEBUG
-                       "msp34xx: nicam sync=%d, mode=%d\n",
+               msp3400_dbg("nicam sync=%d, mode=%d\n",
                        val & 1, (val & 0x1e) >> 1);
 
                if (val & 1) {
@@ -698,8 +812,7 @@ autodetect_stereo(struct i2c_client *client)
                break;
        case MSP_MODE_BTSC:
                val = msp3400c_read(client, I2C_MSP3400C_DEM, 0x200);
-               dprintk(KERN_DEBUG
-                       "msp3410: status=0x%x (pri=%s, sec=%s, %s%s%s)\n",
+               msp3400_dbg("status=0x%x (pri=%s, sec=%s, %s%s%s)\n",
                        val,
                        (val & 0x0002) ? "no"     : "yes",
                        (val & 0x0004) ? "no"     : "yes",
@@ -713,13 +826,13 @@ autodetect_stereo(struct i2c_client *client)
        }
        if (rxsubchans != msp->rxsubchans) {
                update = 1;
-               dprintk(KERN_DEBUG "msp34xx: watch: rxsubchans %d => %d\n",
+               msp3400_dbg("watch: rxsubchans %d => %d\n",
                        msp->rxsubchans,rxsubchans);
                msp->rxsubchans = rxsubchans;
        }
        if (newnicam != msp->nicam_on) {
                update = 1;
-               dprintk(KERN_DEBUG "msp34xx: watch: nicam %d => %d\n",
+               msp3400_dbg("watch: nicam %d => %d\n",
                        msp->nicam_on,newnicam);
                msp->nicam_on = newnicam;
        }
@@ -756,8 +869,15 @@ static void watch_stereo(struct i2c_client *client)
 {
        struct msp3400c *msp = i2c_get_clientdata(client);
 
-       if (autodetect_stereo(client))
-               msp3400c_set_audmode(client,best_audio_mode(msp->rxsubchans));
+       if (autodetect_stereo(client)) {
+               if (msp->stereo & V4L2_TUNER_MODE_STEREO)
+                       msp3400c_setstereo(client, V4L2_TUNER_MODE_STEREO);
+               else if (msp->stereo & VIDEO_SOUND_LANG1)
+                       msp3400c_setstereo(client, V4L2_TUNER_MODE_LANG1);
+               else
+                       msp3400c_setstereo(client, V4L2_TUNER_MODE_MONO);
+       }
+
        if (once)
                msp->watch_stereo = 0;
 }
@@ -769,14 +889,14 @@ static int msp3400c_thread(void *data)
        struct CARRIER_DETECT *cd;
        int count, max1,max2,val1,val2, val,this;
 
-       printk("msp3400: kthread started\n");
+       msp3400_info("msp3400 daemon started\n");
        for (;;) {
-               d2printk("msp3400: thread: sleep\n");
+               msp3400_dbg_mediumvol("msp3400 thread: sleep\n");
                msp34xx_sleep(msp,-1);
-               d2printk("msp3400: thread: wakeup\n");
+               msp3400_dbg_mediumvol("msp3400 thread: wakeup\n");
 
        restart:
-               dprintk("msp3410: thread: restart scan\n");
+               msp3400_dbg("thread: restart scan\n");
                msp->restart = 0;
                if (kthread_should_stop())
                        break;
@@ -784,9 +904,8 @@ static int msp3400c_thread(void *data)
                if (VIDEO_MODE_RADIO == msp->norm ||
                    MSP_MODE_EXTERN  == msp->mode) {
                        /* no carrier scan, just unmute */
-                       printk("msp3400: thread: no carrier scan\n");
-                       msp3400c_setvolume(client, msp->muted,
-                                          msp->volume, msp->balance);
+                       msp3400_info("thread: no carrier scan\n");
+                       msp3400c_setvolume(client, msp->muted, msp->left, msp->right);
                        continue;
                }
 
@@ -802,13 +921,14 @@ static int msp3400c_thread(void *data)
                        goto restart;
 
                /* carrier detect pass #1 -- main carrier */
-               cd = carrier_detect_main; count = CARRIER_COUNT(carrier_detect_main);
+               cd = carrier_detect_main;
+               count = CARRIER_COUNT(carrier_detect_main);
 
                if (amsound && (msp->norm == VIDEO_MODE_SECAM)) {
                        /* autodetect doesn't work well with AM ... */
                        max1 = 3;
                        count = 0;
-                       dprintk("msp3400: AM sound override\n");
+                       msp3400_dbg("AM sound override\n");
                }
 
                for (this = 0; this < count; this++) {
@@ -820,7 +940,7 @@ static int msp3400c_thread(void *data)
                                val -= 65536;
                        if (val1 < val)
                                val1 = val, max1 = this;
-                       dprintk("msp3400: carrier1 val: %5d / %s\n", val,cd[this].name);
+                       msp3400_dbg("carrier1 val: %5d / %s\n", val,cd[this].name);
                }
 
                /* carrier detect pass #2 -- second (stereo) carrier */
@@ -836,13 +956,16 @@ static int msp3400c_thread(void *data)
                case 0: /* 4.5 */
                case 2: /* 6.0 */
                default:
-                       cd = NULL; count = 0;
+                       cd = NULL;
+                       count = 0;
                        break;
                }
 
                if (amsound && (msp->norm == VIDEO_MODE_SECAM)) {
                        /* autodetect doesn't work well with AM ... */
-                       cd = NULL; count = 0; max2 = 0;
+                       cd = NULL;
+                       count = 0;
+                       max2 = 0;
                }
                for (this = 0; this < count; this++) {
                        msp3400c_setcarrier(client, cd[this].cdo,cd[this].cdo);
@@ -853,7 +976,7 @@ static int msp3400c_thread(void *data)
                                val -= 65536;
                        if (val2 < val)
                                val2 = val, max2 = this;
-                       dprintk("msp3400: carrier2 val: %5d / %s\n", val,cd[this].name);
+                       msp3400_dbg("carrier2 val: %5d / %s\n", val,cd[this].name);
                }
 
                /* programm the msp3400 according to the results */
@@ -865,7 +988,7 @@ static int msp3400c_thread(void *data)
                                msp->second = carrier_detect_55[max2].cdo;
                                msp3400c_setmode(client, MSP_MODE_FM_TERRA);
                                msp->nicam_on = 0;
-                               msp3400c_set_audmode(client, V4L2_TUNER_MODE_MONO);
+                               msp3400c_setstereo(client, V4L2_TUNER_MODE_MONO);
                                msp->watch_stereo = 1;
                        } else if (max2 == 1 && HAVE_NICAM(msp)) {
                                /* B/G NICAM */
@@ -892,7 +1015,7 @@ static int msp3400c_thread(void *data)
                                msp->second = carrier_detect_65[max2].cdo;
                                msp3400c_setmode(client, MSP_MODE_FM_TERRA);
                                msp->nicam_on = 0;
-                               msp3400c_set_audmode(client, V4L2_TUNER_MODE_MONO);
+                               msp3400c_setstereo(client, V4L2_TUNER_MODE_MONO);
                                msp->watch_stereo = 1;
                        } else if (max2 == 0 &&
                                   msp->norm == VIDEO_MODE_SECAM) {
@@ -900,7 +1023,7 @@ static int msp3400c_thread(void *data)
                                msp->second = carrier_detect_65[max2].cdo;
                                msp3400c_setmode(client, MSP_MODE_AM_NICAM);
                                msp->nicam_on = 0;
-                               msp3400c_set_audmode(client, V4L2_TUNER_MODE_MONO);
+                               msp3400c_setstereo(client, V4L2_TUNER_MODE_MONO);
                                msp3400c_setcarrier(client, msp->second, msp->main);
                                /* volume prescale for SCART (AM mono input) */
                                msp3400c_write(client,I2C_MSP3400C_DFP, 0x000d, 0x1900);
@@ -924,15 +1047,16 @@ static int msp3400c_thread(void *data)
                        msp->nicam_on = 0;
                        msp3400c_setcarrier(client, msp->second, msp->main);
                        msp->rxsubchans = V4L2_TUNER_SUB_MONO;
-                       msp3400c_set_audmode(client, V4L2_TUNER_MODE_MONO);
+                       msp3400c_setstereo(client, V4L2_TUNER_MODE_MONO);
                        break;
                }
 
                /* unmute */
-               msp3400c_setvolume(client, msp->muted,
-                                  msp->volume, msp->balance);
+               msp3400c_setvolume(client, msp->muted, msp->left, msp->right);
+               msp3400c_restore_dfp(client);
+
                if (debug)
-                       msp3400c_print_mode(msp);
+                       msp3400c_print_mode(client);
 
                /* monitor tv audio mode */
                while (msp->watch_stereo) {
@@ -941,7 +1065,7 @@ static int msp3400c_thread(void *data)
                        watch_stereo(client);
                }
        }
-       dprintk(KERN_DEBUG "msp3400: thread: exit\n");
+       msp3400_dbg("thread: exit\n");
        return 0;
 }
 
@@ -985,10 +1109,12 @@ static inline const char *msp34xx_standard_mode_name(int mode)
        return "unknown";
 }
 
-static int msp34xx_modus(int norm)
+static int msp34xx_modus(struct i2c_client *client, int norm)
 {
        switch (norm) {
        case VIDEO_MODE_PAL:
+               msp3400_dbg("video mode selected to PAL\n");
+
 #if 1
                /* experimental: not sure this works with all chip versions */
                return 0x7003;
@@ -997,12 +1123,16 @@ static int msp34xx_modus(int norm)
                return 0x1003;
 #endif
        case VIDEO_MODE_NTSC:  /* BTSC */
+               msp3400_dbg("video mode selected to NTSC\n");
                return 0x2003;
        case VIDEO_MODE_SECAM:
+               msp3400_dbg("video mode selected to SECAM\n");
                return 0x0003;
        case VIDEO_MODE_RADIO:
+               msp3400_dbg("video mode selected to Radio\n");
                return 0x0003;
        case VIDEO_MODE_AUTO:
+               msp3400_dbg("video mode selected to Auto\n");
                return 0x2003;
        default:
                return 0x0003;
@@ -1031,23 +1161,22 @@ static int msp3410d_thread(void *data)
        struct msp3400c *msp = i2c_get_clientdata(client);
        int mode,val,i,std;
 
-       printk("msp3410: daemon started\n");
+       msp3400_info("msp3410 daemon started\n");
        for (;;) {
-               d2printk(KERN_DEBUG "msp3410: thread: sleep\n");
+               msp3400_dbg_mediumvol("msp3410 thread: sleep\n");
                msp34xx_sleep(msp,-1);
-               d2printk(KERN_DEBUG "msp3410: thread: wakeup\n");
+               msp3400_dbg_mediumvol("msp3410 thread: wakeup\n");
 
        restart:
-               dprintk("msp3410: thread: restart scan\n");
+               msp3400_dbg("thread: restart scan\n");
                msp->restart = 0;
                if (kthread_should_stop())
                        break;
 
                if (msp->mode == MSP_MODE_EXTERN) {
                        /* no carrier scan needed, just unmute */
-                       dprintk(KERN_DEBUG "msp3410: thread: no carrier scan\n");
-                       msp3400c_setvolume(client, msp->muted,
-                                          msp->volume, msp->balance);
+                       msp3400_dbg("thread: no carrier scan\n");
+               msp3400c_setvolume(client, msp->muted, msp->left, msp->right);
                        continue;
                }
 
@@ -1059,14 +1188,14 @@ static int msp3410d_thread(void *data)
                        goto restart;
 
                /* start autodetect */
-               mode = msp34xx_modus(msp->norm);
+               mode = msp34xx_modus(client, msp->norm);
                std  = msp34xx_standard(msp->norm);
                msp3400c_write(client, I2C_MSP3400C_DEM, 0x30, mode);
                msp3400c_write(client, I2C_MSP3400C_DEM, 0x20, std);
                msp->watch_stereo = 0;
 
                if (debug)
-                       printk(KERN_DEBUG "msp3410: setting mode: %s (0x%04x)\n",
+                       msp3400_dbg("setting mode: %s (0x%04x)\n",
                               msp34xx_standard_mode_name(std) ,std);
 
                if (std != 1) {
@@ -1082,13 +1211,13 @@ static int msp3410d_thread(void *data)
                                val = msp3400c_read(client, I2C_MSP3400C_DEM, 0x7e);
                                if (val < 0x07ff)
                                        break;
-                               dprintk(KERN_DEBUG "msp3410: detection still in progress\n");
+                               msp3400_dbg("detection still in progress\n");
                        }
                }
                for (i = 0; modelist[i].name != NULL; i++)
                        if (modelist[i].retval == val)
                                break;
-               dprintk(KERN_DEBUG "msp3410: current mode: %s (0x%04x)\n",
+               msp3400_dbg("current mode: %s (0x%04x)\n",
                        modelist[i].name ? modelist[i].name : "unknown",
                        val);
                msp->main   = modelist[i].main;
@@ -1096,7 +1225,7 @@ static int msp3410d_thread(void *data)
 
                if (amsound && (msp->norm == VIDEO_MODE_SECAM) && (val != 0x0009)) {
                        /* autodetection has failed, let backup */
-                       dprintk(KERN_DEBUG "msp3410: autodetection failed,"
+                       msp3400_dbg("autodetection failed,"
                                " switching to backup mode: %s (0x%04x)\n",
                                modelist[8].name ? modelist[8].name : "unknown",val);
                        val = 0x0009;
@@ -1120,13 +1249,13 @@ static int msp3410d_thread(void *data)
                        msp->rxsubchans = V4L2_TUNER_SUB_STEREO;
                        msp->nicam_on = 1;
                        msp->watch_stereo = 1;
-                       msp3400c_set_audmode(client,V4L2_TUNER_MODE_STEREO);
+                       msp3400c_setstereo(client,V4L2_TUNER_MODE_STEREO);
                        break;
                case 0x0009:
                        msp->mode = MSP_MODE_AM_NICAM;
                        msp->rxsubchans = V4L2_TUNER_SUB_MONO;
                        msp->nicam_on = 1;
-                       msp3400c_set_audmode(client,V4L2_TUNER_MODE_MONO);
+                       msp3400c_setstereo(client,V4L2_TUNER_MODE_MONO);
                        msp->watch_stereo = 1;
                        break;
                case 0x0020: /* BTSC */
@@ -1135,7 +1264,7 @@ static int msp3410d_thread(void *data)
                        msp->rxsubchans = V4L2_TUNER_SUB_STEREO;
                        msp->nicam_on = 0;
                        msp->watch_stereo = 1;
-                       msp3400c_set_audmode(client,V4L2_TUNER_MODE_STEREO);
+                       msp3400c_setstereo(client,V4L2_TUNER_MODE_STEREO);
                        break;
                case 0x0040: /* FM radio */
                        msp->mode   = MSP_MODE_FM_RADIO;
@@ -1169,9 +1298,10 @@ static int msp3410d_thread(void *data)
                /* unmute, restore misc registers */
                msp3400c_setbass(client, msp->bass);
                msp3400c_settreble(client, msp->treble);
-               msp3400c_setvolume(client, msp->muted,
-                                   msp->volume, msp->balance);
-               msp3400c_write(client, I2C_MSP3400C_DFP, 0x0013, msp->acb);
+               msp3400c_setvolume(client, msp->muted, msp->left, msp->right);
+               msp3400c_write(client, I2C_MSP3400C_DFP, 0x13, msp->acb);
+               msp3400c_write(client,I2C_MSP3400C_DEM, 0x40, msp->i2s_mode);
+               msp3400c_restore_dfp(client);
 
                /* monitor tv audio mode */
                while (msp->watch_stereo) {
@@ -1180,7 +1310,7 @@ static int msp3410d_thread(void *data)
                        watch_stereo(client);
                }
        }
-       dprintk(KERN_DEBUG "msp3410: thread: exit\n");
+       msp3400_dbg("thread: exit\n");
        return 0;
 }
 
@@ -1195,7 +1325,7 @@ static void msp34xxg_set_source(struct i2c_client *client, int source);
 /* (re-)initialize the msp34xxg, according to the current norm in msp->norm
  * return 0 if it worked, -1 if it failed
  */
-static int msp34xxg_init(struct i2c_client *client)
+static int msp34xxg_reset(struct i2c_client *client)
 {
        struct msp3400c *msp = i2c_get_clientdata(client);
        int modus,std;
@@ -1210,8 +1340,10 @@ static int msp34xxg_init(struct i2c_client *client)
                           0x0f20 /* mute DSP input, mute SCART 1 */))
                return -1;
 
+       msp3400c_write(client,I2C_MSP3400C_DEM, 0x40, msp->i2s_mode);
+
        /* step-by-step initialisation, as described in the manual */
-       modus = msp34xx_modus(msp->norm);
+       modus = msp34xx_modus(client, msp->norm);
        std   = msp34xx_standard(msp->norm);
        modus &= ~0x03; /* STATUS_CHANGE=0 */
        modus |= 0x01;  /* AUTOMATIC_SOUND_DETECTION=1 */
@@ -1222,7 +1354,7 @@ static int msp34xxg_init(struct i2c_client *client)
                return -1;
        if (msp3400c_write(client,
                           I2C_MSP3400C_DEM,
-                          0x20/*stanard*/,
+                          0x20/*standard*/,
                           std))
                return -1;
 
@@ -1230,21 +1362,18 @@ static int msp34xxg_init(struct i2c_client *client)
           standard/audio autodetection right now */
        msp34xxg_set_source(client, msp->source);
 
-       if (msp3400c_write(client, I2C_MSP3400C_DFP,
-                          0x0e, /* AM/FM Prescale */
-                          0x3000 /* default: [15:8] 75khz deviation */))
+       if (msp3400c_write_dfp_with_default(client, 0x0e,       /* AM/FM Prescale */
+                                           0x3000
+                                           /* default: [15:8] 75khz deviation */
+           ))
                return -1;
 
-       if (msp3400c_write(client, I2C_MSP3400C_DFP,
-                          0x10, /* NICAM Prescale */
-                          0x5a00 /* default: 9db gain (as recommended) */))
+       if (msp3400c_write_dfp_with_default(client, 0x10,       /* NICAM Prescale */
+                                           0x5a00
+                                           /* default: 9db gain (as recommended) */
+           ))
                return -1;
 
-       if (msp3400c_write(client,
-                          I2C_MSP3400C_DEM,
-                          0x20, /* STANDARD SELECT  */
-                          standard /* default: 0x01 for automatic standard select*/))
-               return -1;
        return 0;
 }
 
@@ -1254,27 +1383,27 @@ static int msp34xxg_thread(void *data)
        struct msp3400c *msp = i2c_get_clientdata(client);
        int val, std, i;
 
-       printk("msp34xxg: daemon started\n");
+       msp3400_info("msp34xxg daemon started\n");
        msp->source = 1; /* default */
        for (;;) {
-               d2printk(KERN_DEBUG "msp34xxg: thread: sleep\n");
+               msp3400_dbg_mediumvol("msp34xxg thread: sleep\n");
                msp34xx_sleep(msp,-1);
-               d2printk(KERN_DEBUG "msp34xxg: thread: wakeup\n");
+               msp3400_dbg_mediumvol("msp34xxg thread: wakeup\n");
 
        restart:
-               dprintk("msp34xxg: thread: restart scan\n");
+               msp3400_dbg("thread: restart scan\n");
                msp->restart = 0;
                if (kthread_should_stop())
                        break;
 
                /* setup the chip*/
-               msp34xxg_init(client);
+               msp34xxg_reset(client);
                std = standard;
                if (std != 0x01)
                        goto unmute;
 
                /* watch autodetect */
-               dprintk("msp34xxg: triggered autodetect, waiting for result\n");
+               msp3400_dbg("triggered autodetect, waiting for result\n");
                for (i = 0; i < 10; i++) {
                        if (msp34xx_sleep(msp,100))
                                goto restart;
@@ -1285,23 +1414,23 @@ static int msp34xxg_thread(void *data)
                                std = val;
                                break;
                        }
-                       dprintk("msp34xxg: detection still in progress\n");
+                       msp3400_dbg("detection still in progress\n");
                }
                if (0x01 == std) {
-                       dprintk("msp34xxg: detection still in progress after 10 tries. giving up.\n");
+                       msp3400_dbg("detection still in progress after 10 tries. giving up.\n");
                        continue;
                }
 
        unmute:
-               dprintk("msp34xxg: current mode: %s (0x%04x)\n",
+               msp3400_dbg("current mode: %s (0x%04x)\n",
                        msp34xx_standard_mode_name(std), std);
 
                /* unmute: dispatch sound to scart output, set scart volume */
-               dprintk("msp34xxg: unmute\n");
+               msp3400_dbg("unmute\n");
 
                msp3400c_setbass(client, msp->bass);
                msp3400c_settreble(client, msp->treble);
-               msp3400c_setvolume(client, msp->muted, msp->volume, msp->balance);
+               msp3400c_setvolume(client, msp->muted, msp->left, msp->right);
 
                /* restore ACB */
                if (msp3400c_write(client,
@@ -1309,8 +1438,10 @@ static int msp34xxg_thread(void *data)
                                   0x13, /* ACB */
                                   msp->acb))
                        return -1;
+
+               msp3400c_write(client,I2C_MSP3400C_DEM, 0x40, msp->i2s_mode);
        }
-       dprintk(KERN_DEBUG "msp34xxg: thread: exit\n");
+       msp3400_dbg("thread: exit\n");
        return 0;
 }
 
@@ -1329,7 +1460,7 @@ static void msp34xxg_set_source(struct i2c_client *client, int source)
         * for MONO (source==0) downmixing set bit[7:0] to 0x30
         */
        int value = (source&0x07)<<8|(source==0 ? 0x30:0x20);
-       dprintk("msp34xxg: set source to %d (0x%x)\n", source, value);
+       msp3400_dbg("set source to %d (0x%x)\n", source, value);
        msp3400c_write(client,
                       I2C_MSP3400C_DFP,
                       0x08, /* Loudspeaker Output */
@@ -1380,7 +1511,7 @@ static void msp34xxg_detect_stereo(struct i2c_client *client)
                 * this is a problem, I'll handle SAP just like lang1/lang2.
                 */
        }
-       dprintk("msp34xxg: status=0x%x, stereo=%d, bilingual=%d -> rxsubchans=%d\n",
+       msp3400_dbg("status=0x%x, stereo=%d, bilingual=%d -> rxsubchans=%d\n",
                status, is_stereo, is_bilingual, msp->rxsubchans);
 }
 
@@ -1427,7 +1558,7 @@ static void msp_wake_thread(struct i2c_client *client);
 
 static struct i2c_driver driver = {
        .owner          = THIS_MODULE,
-       .name           = "i2c msp3400 driver",
+       .name           = "msp3400",
         .id             = I2C_DRIVERID_MSP3400,
         .flags          = I2C_DF_NOTIFY,
         .attach_adapter = msp_probe,
@@ -1449,57 +1580,64 @@ static struct i2c_client client_template =
 static int msp_attach(struct i2c_adapter *adap, int addr, int kind)
 {
        struct msp3400c *msp;
-        struct i2c_client *c;
+       struct i2c_client *client = &client_template;
        int (*thread_func)(void *data) = NULL;
+       int i;
 
-        client_template.adapter = adap;
-        client_template.addr = addr;
+       client_template.adapter = adap;
+       client_template.addr = addr;
 
-        if (-1 == msp3400c_reset(&client_template)) {
-                dprintk("msp34xx: no chip found\n");
-                return -1;
-        }
+       if (-1 == msp3400c_reset(&client_template)) {
+               msp3400_dbg("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 == (client = kmalloc(sizeof(struct i2c_client),GFP_KERNEL)))
+               return -ENOMEM;
+       memcpy(client,&client_template,sizeof(struct i2c_client));
        if (NULL == (msp = kmalloc(sizeof(struct msp3400c),GFP_KERNEL))) {
-               kfree(c);
+               kfree(client);
                return -ENOMEM;
        }
 
        memset(msp,0,sizeof(struct msp3400c));
-       msp->volume  = 58880;  /* 0db gain */
-       msp->balance = 32768;
-       msp->bass    = 32768;
-       msp->treble  = 32768;
-       msp->input   = -1;
-       msp->muted   = 1;
-
-       i2c_set_clientdata(c, msp);
+       msp->norm = VIDEO_MODE_NTSC;
+       msp->left = 58880;      /* 0db gain */
+       msp->right = 58880;     /* 0db gain */
+       msp->bass = 32768;
+       msp->treble = 32768;
+       msp->input = -1;
+       msp->muted = 0;
+       msp->i2s_mode = 0;
+       for (i = 0; i < DFP_COUNT; i++)
+               msp->dfp_regs[i] = -1;
+
+       i2c_set_clientdata(client, msp);
        init_waitqueue_head(&msp->wq);
 
-       if (-1 == msp3400c_reset(c)) {
+       if (-1 == msp3400c_reset(client)) {
                kfree(msp);
-               kfree(c);
-               dprintk("msp34xx: no chip found\n");
+               kfree(client);
+               msp3400_dbg("no chip found\n");
                return -1;
        }
 
-       msp->rev1 = msp3400c_read(c, I2C_MSP3400C_DFP, 0x1e);
+       msp->rev1 = msp3400c_read(client, I2C_MSP3400C_DFP, 0x1e);
        if (-1 != msp->rev1)
-               msp->rev2 = msp3400c_read(c, I2C_MSP3400C_DFP, 0x1f);
+               msp->rev2 = msp3400c_read(client, I2C_MSP3400C_DFP, 0x1f);
        if ((-1 == msp->rev1) || (0 == msp->rev1 && 0 == msp->rev2)) {
                kfree(msp);
-               kfree(c);
-               dprintk("msp34xx: error while reading chip version\n");
+               kfree(client);
+               msp3400_dbg("error while reading chip version\n");
                return -1;
        }
+       msp3400_dbg("rev1=0x%04x, rev2=0x%04x\n", msp->rev1, msp->rev2);
 
-       msp3400c_setvolume(c, msp->muted, msp->volume, msp->balance);
+       msp3400c_setvolume(client, msp->muted, msp->left, msp->right);
 
-       snprintf(c->name, sizeof(c->name), "MSP34%02d%c-%c%d",
-                (msp->rev2>>8)&0xff, (msp->rev1&0xff)+'@',
+       snprintf(client->name, sizeof(client->name), "MSP%c4%02d%c-%c%d",
+                ((msp->rev1>>4)&0x0f) + '3',
+                (msp->rev2>>8)&0xff, (msp->rev1&0x0f)+'@',
                 ((msp->rev1>>8)&0xff)+'@', msp->rev2&0x1f);
 
        msp->opmode = opmode;
@@ -1513,7 +1651,7 @@ static int msp_attach(struct i2c_adapter *adap, int addr, int kind)
        }
 
        /* hello world :-) */
-       printk(KERN_INFO "msp34xx: init: chip=%s", c->name);
+       msp3400_info("chip=%s", client->name);
        if (HAVE_NICAM(msp))
                printk(" +nicam");
        if (HAVE_SIMPLE(msp))
@@ -1542,29 +1680,49 @@ static int msp_attach(struct i2c_adapter *adap, int addr, int kind)
 
        /* startup control thread if needed */
        if (thread_func) {
-               msp->kthread = kthread_run(thread_func, c, "msp34xx");
+               msp->kthread = kthread_run(thread_func, client, "msp34xx");
+
                if (NULL == msp->kthread)
-                       printk(KERN_WARNING "msp34xx: kernel_thread() failed\n");
-               msp_wake_thread(c);
+                       msp3400_warn("kernel_thread() failed\n");
+               msp_wake_thread(client);
        }
 
        /* done */
-        i2c_attach_client(c);
+       i2c_attach_client(client);
+
+       /* update our own array */
+       for (i = 0; i < MSP3400_MAX; i++) {
+               if (NULL == msps[i]) {
+                       msps[i] = client;
+                       break;
+               }
+       }
+
        return 0;
 }
 
 static int msp_detach(struct i2c_client *client)
 {
        struct msp3400c *msp  = i2c_get_clientdata(client);
+       int i;
 
        /* shutdown control thread */
-       if (msp->kthread >= 0) {
+       if (msp->kthread) {
                msp->restart = 1;
                kthread_stop(msp->kthread);
        }
-       msp3400c_reset(client);
+       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);
        return 0;
@@ -1640,7 +1798,7 @@ static void msp_any_set_audmode(struct i2c_client *client, int audmode)
        case OPMODE_MANUAL:
        case OPMODE_SIMPLE:
                msp->watch_stereo = 0;
-               msp3400c_set_audmode(client, audmode);
+               msp3400c_setstereo(client, audmode);
                break;
        case OPMODE_SIMPLER:
                msp34xxg_set_audmode(client, audmode);
@@ -1648,16 +1806,18 @@ static void msp_any_set_audmode(struct i2c_client *client, int audmode)
        }
 }
 
+
 static int msp_command(struct i2c_client *client, unsigned int cmd, void *arg)
 {
        struct msp3400c *msp  = i2c_get_clientdata(client);
-        __u16           *sarg = arg;
+       __u16           *sarg = arg;
        int scart = 0;
 
        switch (cmd) {
 
        case AUDC_SET_INPUT:
-               dprintk(KERN_DEBUG "msp34xx: AUDC_SET_INPUT(%d)\n",*sarg);
+               msp3400_dbg("AUDC_SET_INPUT(%d)\n",*sarg);
+
                if (*sarg == msp->input)
                        break;
                msp->input = *sarg;
@@ -1691,15 +1851,15 @@ static int msp_command(struct i2c_client *client, unsigned int cmd, void *arg)
                        msp3400c_set_scart(client,scart,0);
                        msp3400c_write(client,I2C_MSP3400C_DFP,0x000d,0x1900);
                        if (msp->opmode != OPMODE_SIMPLER)
-                               msp3400c_set_audmode(client, msp->audmode);
+                               msp3400c_setstereo(client, msp->audmode);
                }
                msp_wake_thread(client);
                break;
 
        case AUDC_SET_RADIO:
-               dprintk(KERN_DEBUG "msp34xx: AUDC_SET_RADIO\n");
+               msp3400_dbg("AUDC_SET_RADIO\n");
                msp->norm = VIDEO_MODE_RADIO;
-               dprintk(KERN_DEBUG "msp34xx: switching to radio mode\n");
+               msp3400_dbg("switching to radio mode\n");
                msp->watch_stereo = 0;
                switch (msp->opmode) {
                case OPMODE_MANUAL:
@@ -1707,8 +1867,7 @@ static int msp_command(struct i2c_client *client, unsigned int cmd, void *arg)
                        msp3400c_setmode(client,MSP_MODE_FM_RADIO);
                        msp3400c_setcarrier(client, MSP_CARRIER(10.7),
                                            MSP_CARRIER(10.7));
-                       msp3400c_setvolume(client, msp->muted,
-                                          msp->volume, msp->balance);
+                       msp3400c_setvolume(client, msp->muted, msp->left, msp->right);
                        break;
                case OPMODE_SIMPLE:
                case OPMODE_SIMPLER:
@@ -1717,6 +1876,30 @@ static int msp_command(struct i2c_client *client, unsigned int cmd, void *arg)
                        break;
                }
                break;
+               /* work-in-progress:  hook to control the DFP registers */
+       case MSP_SET_DFPREG:
+       {
+               struct msp_dfpreg *r = arg;
+               int i;
+
+               if (r->reg < 0 || r->reg >= DFP_COUNT)
+                       return -EINVAL;
+               for (i = 0; i < sizeof(bl_dfp) / sizeof(int); i++)
+                       if (r->reg == bl_dfp[i])
+                               return -EINVAL;
+               msp->dfp_regs[r->reg] = r->value;
+               msp3400c_write(client, I2C_MSP3400C_DFP, r->reg, r->value);
+               return 0;
+       }
+       case MSP_GET_DFPREG:
+       {
+               struct msp_dfpreg *r = arg;
+
+               if (r->reg < 0 || r->reg >= DFP_COUNT)
+                       return -EINVAL;
+               r->value = msp3400c_read(client, I2C_MSP3400C_DFP, r->reg);
+               return 0;
+       }
 
        /* --- v4l ioctls --- */
        /* take care: bttv does userspace copying, we'll get a
@@ -1725,7 +1908,7 @@ static int msp_command(struct i2c_client *client, unsigned int cmd, void *arg)
        {
                struct video_audio *va = arg;
 
-               dprintk(KERN_DEBUG "msp34xx: VIDIOCGAUDIO\n");
+               msp3400_dbg("VIDIOCGAUDIO\n");
                va->flags |= VIDEO_AUDIO_VOLUME |
                        VIDEO_AUDIO_BASS |
                        VIDEO_AUDIO_TREBLE |
@@ -1733,8 +1916,15 @@ static int msp_command(struct i2c_client *client, unsigned int cmd, void *arg)
                if (msp->muted)
                        va->flags |= VIDEO_AUDIO_MUTE;
 
-               va->volume = msp->volume;
-               va->balance = (va->volume) ? msp->balance : 32768;
+               if (msp->muted)
+                       va->flags |= VIDEO_AUDIO_MUTE;
+               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;
+               if (0 == va->volume)
+                       va->balance = 32768;
                va->bass = msp->bass;
                va->treble = msp->treble;
 
@@ -1746,27 +1936,43 @@ static int msp_command(struct i2c_client *client, unsigned int cmd, void *arg)
        {
                struct video_audio *va = arg;
 
-               dprintk(KERN_DEBUG "msp34xx: VIDIOCSAUDIO\n");
+               msp3400_dbg("VIDIOCSAUDIO\n");
                msp->muted = (va->flags & VIDEO_AUDIO_MUTE);
-               msp->volume = va->volume;
-               msp->balance = va->balance;
+               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->muted,
-                                  msp->volume, msp->balance);
-               msp3400c_setbass(client,msp->bass);
-               msp3400c_settreble(client,msp->treble);
+               msp3400_dbg("VIDIOCSAUDIO setting va->volume to %d\n",
+                       va->volume);
+               msp3400_dbg("VIDIOCSAUDIO setting va->balance to %d\n",
+                       va->balance);
+               msp3400_dbg("VIDIOCSAUDIO setting va->flags to %d\n",
+                       va->flags);
+               msp3400_dbg("VIDIOCSAUDIO setting msp->left to %d\n",
+                       msp->left);
+               msp3400_dbg("VIDIOCSAUDIO setting msp->right to %d\n",
+                       msp->right);
+               msp3400_dbg("VIDIOCSAUDIO setting msp->bass to %d\n",
+                       msp->bass);
+               msp3400_dbg("VIDIOCSAUDIO setting msp->treble to %d\n",
+                       msp->treble);
+               msp3400_dbg("VIDIOCSAUDIO setting msp->mode to %d\n",
+                       msp->mode);
+               msp3400c_setvolume(client, msp->muted, msp->left, msp->right);
+               msp3400c_setbass(client, msp->bass);
+               msp3400c_settreble(client, msp->treble);
 
                if (va->mode != 0 && msp->norm != VIDEO_MODE_RADIO)
                        msp_any_set_audmode(client,mode_v4l1_to_v4l2(va->mode));
                break;
        }
+
        case VIDIOCSCHAN:
        {
                struct video_channel *vc = arg;
 
-               dprintk(KERN_DEBUG "msp34xx: VIDIOCSCHAN (norm=%d)\n",vc->norm);
+               msp3400_dbg("VIDIOCSCHAN (norm=%d)\n",vc->norm);
                msp->norm = vc->norm;
                msp_wake_thread(client);
                break;
@@ -1776,12 +1982,135 @@ static int msp_command(struct i2c_client *client, unsigned int cmd, void *arg)
        case VIDIOC_S_FREQUENCY:
        {
                /* new channel -- kick audio carrier scan */
-               dprintk(KERN_DEBUG "msp34xx: VIDIOCSFREQ\n");
+               msp3400_dbg("VIDIOCSFREQ\n");
                msp_wake_thread(client);
                break;
        }
 
+       /* msp34xx specific */
+       case MSP_SET_MATRIX:
+       {
+               struct msp_matrix *mspm = arg;
+
+               msp3400_dbg("MSP_SET_MATRIX\n");
+               msp3400c_set_scart(client, mspm->input, mspm->output);
+               break;
+       }
+
        /* --- v4l2 ioctls --- */
+       case VIDIOC_S_STD:
+       {
+               v4l2_std_id *id = arg;
+
+               /*FIXME: use V4L2 mode flags on msp3400 instead of V4L1*/
+               if (*id & V4L2_STD_PAL) {
+                       msp->norm=VIDEO_MODE_PAL;
+               } else if (*id & V4L2_STD_SECAM) {
+                       msp->norm=VIDEO_MODE_SECAM;
+               } else {
+                       msp->norm=VIDEO_MODE_NTSC;
+               }
+
+               msp_wake_thread(client);
+               return 0;
+       }
+
+       case VIDIOC_ENUMINPUT:
+       {
+               struct v4l2_input *i = arg;
+
+               if (i->index != 0)
+                       return -EINVAL;
+
+               i->type = V4L2_INPUT_TYPE_TUNER;
+               switch (i->index) {
+               case AUDIO_RADIO:
+                       strcpy(i->name,"Radio");
+                       break;
+               case AUDIO_EXTERN_1:
+                       strcpy(i->name,"Extern 1");
+                       break;
+               case AUDIO_EXTERN_2:
+                       strcpy(i->name,"Extern 2");
+                       break;
+               case AUDIO_TUNER:
+                       strcpy(i->name,"Television");
+                       break;
+               default:
+                       return -EINVAL;
+               }
+               return 0;
+       }
+
+       case VIDIOC_G_AUDIO:
+       {
+               struct v4l2_audio *a = arg;
+
+               memset(a,0,sizeof(*a));
+
+               switch (a->index) {
+               case AUDIO_RADIO:
+                       strcpy(a->name,"Radio");
+                       break;
+               case AUDIO_EXTERN_1:
+                       strcpy(a->name,"Extern 1");
+                       break;
+               case AUDIO_EXTERN_2:
+                       strcpy(a->name,"Extern 2");
+                       break;
+               case AUDIO_TUNER:
+                       strcpy(a->name,"Television");
+                       break;
+               default:
+                       return -EINVAL;
+               }
+
+               msp_any_detect_stereo(client);
+               if (msp->audmode == V4L2_TUNER_MODE_STEREO) {
+                       a->capability=V4L2_AUDCAP_STEREO;
+               }
+
+               break;
+       }
+       case VIDIOC_S_AUDIO:
+       {
+               struct v4l2_audio *sarg = arg;
+
+               switch (sarg->index) {
+               case AUDIO_RADIO:
+                       /* Hauppauge uses IN2 for the radio */
+                       msp->mode   = MSP_MODE_FM_RADIO;
+                       scart       = SCART_IN2;
+                       break;
+               case AUDIO_EXTERN_1:
+                       /* IN1 is often used for external input ... */
+                       msp->mode   = MSP_MODE_EXTERN;
+                       scart       = SCART_IN1;
+                       break;
+               case AUDIO_EXTERN_2:
+                       /* ... sometimes it is IN2 through ;) */
+                       msp->mode   = MSP_MODE_EXTERN;
+                       scart       = SCART_IN2;
+                       break;
+               case AUDIO_TUNER:
+                       msp->mode   = -1;
+                       break;
+               }
+               if (scart) {
+                       msp->rxsubchans = V4L2_TUNER_SUB_STEREO;
+                       msp->audmode = V4L2_TUNER_MODE_STEREO;
+                       msp3400c_set_scart(client,scart,0);
+                       msp3400c_write(client,I2C_MSP3400C_DFP,0x000d,0x1900);
+               }
+               if (sarg->capability==V4L2_AUDCAP_STEREO) {
+                       msp->audmode = V4L2_TUNER_MODE_STEREO;
+               } else {
+                       msp->audmode &= ~V4L2_TUNER_MODE_STEREO;
+               }
+               msp_any_set_audmode(client, msp->audmode);
+               msp_wake_thread(client);
+               break;
+       }
        case VIDIOC_G_TUNER:
        {
                struct v4l2_tuner *vt = arg;
@@ -1804,13 +2133,46 @@ static int msp_command(struct i2c_client *client, unsigned int cmd, void *arg)
                break;
        }
 
-       /* msp34xx specific */
-       case MSP_SET_MATRIX:
+       case VIDIOC_G_AUDOUT:
        {
-               struct msp_matrix *mspm = arg;
+               struct v4l2_audioout *a=(struct v4l2_audioout *)arg;
+               int idx=a->index;
+
+               memset(a,0,sizeof(*a));
+
+               switch (idx) {
+               case 0:
+                       strcpy(a->name,"Scart1 Out");
+                       break;
+               case 1:
+                       strcpy(a->name,"Scart2 Out");
+                       break;
+               case 2:
+                       strcpy(a->name,"I2S Out");
+                       break;
+               default:
+                       return -EINVAL;
+               }
+               break;
+
+       }
+       case VIDIOC_S_AUDOUT:
+       {
+               struct v4l2_audioout *a=(struct v4l2_audioout *)arg;
+
+               if (a->index<0||a->index>2)
+                       return -EINVAL;
+
+               if (a->index==2) {
+                       if (a->mode == V4L2_AUDMODE_32BITS)
+                               msp->i2s_mode=1;
+                       else
+                               msp->i2s_mode=0;
+               }
+               msp3400_dbg("Setting audio out on msp34xx to input %i, mode %i\n",
+                                               a->index,msp->i2s_mode);
+               msp3400c_set_scart(client,msp->in_scart,a->index+1);
 
-               dprintk(KERN_DEBUG "msp34xx: MSP_SET_MATRIX\n");
-               msp3400c_set_scart(client, mspm->input, mspm->output);
                break;
        }
 
@@ -1823,19 +2185,19 @@ static int msp_command(struct i2c_client *client, unsigned int cmd, void *arg)
 
 static int msp_suspend(struct device * dev, pm_message_t state)
 {
-       struct i2c_client *c = container_of(dev, struct i2c_client, dev);
+       struct i2c_client *client = container_of(dev, struct i2c_client, dev);
 
-       dprintk("msp34xx: suspend\n");
-       msp3400c_reset(c);
+       msp3400_dbg("msp34xx: suspend\n");
+       msp3400c_reset(client);
        return 0;
 }
 
 static int msp_resume(struct device * dev)
 {
-       struct i2c_client *c = container_of(dev, struct i2c_client, dev);
+       struct i2c_client *client = container_of(dev, struct i2c_client, dev);
 
-       dprintk("msp34xx: resume\n");
-       msp_wake_thread(c);
+       msp3400_dbg("msp34xx: resume\n");
+       msp_wake_thread(client);
        return 0;
 }
 
index 972aa5e0aeef623f7ac8e02e6333949d02395246..2180018f06de95af017850d319441650d1f16acb 100644 (file)
@@ -76,17 +76,17 @@ static int mt2032_compute_freq(struct i2c_client *c,
                               unsigned int xogc) //all in Hz
 {
        struct tuner *t = i2c_get_clientdata(c);
-        unsigned int fref,lo1,lo1n,lo1a,s,sel,lo1freq, desired_lo1,
+       unsigned int fref,lo1,lo1n,lo1a,s,sel,lo1freq, desired_lo1,
                desired_lo2,lo2,lo2n,lo2a,lo2num,lo2freq;
 
-        fref= 5250 *1000; //5.25MHz
+       fref= 5250 *1000; //5.25MHz
        desired_lo1=rfin+if1;
 
        lo1=(2*(desired_lo1/1000)+(fref/1000)) / (2*fref/1000);
-        lo1n=lo1/8;
-        lo1a=lo1-(lo1n*8);
+       lo1n=lo1/8;
+       lo1a=lo1-(lo1n*8);
 
-        s=rfin/1000/1000+1090;
+       s=rfin/1000/1000+1090;
 
        if(optimize_vco) {
                if(s>1890) sel=0;
@@ -96,34 +96,34 @@ static int mt2032_compute_freq(struct i2c_client *c,
                else sel=4; // >1090
        }
        else {
-               if(s>1790) sel=0; // <1958
-               else if(s>1617) sel=1;
-               else if(s>1449) sel=2;
-               else if(s>1291) sel=3;
-               else sel=4; // >1090
+               if(s>1790) sel=0; // <1958
+               else if(s>1617) sel=1;
+               else if(s>1449) sel=2;
+               else if(s>1291) sel=3;
+               else sel=4; // >1090
        }
        *ret_sel=sel;
 
-        lo1freq=(lo1a+8*lo1n)*fref;
+       lo1freq=(lo1a+8*lo1n)*fref;
 
        tuner_dbg("mt2032: rfin=%d lo1=%d lo1n=%d lo1a=%d sel=%d, lo1freq=%d\n",
                  rfin,lo1,lo1n,lo1a,sel,lo1freq);
 
-        desired_lo2=lo1freq-rfin-if2;
-        lo2=(desired_lo2)/fref;
-        lo2n=lo2/8;
-        lo2a=lo2-(lo2n*8);
-        lo2num=((desired_lo2/1000)%(fref/1000))* 3780/(fref/1000); //scale to fit in 32bit arith
-        lo2freq=(lo2a+8*lo2n)*fref + lo2num*(fref/1000)/3780*1000;
+       desired_lo2=lo1freq-rfin-if2;
+       lo2=(desired_lo2)/fref;
+       lo2n=lo2/8;
+       lo2a=lo2-(lo2n*8);
+       lo2num=((desired_lo2/1000)%(fref/1000))* 3780/(fref/1000); //scale to fit in 32bit arith
+       lo2freq=(lo2a+8*lo2n)*fref + lo2num*(fref/1000)/3780*1000;
 
        tuner_dbg("mt2032: rfin=%d lo2=%d lo2n=%d lo2a=%d num=%d lo2freq=%d\n",
                  rfin,lo2,lo2n,lo2a,lo2num,lo2freq);
 
-        if(lo1a<0 || lo1a>7 || lo1n<17 ||lo1n>48 || lo2a<0 ||lo2a >7 ||lo2n<17 || lo2n>30) {
+       if(lo1a<0 || lo1a>7 || lo1n<17 ||lo1n>48 || lo2a<0 ||lo2a >7 ||lo2n<17 || lo2n>30) {
                tuner_info("mt2032: frequency parameters out of range: %d %d %d %d\n",
                           lo1a, lo1n, lo2a,lo2n);
-                return(-1);
-        }
+               return(-1);
+       }
 
        mt2032_spurcheck(c, lo1freq, desired_lo2,  spectrum_from, spectrum_to);
        // should recalculate lo1 (one step up/down)
@@ -135,10 +135,10 @@ static int mt2032_compute_freq(struct i2c_client *c,
        buf[3]=0x0f; //reserved
        buf[4]=0x1f;
        buf[5]=(lo2n-1) | (lo2a<<5);
-       if(rfin >400*1000*1000)
-                buf[6]=0xe4;
-        else
-                buf[6]=0xf4; // set PKEN per rev 1.2
+       if(rfin >400*1000*1000)
+               buf[6]=0xe4;
+       else
+               buf[6]=0xf4; // set PKEN per rev 1.2
        buf[7]=8+xogc;
        buf[8]=0xc3; //reserved
        buf[9]=0x4e; //reserved
@@ -168,7 +168,7 @@ static int mt2032_check_lo_lock(struct i2c_client *c)
                tuner_dbg("mt2032: pll wait 1ms for lock (0x%2x)\n",buf[0]);
                udelay(1000);
        }
-        return lock;
+       return lock;
 }
 
 static int mt2032_optimize_vco(struct i2c_client *c,int sel,int lock)
@@ -202,7 +202,7 @@ static int mt2032_optimize_vco(struct i2c_client *c,int sel,int lock)
 
        buf[0]=0x0f;
        buf[1]=sel;
-        i2c_master_send(c,buf,2);
+       i2c_master_send(c,buf,2);
        lock=mt2032_check_lo_lock(c);
        return lock;
 }
@@ -219,23 +219,23 @@ static void mt2032_set_if_freq(struct i2c_client *c, unsigned int rfin,
        tuner_dbg("mt2032_set_if_freq rfin=%d if1=%d if2=%d from=%d to=%d\n",
                  rfin,if1,if2,from,to);
 
-        buf[0]=0;
-        ret=i2c_master_send(c,buf,1);
-        i2c_master_recv(c,buf,21);
+       buf[0]=0;
+       ret=i2c_master_send(c,buf,1);
+       i2c_master_recv(c,buf,21);
 
        buf[0]=0;
        ret=mt2032_compute_freq(c,rfin,if1,if2,from,to,&buf[1],&sel,t->xogc);
        if (ret<0)
                return;
 
-        // send only the relevant registers per Rev. 1.2
-        buf[0]=0;
-        ret=i2c_master_send(c,buf,4);
-        buf[5]=5;
-        ret=i2c_master_send(c,buf+5,4);
-        buf[11]=11;
-        ret=i2c_master_send(c,buf+11,3);
-        if(ret!=3)
+       // send only the relevant registers per Rev. 1.2
+       buf[0]=0;
+       ret=i2c_master_send(c,buf,4);
+       buf[5]=5;
+       ret=i2c_master_send(c,buf+5,4);
+       buf[11]=11;
+       ret=i2c_master_send(c,buf+11,3);
+       if(ret!=3)
                tuner_warn("i2c i/o error: rc == %d (should be 3)\n",ret);
 
        // wait for PLLs to lock (per manual), retry LINT if not.
@@ -253,7 +253,7 @@ static void mt2032_set_if_freq(struct i2c_client *c, unsigned int rfin,
                mdelay(10);
                buf[1]=8+t->xogc;
                i2c_master_send(c,buf,2);
-        }
+       }
 
        if (lock!=6)
                tuner_warn("MT2032 Fatal Error: PLLs didn't lock.\n");
@@ -284,7 +284,7 @@ static void mt2032_set_tv_freq(struct i2c_client *c, unsigned int freq)
                if2  = 38900*1000;
        }
 
-        mt2032_set_if_freq(c, freq*62500 /* freq*1000*1000/16 */,
+       mt2032_set_if_freq(c, freq*62500 /* freq*1000*1000/16 */,
                           1090*1000*1000, if2, from, to);
 }
 
@@ -294,7 +294,7 @@ static void mt2032_set_radio_freq(struct i2c_client *c, unsigned int freq)
        int if2 = t->radio_if2;
 
        // per Manual for FM tuning: first if center freq. 1085 MHz
-        mt2032_set_if_freq(c, freq * 1000 / 16,
+       mt2032_set_if_freq(c, freq * 1000 / 16,
                              1085*1000*1000,if2,if2,if2);
 }
 
@@ -302,57 +302,57 @@ static void mt2032_set_radio_freq(struct i2c_client *c, unsigned int freq)
 static int mt2032_init(struct i2c_client *c)
 {
        struct tuner *t = i2c_get_clientdata(c);
-        unsigned char buf[21];
-        int ret,xogc,xok=0;
+       unsigned char buf[21];
+       int ret,xogc,xok=0;
 
        // Initialize Registers per spec.
-        buf[1]=2; // Index to register 2
-        buf[2]=0xff;
-        buf[3]=0x0f;
-        buf[4]=0x1f;
-        ret=i2c_master_send(c,buf+1,4);
-
-        buf[5]=6; // Index register 6
-        buf[6]=0xe4;
-        buf[7]=0x8f;
-        buf[8]=0xc3;
-        buf[9]=0x4e;
-        buf[10]=0xec;
-        ret=i2c_master_send(c,buf+5,6);
-
-        buf[12]=13;  // Index register 13
-        buf[13]=0x32;
-        ret=i2c_master_send(c,buf+12,2);
-
-        // Adjust XOGC (register 7), wait for XOK
-        xogc=7;
-        do {
+       buf[1]=2; // Index to register 2
+       buf[2]=0xff;
+       buf[3]=0x0f;
+       buf[4]=0x1f;
+       ret=i2c_master_send(c,buf+1,4);
+
+       buf[5]=6; // Index register 6
+       buf[6]=0xe4;
+       buf[7]=0x8f;
+       buf[8]=0xc3;
+       buf[9]=0x4e;
+       buf[10]=0xec;
+       ret=i2c_master_send(c,buf+5,6);
+
+       buf[12]=13;  // Index register 13
+       buf[13]=0x32;
+       ret=i2c_master_send(c,buf+12,2);
+
+       // Adjust XOGC (register 7), wait for XOK
+       xogc=7;
+       do {
                tuner_dbg("mt2032: xogc = 0x%02x\n",xogc&0x07);
-                mdelay(10);
-                buf[0]=0x0e;
-                i2c_master_send(c,buf,1);
-                i2c_master_recv(c,buf,1);
-                xok=buf[0]&0x01;
-                tuner_dbg("mt2032: xok = 0x%02x\n",xok);
-                if (xok == 1) break;
-
-                xogc--;
-                tuner_dbg("mt2032: xogc = 0x%02x\n",xogc&0x07);
-                if (xogc == 3) {
-                        xogc=4; // min. 4 per spec
-                        break;
-                }
-                buf[0]=0x07;
-                buf[1]=0x88 + xogc;
-                ret=i2c_master_send(c,buf,2);
-                if (ret!=2)
+               mdelay(10);
+               buf[0]=0x0e;
+               i2c_master_send(c,buf,1);
+               i2c_master_recv(c,buf,1);
+               xok=buf[0]&0x01;
+               tuner_dbg("mt2032: xok = 0x%02x\n",xok);
+               if (xok == 1) break;
+
+               xogc--;
+               tuner_dbg("mt2032: xogc = 0x%02x\n",xogc&0x07);
+               if (xogc == 3) {
+                       xogc=4; // min. 4 per spec
+                       break;
+               }
+               buf[0]=0x07;
+               buf[1]=0x88 + xogc;
+               ret=i2c_master_send(c,buf,2);
+               if (ret!=2)
                        tuner_warn("i2c i/o error: rc == %d (should be 2)\n",ret);
-        } while (xok != 1 );
+       } while (xok != 1 );
        t->xogc=xogc;
 
        t->tv_freq    = mt2032_set_tv_freq;
        t->radio_freq = mt2032_set_radio_freq;
-        return(1);
+       return(1);
 }
 
 static void mt2050_set_antenna(struct i2c_client *c, unsigned char antenna)
@@ -426,7 +426,7 @@ static void mt2050_set_if_freq(struct i2c_client *c,unsigned int freq, unsigned
        }
 
        ret=i2c_master_send(c,buf,6);
-        if (ret!=6)
+       if (ret!=6)
                tuner_warn("i2c i/o error: rc == %d (should be 6)\n",ret);
 }
 
@@ -437,11 +437,11 @@ static void mt2050_set_tv_freq(struct i2c_client *c, unsigned int freq)
 
        if (t->std & V4L2_STD_525_60) {
                // NTSC
-                if2 = 45750*1000;
-        } else {
-                // PAL
-                if2 = 38900*1000;
-        }
+               if2 = 45750*1000;
+       } else {
+               // PAL
+               if2 = 38900*1000;
+       }
        if (V4L2_TUNER_DIGITAL_TV == t->mode) {
                // DVB (pinnacle 300i)
                if2 = 36150*1000;
@@ -455,7 +455,7 @@ static void mt2050_set_radio_freq(struct i2c_client *c, unsigned int freq)
        struct tuner *t = i2c_get_clientdata(c);
        int if2 = t->radio_if2;
 
-       mt2050_set_if_freq(c, freq*62500, if2);
+       mt2050_set_if_freq(c, freq * 1000 / 16, if2);
        mt2050_set_antenna(c, radio_antenna);
 }
 
@@ -487,7 +487,7 @@ int microtune_init(struct i2c_client *c)
 {
        struct tuner *t = i2c_get_clientdata(c);
        char *name;
-        unsigned char buf[21];
+       unsigned char buf[21];
        int company_code;
 
        memset(buf,0,sizeof(buf));
@@ -496,17 +496,17 @@ int microtune_init(struct i2c_client *c)
        t->standby    = NULL;
        name = "unknown";
 
-        i2c_master_send(c,buf,1);
-        i2c_master_recv(c,buf,21);
-        if (tuner_debug) {
-                int i;
+       i2c_master_send(c,buf,1);
+       i2c_master_recv(c,buf,21);
+       if (tuner_debug) {
+               int i;
                tuner_dbg("MT20xx hexdump:");
-                for(i=0;i<21;i++) {
-                        printk(" %02x",buf[i]);
-                        if(((i+1)%8)==0) printk(" ");
-                }
-                printk("\n");
-        }
+               for(i=0;i<21;i++) {
+                       printk(" %02x",buf[i]);
+                       if(((i+1)%8)==0) printk(" ");
+               }
+               printk("\n");
+       }
        company_code = buf[0x11] << 8 | buf[0x12];
        tuner_info("microtune: companycode=%04x part=%02x rev=%02x\n",
                   company_code,buf[0x13],buf[0x14]);
@@ -525,8 +525,8 @@ int microtune_init(struct i2c_client *c)
        default:
                tuner_info("microtune %s found, not (yet?) supported, sorry :-/\n",
                           name);
-                return 0;
-        }
+               return 0;
+       }
 
        strlcpy(c->name, name, sizeof(c->name));
        tuner_info("microtune %s found, OK\n",name);
index 72b70eb5da1d70e5f586dabfea18e1effad28a74..dca3ddfd510fa0aa92170cbe788985fc2d5e08c0 100644 (file)
@@ -31,7 +31,6 @@
 #include <linux/wait.h>
 #include <asm/uaccess.h>
 
-#include <media/id.h>
 
 #include "rds.h"
 
@@ -246,7 +245,7 @@ static void block_to_buf(struct saa6588 *s, unsigned char *blockbuf)
                s->wr_index = 0;
 
        if (s->wr_index == s->rd_index) {
-               s->rd_index++;
+               s->rd_index += 3;
                if (s->rd_index >= s->buf_size)
                        s->rd_index = 0;
        } else
@@ -328,7 +327,7 @@ static void saa6588_work(void *data)
        struct saa6588 *s = (struct saa6588 *)data;
 
        saa6588_i2c_poll(s);
-       mod_timer(&s->timer, jiffies + HZ / 50);        /* 20 msec */
+       mod_timer(&s->timer, jiffies + msecs_to_jiffies(20));
 }
 
 static int saa6588_configure(struct saa6588 *s)
@@ -434,9 +433,9 @@ static int saa6588_probe(struct i2c_adapter *adap)
                return i2c_probe(adap, &addr_data, saa6588_attach);
 #else
        switch (adap->id) {
-       case I2C_ALGO_BIT | I2C_HW_B_BT848:
-       case I2C_ALGO_BIT | I2C_HW_B_RIVA:
-       case I2C_ALGO_SAA7134:
+       case I2C_HW_B_BT848:
+       case I2C_HW_B_RIVA:
+       case I2C_HW_SAA7134:
                return i2c_probe(adap, &addr_data, saa6588_attach);
                break;
        }
diff --git a/drivers/media/video/saa711x.c b/drivers/media/video/saa711x.c
new file mode 100644 (file)
index 0000000..9aa8827
--- /dev/null
@@ -0,0 +1,593 @@
+/*
+ * saa711x - Philips SAA711x video decoder driver version 0.0.1
+ *
+ * To do: Now, it handles only saa7113/7114. Should be improved to
+ * handle all Philips saa711x devices.
+ *
+ * Based on saa7113 driver from Dave Perks <dperks@ibm.net>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/errno.h>
+#include <linux/fs.h>
+#include <linux/kernel.h>
+#include <linux/major.h>
+#include <linux/slab.h>
+#include <linux/mm.h>
+#include <linux/pci.h>
+#include <linux/signal.h>
+#include <asm/io.h>
+#include <asm/pgtable.h>
+#include <asm/page.h>
+#include <linux/sched.h>
+#include <asm/segment.h>
+#include <linux/types.h>
+#include <asm/uaccess.h>
+#include <linux/videodev.h>
+
+MODULE_DESCRIPTION("Philips SAA711x video decoder driver");
+MODULE_AUTHOR("Dave Perks, Jose Ignacio Gijon, Joerg Heckenbach, Mark McClelland, Dwaine Garden");
+MODULE_LICENSE("GPL");
+
+#include <linux/i2c.h>
+#include <linux/i2c-dev.h>
+
+#define I2C_NAME(s) (s)->name
+
+#include <linux/video_decoder.h>
+
+static int debug = 0;
+MODULE_PARM(debug, "i");
+MODULE_PARM_DESC(debug, " Set the default Debug level.  Default: 0 (Off) - (0-1)");
+
+
+#define dprintk(num, format, args...) \
+       do { \
+               if (debug >= num) \
+                       printk(format , ##args); \
+       } while (0)
+
+/* ----------------------------------------------------------------------- */
+
+struct saa711x {
+       unsigned char reg[32];
+
+       int norm;
+       int input;
+       int enable;
+       int bright;
+       int contrast;
+       int hue;
+       int sat;
+};
+
+#define   I2C_SAA7113        0x4A
+#define   I2C_SAA7114        0x42
+
+/* ----------------------------------------------------------------------- */
+
+static inline int
+saa711x_write (struct i2c_client *client,
+              u8                 reg,
+              u8                 value)
+{
+       struct saa711x *decoder = i2c_get_clientdata(client);
+
+       decoder->reg[reg] = value;
+       return i2c_smbus_write_byte_data(client, reg, value);
+}
+
+static int
+saa711x_write_block (struct i2c_client *client,
+                    const u8          *data,
+                    unsigned int       len)
+{
+       int ret = -1;
+       u8 reg;
+
+       /* the saa711x has an autoincrement function, use it if
+        * the adapter understands raw I2C */
+       if (i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) {
+               /* do raw I2C, not smbus compatible */
+               struct saa711x *decoder = i2c_get_clientdata(client);
+               struct i2c_msg msg;
+               u8 block_data[32];
+
+               msg.addr = client->addr;
+               msg.flags = 0;
+               while (len >= 2) {
+                       msg.buf = (char *) block_data;
+                       msg.len = 0;
+                       block_data[msg.len++] = reg = data[0];
+                       do {
+                               block_data[msg.len++] =
+                                   decoder->reg[reg++] = data[1];
+                               len -= 2;
+                               data += 2;
+                       } while (len >= 2 && data[0] == reg &&
+                                msg.len < 32);
+                       if ((ret = i2c_transfer(client->adapter,
+                                               &msg, 1)) < 0)
+                               break;
+               }
+       } else {
+               /* do some slow I2C emulation kind of thing */
+               while (len >= 2) {
+                       reg = *data++;
+                       if ((ret = saa711x_write(client, reg,
+                                                *data++)) < 0)
+                               break;
+                       len -= 2;
+               }
+       }
+
+       return ret;
+}
+
+static int
+saa711x_init_decoder (struct i2c_client *client,
+             struct video_decoder_init *init)
+{
+       return saa711x_write_block(client, init->data, init->len);
+}
+
+static inline int
+saa711x_read (struct i2c_client *client,
+             u8                 reg)
+{
+       return i2c_smbus_read_byte_data(client, reg);
+}
+
+/* ----------------------------------------------------------------------- */
+
+static const unsigned char saa711x_i2c_init[] = {
+       0x00, 0x00,     /* PH711x_CHIP_VERSION 00 - ID byte */
+       0x01, 0x08,     /* PH711x_INCREMENT_DELAY - (1) (1) (1) (1) IDEL3 IDEL2 IDELL1 IDEL0 */
+       0x02, 0xc0,     /* PH711x_ANALOG_INPUT_CONTR_1 - FUSE1 FUSE0 GUDL1 GUDL0 MODE3 MODE2 MODE1 MODE0 */
+       0x03, 0x23,     /* PH711x_ANALOG_INPUT_CONTR_2 - (1) HLNRS VBSL WPOFF HOLDG GAFIX GAI28 GAI18 */
+       0x04, 0x00,     /* PH711x_ANALOG_INPUT_CONTR_3 - GAI17 GAI16 GAI15 GAI14 GAI13 GAI12 GAI11 GAI10 */
+       0x05, 0x00,     /* PH711x_ANALOG_INPUT_CONTR_4 - GAI27 GAI26 GAI25 GAI24 GAI23 GAI22 GAI21 GAI20 */
+       0x06, 0xeb,     /* PH711x_HORIZONTAL_SYNC_START - HSB7 HSB6 HSB5 HSB4 HSB3 HSB2 HSB1 HSB0 */
+       0x07, 0xe0,     /* PH711x_HORIZONTAL_SYNC_STOP - HSS7 HSS6 HSS5 HSS4 HSS3 HSS2 HSS1 HSS0 */
+       0x08, 0x88,     /* PH711x_SYNC_CONTROL - AUFD FSEL FOET HTC1 HTC0 HPLL VNOI1 VNOI0 */
+       0x09, 0x00,     /* PH711x_LUMINANCE_CONTROL - BYPS PREF BPSS1 BPSS0 VBLB UPTCV APER1 APER0 */
+       0x0a, 0x80,     /* PH711x_LUMINANCE_BRIGHTNESS - BRIG7 BRIG6 BRIG5 BRIG4 BRIG3 BRIG2 BRIG1 BRIG0 */
+       0x0b, 0x47,     /* PH711x_LUMINANCE_CONTRAST - CONT7 CONT6 CONT5 CONT4 CONT3 CONT2 CONT1 CONT0 */
+       0x0c, 0x40,     /* PH711x_CHROMA_SATURATION - SATN7 SATN6 SATN5 SATN4 SATN3 SATN2 SATN1 SATN0 */
+       0x0d, 0x00,     /* PH711x_CHROMA_HUE_CONTROL - HUEC7 HUEC6 HUEC5 HUEC4 HUEC3 HUEC2 HUEC1 HUEC0 */
+       0x0e, 0x01,     /* PH711x_CHROMA_CONTROL - CDTO CSTD2 CSTD1 CSTD0 DCCF FCTC CHBW1 CHBW0 */
+       0x0f, 0xaa,     /* PH711x_CHROMA_GAIN_CONTROL - ACGC CGAIN6 CGAIN5 CGAIN4 CGAIN3 CGAIN2 CGAIN1 CGAIN0 */
+       0x10, 0x00,     /* PH711x_FORMAT_DELAY_CONTROL - OFTS1 OFTS0 HDEL1 HDEL0 VRLN YDEL2 YDEL1 YDEL0 */
+       0x11, 0x1C,     /* PH711x_OUTPUT_CONTROL_1 - GPSW1 CM99 GPSW0 HLSEL OEYC OERT VIPB COLO */
+       0x12, 0x01,     /* PH711x_OUTPUT_CONTROL_2 - RTSE13 RTSE12 RTSE11 RTSE10 RTSE03 RTSE02 RTSE01 RTSE00 */
+       0x13, 0x00,     /* PH711x_OUTPUT_CONTROL_3 - ADLSB (1) (1) OLDSB FIDP (1) AOSL1 AOSL0 */
+       0x14, 0x00,     /* RESERVED 14 - (1) (1) (1) (1) (1) (1) (1) (1) */
+       0x15, 0x00,     /* PH711x_V_GATE1_START - VSTA7 VSTA6 VSTA5 VSTA4 VSTA3 VSTA2 VSTA1 VSTA0 */
+       0x16, 0x00,     /* PH711x_V_GATE1_STOP - VSTO7 VSTO6 VSTO5 VSTO4 VSTO3 VSTO2 VSTO1 VSTO0 */
+       0x17, 0x00,     /* PH711x_V_GATE1_MSB - (1) (1) (1) (1) (1) (1) VSTO8 VSTA8 */
+};
+
+static int
+saa711x_command (struct i2c_client *client,
+                unsigned int       cmd,
+                void              *arg)
+{
+       struct saa711x *decoder = i2c_get_clientdata(client);
+
+       switch (cmd) {
+
+       case 0:
+       case DECODER_INIT:
+       {
+               struct video_decoder_init *init = arg;
+               if (NULL != init)
+                       return saa711x_init_decoder(client, init);
+               else {
+                       struct video_decoder_init vdi;
+                       vdi.data = saa711x_i2c_init;
+                       vdi.len = sizeof(saa711x_i2c_init);
+                       return saa711x_init_decoder(client, &vdi);
+               }
+       }
+
+       case DECODER_DUMP:
+       {
+               int i;
+
+               for (i = 0; i < 32; i += 16) {
+                       int j;
+
+                       printk(KERN_DEBUG "%s: %03x", I2C_NAME(client), i);
+                       for (j = 0; j < 16; ++j) {
+                               printk(" %02x",
+                                      saa711x_read(client, i + j));
+                       }
+                       printk("\n");
+               }
+       }
+               break;
+
+       case DECODER_GET_CAPABILITIES:
+       {
+               struct video_decoder_capability *cap = arg;
+
+               cap->flags = VIDEO_DECODER_PAL |
+                            VIDEO_DECODER_NTSC |
+                            VIDEO_DECODER_SECAM |
+                            VIDEO_DECODER_AUTO |
+                            VIDEO_DECODER_CCIR;
+               cap->inputs = 8;
+               cap->outputs = 1;
+       }
+               break;
+
+       case DECODER_GET_STATUS:
+       {
+               int *iarg = arg;
+               int status;
+               int res;
+
+               status = saa711x_read(client, 0x1f);
+               dprintk(1, KERN_DEBUG "%s status: 0x%02x\n", I2C_NAME(client),
+                       status);
+               res = 0;
+               if ((status & (1 << 6)) == 0) {
+                       res |= DECODER_STATUS_GOOD;
+               }
+               switch (decoder->norm) {
+               case VIDEO_MODE_NTSC:
+                       res |= DECODER_STATUS_NTSC;
+                       break;
+               case VIDEO_MODE_PAL:
+                       res |= DECODER_STATUS_PAL;
+                       break;
+               case VIDEO_MODE_SECAM:
+                       res |= DECODER_STATUS_SECAM;
+                       break;
+               default:
+               case VIDEO_MODE_AUTO:
+                       if ((status & (1 << 5)) != 0) {
+                               res |= DECODER_STATUS_NTSC;
+                       } else {
+                               res |= DECODER_STATUS_PAL;
+                       }
+                       break;
+               }
+               if ((status & (1 << 0)) != 0) {
+                       res |= DECODER_STATUS_COLOR;
+               }
+               *iarg = res;
+       }
+               break;
+
+       case DECODER_SET_GPIO:
+       {
+               int *iarg = arg;
+               if (0 != *iarg) {
+                       saa711x_write(client, 0x11,
+                               (decoder->reg[0x11] | 0x80));
+               } else {
+                       saa711x_write(client, 0x11,
+                               (decoder->reg[0x11] & 0x7f));
+               }
+               break;
+       }
+
+       case DECODER_SET_VBI_BYPASS:
+       {
+               int *iarg = arg;
+               if (0 != *iarg) {
+                       saa711x_write(client, 0x13,
+                               (decoder->reg[0x13] & 0xf0) | 0x0a);
+               } else {
+                       saa711x_write(client, 0x13,
+                               (decoder->reg[0x13] & 0xf0));
+               }
+               break;
+       }
+
+       case DECODER_SET_NORM:
+       {
+               int *iarg = arg;
+
+               switch (*iarg) {
+
+               case VIDEO_MODE_NTSC:
+                       saa711x_write(client, 0x08,
+                                     (decoder->reg[0x08] & 0x3f) | 0x40);
+                       saa711x_write(client, 0x0e,
+                                     (decoder->reg[0x0e] & 0x8f));
+                       break;
+
+               case VIDEO_MODE_PAL:
+                       saa711x_write(client, 0x08,
+                                     (decoder->reg[0x08] & 0x3f) | 0x00);
+                       saa711x_write(client, 0x0e,
+                                     (decoder->reg[0x0e] & 0x8f));
+                       break;
+
+               case VIDEO_MODE_SECAM:
+                       saa711x_write(client, 0x08,
+                                     (decoder->reg[0x0e] & 0x3f) | 0x00);
+                       saa711x_write(client, 0x0e,
+                                     (decoder->reg[0x0e] & 0x8f) | 0x50);
+                       break;
+
+               case VIDEO_MODE_AUTO:
+                       saa711x_write(client, 0x08,
+                                     (decoder->reg[0x08] & 0x3f) | 0x80);
+                       saa711x_write(client, 0x0e,
+                                     (decoder->reg[0x0e] & 0x8f));
+                       break;
+
+               default:
+                       return -EINVAL;
+
+               }
+               decoder->norm = *iarg;
+       }
+               break;
+
+       case DECODER_SET_INPUT:
+       {
+               int *iarg = arg;
+               if (*iarg < 0 || *iarg > 9) {
+                       return -EINVAL;
+               }
+               if (decoder->input != *iarg) {
+                       decoder->input = *iarg;
+                       /* select mode */
+                       saa711x_write(client, 0x02,
+                                     (decoder->reg[0x02] & 0xf0) | decoder->input);
+                       /* bypass chrominance trap for modes 4..7 */
+                       saa711x_write(client, 0x09,
+                                     (decoder->reg[0x09] & 0x7f) | ((decoder->input > 3) ? 0x80 : 0));
+               }
+       }
+               break;
+
+       case DECODER_SET_OUTPUT:
+       {
+               int *iarg = arg;
+
+               /* not much choice of outputs */
+               if (*iarg != 0) {
+                       return -EINVAL;
+               }
+       }
+               break;
+
+       case DECODER_ENABLE_OUTPUT:
+       {
+               int *iarg = arg;
+               int enable = (*iarg != 0);
+
+               if (decoder->enable != enable) {
+                       decoder->enable = enable;
+
+                       /* RJ: If output should be disabled (for
+                        * playing videos), we also need a open PLL.
+                        * The input is set to 0 (where no input
+                        * source is connected), although this
+                        * is not necessary.
+                        *
+                        * If output should be enabled, we have to
+                        * reverse the above.
+                        */
+
+                       if (decoder->enable) {
+                               saa711x_write(client, 0x02,
+                                             (decoder->
+                                              reg[0x02] & 0xf8) |
+                                             decoder->input);
+                               saa711x_write(client, 0x08,
+                                             (decoder->reg[0x08] & 0xfb));
+                               saa711x_write(client, 0x11,
+                                             (decoder->
+                                              reg[0x11] & 0xf3) | 0x0c);
+                       } else {
+                               saa711x_write(client, 0x02,
+                                             (decoder->reg[0x02] & 0xf8));
+                               saa711x_write(client, 0x08,
+                                             (decoder->
+                                              reg[0x08] & 0xfb) | 0x04);
+                               saa711x_write(client, 0x11,
+                                             (decoder->reg[0x11] & 0xf3));
+                       }
+               }
+       }
+               break;
+
+       case DECODER_SET_PICTURE:
+       {
+               struct video_picture *pic = arg;
+
+               if (decoder->bright != pic->brightness) {
+                       /* We want 0 to 255 we get 0-65535 */
+                       decoder->bright = pic->brightness;
+                       saa711x_write(client, 0x0a, decoder->bright >> 8);
+               }
+               if (decoder->contrast != pic->contrast) {
+                       /* We want 0 to 127 we get 0-65535 */
+                       decoder->contrast = pic->contrast;
+                       saa711x_write(client, 0x0b,
+                                     decoder->contrast >> 9);
+               }
+               if (decoder->sat != pic->colour) {
+                       /* We want 0 to 127 we get 0-65535 */
+                       decoder->sat = pic->colour;
+                       saa711x_write(client, 0x0c, decoder->sat >> 9);
+               }
+               if (decoder->hue != pic->hue) {
+                       /* We want -128 to 127 we get 0-65535 */
+                       decoder->hue = pic->hue;
+                       saa711x_write(client, 0x0d,
+                                     (decoder->hue - 32768) >> 8);
+               }
+       }
+               break;
+
+       default:
+               return -EINVAL;
+       }
+
+       return 0;
+}
+
+/* ----------------------------------------------------------------------- */
+
+/*
+ * Generic i2c probe
+ * concerning the addresses: i2c wants 7 bit (without the r/w bit), so '>>1'
+ */
+
+/* standard i2c insmod options */
+static unsigned short normal_i2c[] = {
+       I2C_SAA7113>>1,         /* saa7113 */
+       I2C_SAA7114>>1,         /* saa7114 */
+       I2C_CLIENT_END
+};
+
+I2C_CLIENT_INSMOD;
+
+
+static struct i2c_driver i2c_driver_saa711x;
+
+static int
+saa711x_detect_client (struct i2c_adapter *adapter,
+                      int                 address,
+                      int                 kind)
+{
+       int i;
+       struct i2c_client *client;
+       struct saa711x *decoder;
+       struct video_decoder_init vdi;
+
+       dprintk(1,
+               KERN_INFO
+               "saa711x.c: detecting saa711x client on address 0x%x\n",
+               address << 1);
+
+       /* Check if the adapter supports the needed features */
+       if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA))
+               return 0;
+
+       client = kmalloc(sizeof(struct i2c_client), GFP_KERNEL);
+       if (client == 0)
+               return -ENOMEM;
+       memset(client, 0, sizeof(struct i2c_client));
+       client->addr = address;
+       client->adapter = adapter;
+       client->driver = &i2c_driver_saa711x;
+       client->flags = I2C_CLIENT_ALLOW_USE;
+       strlcpy(I2C_NAME(client), "saa711x", sizeof(I2C_NAME(client)));
+       decoder = kmalloc(sizeof(struct saa711x), GFP_KERNEL);
+       if (decoder == NULL) {
+               kfree(client);
+               return -ENOMEM;
+       }
+       memset(decoder, 0, sizeof(struct saa711x));
+       decoder->norm = VIDEO_MODE_NTSC;
+       decoder->input = 0;
+       decoder->enable = 1;
+       decoder->bright = 32768;
+       decoder->contrast = 32768;
+       decoder->hue = 32768;
+       decoder->sat = 32768;
+       i2c_set_clientdata(client, decoder);
+
+       i = i2c_attach_client(client);
+       if (i) {
+               kfree(client);
+               kfree(decoder);
+               return i;
+       }
+
+       vdi.data = saa711x_i2c_init;
+       vdi.len = sizeof(saa711x_i2c_init);
+       i = saa711x_init_decoder(client, &vdi);
+       if (i < 0) {
+               dprintk(1, KERN_ERR "%s_attach error: init status %d\n",
+                       I2C_NAME(client), i);
+       } else {
+               dprintk(1,
+                       KERN_INFO
+                       "%s_attach: chip version %x at address 0x%x\n",
+                       I2C_NAME(client), saa711x_read(client, 0x00) >> 4,
+                       client->addr << 1);
+       }
+
+       return 0;
+}
+
+static int
+saa711x_attach_adapter (struct i2c_adapter *adapter)
+{
+       dprintk(1,
+               KERN_INFO
+               "saa711x.c: starting probe for adapter %s (0x%x)\n",
+               I2C_NAME(adapter), adapter->id);
+       return i2c_probe(adapter, &addr_data, &saa711x_detect_client);
+}
+
+static int
+saa711x_detach_client (struct i2c_client *client)
+{
+       struct saa711x *decoder = i2c_get_clientdata(client);
+       int err;
+
+       err = i2c_detach_client(client);
+       if (err) {
+               return err;
+       }
+
+       kfree(decoder);
+       kfree(client);
+
+       return 0;
+}
+
+/* ----------------------------------------------------------------------- */
+
+static struct i2c_driver i2c_driver_saa711x = {
+       .owner = THIS_MODULE,
+       .name = "saa711x",
+
+       .id = I2C_DRIVERID_SAA711X,
+       .flags = I2C_DF_NOTIFY,
+
+       .attach_adapter = saa711x_attach_adapter,
+       .detach_client = saa711x_detach_client,
+       .command = saa711x_command,
+};
+
+static int __init
+saa711x_init (void)
+{
+       return i2c_add_driver(&i2c_driver_saa711x);
+}
+
+static void __exit
+saa711x_exit (void)
+{
+       i2c_del_driver(&i2c_driver_saa711x);
+}
+
+module_init(saa711x_init);
+module_exit(saa711x_exit);
diff --git a/drivers/media/video/saa7134/Kconfig b/drivers/media/video/saa7134/Kconfig
new file mode 100644 (file)
index 0000000..624e880
--- /dev/null
@@ -0,0 +1,68 @@
+config VIDEO_SAA7134
+       tristate "Philips SAA7134 support"
+       depends on VIDEO_DEV && PCI && I2C && SOUND
+       select VIDEO_BUF
+       select VIDEO_IR
+       select VIDEO_TUNER
+       select CRC32
+       ---help---
+         This is a video4linux driver for Philips SAA713x based
+         TV cards.
+
+         To compile this driver as a module, choose M here: the
+         module will be called saa7134.
+
+config VIDEO_SAA7134_DVB
+       tristate "DVB/ATSC Support for saa7134 based TV cards"
+       depends on VIDEO_SAA7134 && DVB_CORE
+       select VIDEO_BUF_DVB
+       ---help---
+         This adds support for DVB cards based on the
+         Philips saa7134 chip.
+
+         To compile this driver as a module, choose M here: the
+         module will be called saa7134-dvb.
+
+         You must also select one or more DVB demodulators.
+         If you are unsure which you need, choose all of them.
+
+config VIDEO_SAA7134_DVB_ALL_FRONTENDS
+       bool "Build all supported frontends for saa7134 based TV cards"
+       default y
+       depends on VIDEO_SAA7134_DVB
+       select DVB_MT352
+       select DVB_TDA1004X
+       select DVB_NXT200X
+       ---help---
+         This builds saa7134-dvb with all currently supported frontend
+         demodulators.  If you wish to tweak your configuration, and
+         only include support for the hardware that you need, choose N here.
+
+         If you are unsure, choose Y.
+
+config VIDEO_SAA7134_DVB_MT352
+       tristate "Zarlink MT352 DVB-T Support"
+       default m
+       depends on VIDEO_SAA7134_DVB && !VIDEO_SAA7134_DVB_ALL_FRONTENDS
+       select DVB_MT352
+       ---help---
+         This adds DVB-T support for cards based on the
+         Philips saa7134 chip and the MT352 demodulator.
+
+config VIDEO_SAA7134_DVB_TDA1004X
+       tristate "Phillips TDA10045H/TDA10046H DVB-T Support"
+       default m
+       depends on VIDEO_SAA7134_DVB && !VIDEO_SAA7134_DVB_ALL_FRONTENDS
+       select DVB_TDA1004X
+       ---help---
+         This adds DVB-T support for cards based on the
+         Philips saa7134 chip and the TDA10045H/TDA10046H demodulator.
+
+config VIDEO_SAA7134_DVB_NXT200X
+       tristate "NXT2002/NXT2004 ATSC Support"
+       default m
+       depends on VIDEO_SAA7134_DVB && !VIDEO_SAA7134_DVB_ALL_FRONTENDS
+       select DVB_NXT200X
+       ---help---
+         This adds ATSC 8VSB and QAM64/256 support for cards based on the
+         Philips saa7134 chip and the NXT2002/NXT2004 demodulator.
index b778ffd94e65679ed3a274dbd103457a726092a7..e0b28f0533af02549d0b9e1722e3e744196d80cd 100644 (file)
@@ -3,15 +3,22 @@ saa7134-objs :=       saa7134-cards.o saa7134-core.o saa7134-i2c.o    \
                saa7134-oss.o saa7134-ts.o saa7134-tvaudio.o    \
                saa7134-vbi.o saa7134-video.o saa7134-input.o
 
-obj-$(CONFIG_VIDEO_SAA7134) += saa7134.o saa7134-empress.o saa6752hs.o
+obj-$(CONFIG_VIDEO_SAA7134) +=  saa7134.o saa7134-empress.o \
+                               saa6752hs.o saa7134-alsa.o
 obj-$(CONFIG_VIDEO_SAA7134_DVB) += saa7134-dvb.o
 
 EXTRA_CFLAGS += -I$(src)/..
 EXTRA_CFLAGS += -I$(srctree)/drivers/media/dvb/dvb-core
 EXTRA_CFLAGS += -I$(srctree)/drivers/media/dvb/frontends
+ifneq ($(CONFIG_VIDEO_BUF_DVB),n)
+ EXTRA_CFLAGS += -DHAVE_VIDEO_BUF_DVB=1
+endif
 ifneq ($(CONFIG_DVB_MT352),n)
  EXTRA_CFLAGS += -DHAVE_MT352=1
 endif
 ifneq ($(CONFIG_DVB_TDA1004X),n)
  EXTRA_CFLAGS += -DHAVE_TDA1004X=1
 endif
+ifneq ($(CONFIG_DVB_NXT200X),n)
+ EXTRA_CFLAGS += -DHAVE_NXT200X=1
+endif
index 382911c6ef2243813b02fe7d8107ed5194f17b4c..cdd1ed9c80658d358ebcad24de73fdb79112b0c4 100644 (file)
@@ -13,7 +13,6 @@
 #include <linux/init.h>
 #include <linux/crc32.h>
 
-#include <media/id.h>
 
 #define MPEG_VIDEO_TARGET_BITRATE_MAX  27000
 #define MPEG_VIDEO_MAX_BITRATE_MAX     27000
@@ -57,6 +56,7 @@ struct saa6752hs_state {
        struct i2c_client             client;
        struct v4l2_mpeg_compression  params;
        enum saa6752hs_videoformat    video_format;
+       v4l2_std_id                   standard;
 };
 
 enum saa6752hs_command {
@@ -74,58 +74,58 @@ enum saa6752hs_command {
 /* ---------------------------------------------------------------------- */
 
 static u8 PAT[] = {
-       0xc2, // i2c register
-       0x00, // table number for encoder
+       0xc2, /* i2c register */
+       0x00, /* table number for encoder */
 
-       0x47, // sync
-       0x40, 0x00, // transport_error_indicator(0), payload_unit_start(1), transport_priority(0), pid(0)
-       0x10, // transport_scrambling_control(00), adaptation_field_control(01), continuity_counter(0)
+       0x47, /* sync */
+       0x40, 0x00, /* transport_error_indicator(0), payload_unit_start(1), transport_priority(0), pid(0) */
+       0x10, /* transport_scrambling_control(00), adaptation_field_control(01), continuity_counter(0) */
 
-       0x00, // PSI pointer to start of table
+       0x00, /* PSI pointer to start of table */
 
-       0x00, // tid(0)
-       0xb0, 0x0d, // section_syntax_indicator(1), section_length(13)
+       0x00, /* tid(0) */
+       0xb0, 0x0d, /* section_syntax_indicator(1), section_length(13) */
 
-       0x00, 0x01, // transport_stream_id(1)
+       0x00, 0x01, /* transport_stream_id(1) */
 
-       0xc1, // version_number(0), current_next_indicator(1)
+       0xc1, /* version_number(0), current_next_indicator(1) */
 
-       0x00, 0x00, // section_number(0), last_section_number(0)
+       0x00, 0x00, /* section_number(0), last_section_number(0) */
 
-       0x00, 0x01, // program_number(1)
+       0x00, 0x01, /* program_number(1) */
 
-       0xe0, 0x00, // PMT PID
+       0xe0, 0x00, /* PMT PID */
 
-       0x00, 0x00, 0x00, 0x00 // CRC32
+       0x00, 0x00, 0x00, 0x00 /* CRC32 */
 };
 
 static u8 PMT[] = {
-       0xc2, // i2c register
-       0x01, // table number for encoder
+       0xc2, /* i2c register */
+       0x01, /* table number for encoder */
 
-       0x47, // sync
-       0x40, 0x00, // transport_error_indicator(0), payload_unit_start(1), transport_priority(0), pid
-       0x10, // transport_scrambling_control(00), adaptation_field_control(01), continuity_counter(0)
+       0x47, /* sync */
+       0x40, 0x00, /* transport_error_indicator(0), payload_unit_start(1), transport_priority(0), pid */
+       0x10, /* transport_scrambling_control(00), adaptation_field_control(01), continuity_counter(0) */
 
-       0x00, // PSI pointer to start of table
+       0x00, /* PSI pointer to start of table */
 
-       0x02, // tid(2)
-       0xb0, 0x17, // section_syntax_indicator(1), section_length(23)
+       0x02, /* tid(2) */
+       0xb0, 0x17, /* section_syntax_indicator(1), section_length(23) */
 
-       0x00, 0x01, // program_number(1)
+       0x00, 0x01, /* program_number(1) */
 
-       0xc1, // version_number(0), current_next_indicator(1)
+       0xc1, /* version_number(0), current_next_indicator(1) */
 
-       0x00, 0x00, // section_number(0), last_section_number(0)
+       0x00, 0x00, /* section_number(0), last_section_number(0) */
 
-       0xe0, 0x00, // PCR_PID
+       0xe0, 0x00, /* PCR_PID */
 
-       0xf0, 0x00, // program_info_length(0)
+       0xf0, 0x00, /* program_info_length(0) */
 
-       0x02, 0xe0, 0x00, 0xf0, 0x00, // video stream type(2), pid
-       0x04, 0xe0, 0x00, 0xf0, 0x00, // audio stream type(4), pid
+       0x02, 0xe0, 0x00, 0xf0, 0x00, /* video stream type(2), pid */
+       0x04, 0xe0, 0x00, 0xf0, 0x00, /* audio stream type(4), pid */
 
-       0x00, 0x00, 0x00, 0x00 // CRC32
+       0x00, 0x00, 0x00, 0x00 /* CRC32 */
 };
 
 static struct v4l2_mpeg_compression param_defaults =
@@ -166,33 +166,33 @@ static int saa6752hs_chip_command(struct i2c_client* client,
        unsigned long timeout;
        int status = 0;
 
-       // execute the command
+       /* execute the command */
        switch(command) {
-       case SAA6752HS_COMMAND_RESET:
-               buf[0] = 0x00;
+       case SAA6752HS_COMMAND_RESET:
+               buf[0] = 0x00;
                break;
 
        case SAA6752HS_COMMAND_STOP:
-               buf[0] = 0x03;
+               buf[0] = 0x03;
                break;
 
        case SAA6752HS_COMMAND_START:
-               buf[0] = 0x02;
+               buf[0] = 0x02;
                break;
 
        case SAA6752HS_COMMAND_PAUSE:
-               buf[0] = 0x04;
+               buf[0] = 0x04;
                break;
 
        case SAA6752HS_COMMAND_RECONFIGURE:
                buf[0] = 0x05;
                break;
 
-       case SAA6752HS_COMMAND_SLEEP:
-               buf[0] = 0x06;
+       case SAA6752HS_COMMAND_SLEEP:
+               buf[0] = 0x06;
                break;
 
-       case SAA6752HS_COMMAND_RECONFIGURE_FORCE:
+       case SAA6752HS_COMMAND_RECONFIGURE_FORCE:
                buf[0] = 0x07;
                break;
 
@@ -200,13 +200,13 @@ static int saa6752hs_chip_command(struct i2c_client* client,
                return -EINVAL;
        }
 
-       // set it and wait for it to be so
+       /* set it and wait for it to be so */
        i2c_master_send(client, buf, 1);
        timeout = jiffies + HZ * 3;
        for (;;) {
-               // get the current status
+               /* get the current status */
                buf[0] = 0x10;
-               i2c_master_send(client, buf, 1);
+               i2c_master_send(client, buf, 1);
                i2c_master_recv(client, buf, 1);
 
                if (!(buf[0] & 0x20))
@@ -216,61 +216,58 @@ static int saa6752hs_chip_command(struct i2c_client* client,
                        break;
                }
 
-               // wait a bit
                msleep(10);
        }
 
-       // delay a bit to let encoder settle
+       /* delay a bit to let encoder settle */
        msleep(50);
 
-       // done
-       return status;
+       return status;
 }
 
 
 static int saa6752hs_set_bitrate(struct i2c_client* client,
                                 struct v4l2_mpeg_compression* params)
 {
-       u8 buf[3];
+       u8 buf[3];
 
-       // set the bitrate mode
+       /* set the bitrate mode */
        buf[0] = 0x71;
        buf[1] = (params->vi_bitrate.mode == V4L2_BITRATE_VBR) ? 0 : 1;
        i2c_master_send(client, buf, 2);
 
-       // set the video bitrate
+       /* set the video bitrate */
        if (params->vi_bitrate.mode == V4L2_BITRATE_VBR) {
-               // set the target bitrate
+               /* set the target bitrate */
                buf[0] = 0x80;
                buf[1] = params->vi_bitrate.target >> 8;
-               buf[2] = params->vi_bitrate.target & 0xff;
+               buf[2] = params->vi_bitrate.target & 0xff;
                i2c_master_send(client, buf, 3);
 
-               // set the max bitrate
+               /* set the max bitrate */
                buf[0] = 0x81;
                buf[1] = params->vi_bitrate.max >> 8;
-               buf[2] = params->vi_bitrate.max & 0xff;
+               buf[2] = params->vi_bitrate.max & 0xff;
                i2c_master_send(client, buf, 3);
        } else {
-               // set the target bitrate (no max bitrate for CBR)
-               buf[0] = 0x81;
+               /* set the target bitrate (no max bitrate for CBR) */
+               buf[0] = 0x81;
                buf[1] = params->vi_bitrate.target >> 8;
-               buf[2] = params->vi_bitrate.target & 0xff;
+               buf[2] = params->vi_bitrate.target & 0xff;
                i2c_master_send(client, buf, 3);
        }
 
-       // set the audio bitrate
-       buf[0] = 0x94;
+       /* set the audio bitrate */
+       buf[0] = 0x94;
        buf[1] = (256 == params->au_bitrate.target) ? 0 : 1;
        i2c_master_send(client, buf, 2);
 
-       // set the total bitrate
+       /* set the total bitrate */
        buf[0] = 0xb1;
-       buf[1] = params->st_bitrate.target >> 8;
-       buf[2] = params->st_bitrate.target & 0xff;
+       buf[1] = params->st_bitrate.target >> 8;
+       buf[2] = params->st_bitrate.target & 0xff;
        i2c_master_send(client, buf, 3);
 
-       // return success
        return 0;
 }
 
@@ -376,36 +373,43 @@ static int saa6752hs_init(struct i2c_client* client)
 
        h = i2c_get_clientdata(client);
 
-       // Set video format - must be done first as it resets other settings
+       /* Set video format - must be done first as it resets other settings */
        buf[0] = 0x41;
        buf[1] = h->video_format;
        i2c_master_send(client, buf, 2);
 
-        // set bitrate
-        saa6752hs_set_bitrate(client, &h->params);
+       /* Set number of lines in input signal */
+       buf[0] = 0x40;
+       buf[1] = 0x00;
+       if (h->standard & V4L2_STD_525_60)
+               buf[1] = 0x01;
+       i2c_master_send(client, buf, 2);
+
+       /* set bitrate */
+       saa6752hs_set_bitrate(client, &h->params);
 
-       // Set GOP structure {3, 13}
+       /* Set GOP structure {3, 13} */
        buf[0] = 0x72;
        buf[1] = 0x03;
        buf[2] = 0x0D;
        i2c_master_send(client,buf,3);
 
-       // Set minimum Q-scale {4}
+       /* Set minimum Q-scale {4} */
        buf[0] = 0x82;
        buf[1] = 0x04;
        i2c_master_send(client,buf,2);
 
-       // Set maximum Q-scale {12}
+       /* Set maximum Q-scale {12} */
        buf[0] = 0x83;
        buf[1] = 0x0C;
        i2c_master_send(client,buf,2);
 
-       // Set Output Protocol
+       /* Set Output Protocol */
        buf[0] = 0xD0;
        buf[1] = 0x81;
        i2c_master_send(client,buf,2);
 
-       // Set video output stream format {TS}
+       /* Set video output stream format {TS} */
        buf[0] = 0xB0;
        buf[1] = 0x05;
        i2c_master_send(client,buf,2);
@@ -421,9 +425,9 @@ static int saa6752hs_init(struct i2c_client* client)
        localPAT[sizeof(PAT) - 1] = crc & 0xFF;
 
        /* compute PMT */
-       memcpy(localPMT, PMT, sizeof(PMT));
-       localPMT[3] = 0x40 | ((h->params.ts_pid_pmt >> 8) & 0x0f);
-       localPMT[4] = h->params.ts_pid_pmt & 0xff;
+       memcpy(localPMT, PMT, sizeof(PMT));
+       localPMT[3] = 0x40 | ((h->params.ts_pid_pmt >> 8) & 0x0f);
+       localPMT[4] = h->params.ts_pid_pmt & 0xff;
        localPMT[15] = 0xE0 | ((h->params.ts_pid_pcr >> 8) & 0x0F);
        localPMT[16] = h->params.ts_pid_pcr & 0xFF;
        localPMT[20] = 0xE0 | ((h->params.ts_pid_video >> 8) & 0x0F);
@@ -436,39 +440,39 @@ static int saa6752hs_init(struct i2c_client* client)
        localPMT[sizeof(PMT) - 2] = (crc >> 8) & 0xFF;
        localPMT[sizeof(PMT) - 1] = crc & 0xFF;
 
-       // Set Audio PID
+       /* Set Audio PID */
        buf[0] = 0xC1;
        buf[1] = (h->params.ts_pid_audio >> 8) & 0xFF;
        buf[2] = h->params.ts_pid_audio & 0xFF;
        i2c_master_send(client,buf,3);
 
-       // Set Video PID
+       /* Set Video PID */
        buf[0] = 0xC0;
        buf[1] = (h->params.ts_pid_video >> 8) & 0xFF;
        buf[2] = h->params.ts_pid_video & 0xFF;
        i2c_master_send(client,buf,3);
 
-       // Set PCR PID
+       /* Set PCR PID */
        buf[0] = 0xC4;
        buf[1] = (h->params.ts_pid_pcr >> 8) & 0xFF;
        buf[2] = h->params.ts_pid_pcr & 0xFF;
        i2c_master_send(client,buf,3);
 
-       // Send SI tables
+       /* Send SI tables */
        i2c_master_send(client,localPAT,sizeof(PAT));
        i2c_master_send(client,localPMT,sizeof(PMT));
 
-       // mute then unmute audio. This removes buzzing artefacts
+       /* mute then unmute audio. This removes buzzing artefacts */
        buf[0] = 0xa4;
        buf[1] = 1;
        i2c_master_send(client, buf, 2);
-       buf[1] = 0;
+       buf[1] = 0;
        i2c_master_send(client, buf, 2);
 
-       // start it going
+       /* start it going */
        saa6752hs_chip_command(client, SAA6752HS_COMMAND_START);
 
-       // readout current state
+       /* readout current state */
        buf[0] = 0xE1;
        buf[1] = 0xA7;
        buf[2] = 0xFE;
@@ -477,7 +481,7 @@ static int saa6752hs_init(struct i2c_client* client)
        i2c_master_send(client, buf, 5);
        i2c_master_recv(client, buf2, 4);
 
-       // change aspect ratio
+       /* change aspect ratio */
        buf[0] = 0xE0;
        buf[1] = 0xA7;
        buf[2] = 0xFE;
@@ -498,7 +502,6 @@ static int saa6752hs_init(struct i2c_client* client)
        buf[8] = buf2[3];
        i2c_master_send(client, buf, 9);
 
-       // return success
        return 0;
 }
 
@@ -506,16 +509,19 @@ static int saa6752hs_attach(struct i2c_adapter *adap, int addr, int kind)
 {
        struct saa6752hs_state *h;
 
-        printk("saa6752hs: chip found @ 0x%x\n", addr<<1);
+       printk("saa6752hs: chip found @ 0x%x\n", addr<<1);
 
-        if (NULL == (h = kmalloc(sizeof(*h), GFP_KERNEL)))
-                return -ENOMEM;
+       if (NULL == (h = kmalloc(sizeof(*h), GFP_KERNEL)))
+               return -ENOMEM;
        memset(h,0,sizeof(*h));
        h->client = client_template;
        h->params = param_defaults;
        h->client.adapter = adap;
        h->client.addr = addr;
 
+       /* Assume 625 input lines */
+       h->standard = 0;
+
        i2c_set_clientdata(&h->client, h);
         i2c_attach_client(&h->client);
        return 0;
@@ -545,7 +551,7 @@ saa6752hs_command(struct i2c_client *client, unsigned int cmd, void *arg)
        struct v4l2_mpeg_compression *params = arg;
        int err = 0;
 
-        switch (cmd) {
+       switch (cmd) {
        case VIDIOC_S_MPEGCOMP:
                if (NULL == params) {
                        /* apply settings and start encoder */
@@ -559,7 +565,7 @@ saa6752hs_command(struct i2c_client *client, unsigned int cmd, void *arg)
                break;
        case VIDIOC_G_FMT:
        {
-           struct v4l2_format *f = arg;
+          struct v4l2_format *f = arg;
 
           if (h->video_format == SAA6752HS_VF_UNKNOWN)
                   h->video_format = SAA6752HS_VF_D1;
@@ -576,6 +582,9 @@ saa6752hs_command(struct i2c_client *client, unsigned int cmd, void *arg)
                saa6752hs_set_subsampling(client, f);
                break;
        }
+       case VIDIOC_S_STD:
+               h->standard = *((v4l2_std_id *) arg);
+               break;
        default:
                /* nothing */
                break;
diff --git a/drivers/media/video/saa7134/saa7134-alsa.c b/drivers/media/video/saa7134/saa7134-alsa.c
new file mode 100644 (file)
index 0000000..4f3c423
--- /dev/null
@@ -0,0 +1,1047 @@
+/*
+ *   SAA713x ALSA support for V4L
+ *
+ *
+ *   Caveats:
+ *        - Volume doesn't work (it's always at max)
+ *
+ *   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, version 2
+ *
+ *   This program is distributed in the hope that it will be useful,
+ *   but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *   GNU General Public License for more details.
+ *
+ *   You should have received a copy of the GNU General Public License
+ *   along with this program; if not, write to the Free Software
+ *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
+ *
+ */
+
+#include <sound/driver.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/time.h>
+#include <linux/wait.h>
+#include <linux/moduleparam.h>
+#include <linux/module.h>
+#include <sound/core.h>
+#include <sound/control.h>
+#include <sound/pcm.h>
+#include <sound/initval.h>
+
+#include "saa7134.h"
+#include "saa7134-reg.h"
+
+static unsigned int debug  = 0;
+module_param(debug, int, 0644);
+MODULE_PARM_DESC(debug,"enable debug messages [alsa]");
+
+/*
+ * Configuration macros
+ */
+
+/* defaults */
+#define MIXER_ADDR_TVTUNER     0
+#define MIXER_ADDR_LINE1       1
+#define MIXER_ADDR_LINE2       2
+#define MIXER_ADDR_LAST                2
+
+static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX;     /* Index 0-MAX */
+static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR;      /* ID for this card */
+static int enable[SNDRV_CARDS] = {1, [1 ... (SNDRV_CARDS - 1)] = 0};
+
+module_param_array(index, int, NULL, 0444);
+MODULE_PARM_DESC(index, "Index value for SAA7134 capture interface(s).");
+
+#define dprintk(fmt, arg...)    if (debug) \
+        printk(KERN_DEBUG "%s/alsa: " fmt, dev->name , ## arg)
+
+/*
+ * Main chip structure
+ */
+typedef struct snd_card_saa7134 {
+       snd_card_t *card;
+       spinlock_t mixer_lock;
+       int mixer_volume[MIXER_ADDR_LAST+1][2];
+       int capture_source[MIXER_ADDR_LAST+1][2];
+       struct pci_dev *pci;
+       struct saa7134_dev *saadev;
+
+       unsigned long iobase;
+       int irq;
+
+       spinlock_t lock;
+} snd_card_saa7134_t;
+
+
+
+/*
+ * PCM structure
+ */
+
+typedef struct snd_card_saa7134_pcm {
+       struct saa7134_dev *saadev;
+
+       spinlock_t lock;
+       unsigned int pcm_size;          /* buffer size */
+       unsigned int pcm_count;         /* bytes per period */
+       unsigned int pcm_bps;           /* bytes per second */
+       snd_pcm_substream_t *substream;
+} snd_card_saa7134_pcm_t;
+
+static snd_card_t *snd_saa7134_cards[SNDRV_CARDS];
+
+
+/*
+ * saa7134 DMA audio stop
+ *
+ *   Called when the capture device is released or the buffer overflows
+ *
+ *   - Copied verbatim from saa7134-oss's dsp_dma_stop. Can be dropped
+ *     if we just share dsp_dma_stop and use it here
+ *
+ */
+
+static void saa7134_dma_stop(struct saa7134_dev *dev)
+
+{
+       dev->dmasound.dma_blk     = -1;
+       dev->dmasound.dma_running = 0;
+       saa7134_set_dmabits(dev);
+}
+
+/*
+ * saa7134 DMA audio start
+ *
+ *   Called when preparing the capture device for use
+ *
+ *   - Copied verbatim from saa7134-oss's dsp_dma_start. Can be dropped
+ *     if we just share dsp_dma_start and use it here
+ *
+ */
+
+static void saa7134_dma_start(struct saa7134_dev *dev)
+{
+       dev->dmasound.dma_blk     = 0;
+       dev->dmasound.dma_running = 1;
+       saa7134_set_dmabits(dev);
+}
+
+/*
+ * saa7134 audio DMA IRQ handler
+ *
+ *   Called whenever we get an SAA7134_IRQ_REPORT_DONE_RA3 interrupt
+ *   Handles shifting between the 2 buffers, manages the read counters,
+ *  and notifies ALSA when periods elapse
+ *
+ *   - Mostly copied from saa7134-oss's saa7134_irq_oss_done.
+ *
+ */
+
+void saa7134_irq_alsa_done(struct saa7134_dev *dev, unsigned long status)
+{
+       int next_blk, reg = 0;
+
+       spin_lock(&dev->slock);
+       if (UNSET == dev->dmasound.dma_blk) {
+               dprintk("irq: recording stopped\n");
+               goto done;
+       }
+       if (0 != (status & 0x0f000000))
+               dprintk("irq: lost %ld\n", (status >> 24) & 0x0f);
+       if (0 == (status & 0x10000000)) {
+               /* odd */
+               if (0 == (dev->dmasound.dma_blk & 0x01))
+                       reg = SAA7134_RS_BA1(6);
+       } else {
+               /* even */
+               if (1 == (dev->dmasound.dma_blk & 0x01))
+                       reg = SAA7134_RS_BA2(6);
+       }
+       if (0 == reg) {
+               dprintk("irq: field oops [%s]\n",
+                       (status & 0x10000000) ? "even" : "odd");
+               goto done;
+       }
+
+       if (dev->dmasound.read_count >= dev->dmasound.blksize * (dev->dmasound.blocks-2)) {
+               dprintk("irq: overrun [full=%d/%d] - Blocks in %d\n",dev->dmasound.read_count,
+                       dev->dmasound.bufsize, dev->dmasound.blocks);
+               snd_pcm_stop(dev->dmasound.substream,SNDRV_PCM_STATE_XRUN);
+               saa7134_dma_stop(dev);
+               goto done;
+       }
+
+       /* next block addr */
+       next_blk = (dev->dmasound.dma_blk + 2) % dev->dmasound.blocks;
+       saa_writel(reg,next_blk * dev->dmasound.blksize);
+       if (debug > 2)
+               dprintk("irq: ok, %s, next_blk=%d, addr=%x, blocks=%u, size=%u, read=%u\n",
+                       (status & 0x10000000) ? "even" : "odd ", next_blk,
+                       next_blk * dev->dmasound.blksize, dev->dmasound.blocks, dev->dmasound.blksize, dev->dmasound.read_count);
+
+       /* update status & wake waiting readers */
+       dev->dmasound.dma_blk = (dev->dmasound.dma_blk + 1) % dev->dmasound.blocks;
+       dev->dmasound.read_count += dev->dmasound.blksize;
+
+       dev->dmasound.recording_on = reg;
+
+       if (dev->dmasound.read_count >= snd_pcm_lib_period_bytes(dev->dmasound.substream)) {
+               spin_unlock(&dev->slock);
+               snd_pcm_period_elapsed(dev->dmasound.substream);
+               spin_lock(&dev->slock);
+       }
+ done:
+       spin_unlock(&dev->slock);
+
+}
+
+/*
+ * IRQ request handler
+ *
+ *   Runs along with saa7134's IRQ handler, discards anything that isn't
+ *   DMA sound
+ *
+ */
+
+static irqreturn_t saa7134_alsa_irq(int irq, void *dev_id, struct pt_regs *regs)
+{
+       struct saa7134_dev *dev = (struct saa7134_dev*) dev_id;
+       unsigned long report, status;
+       int loop, handled = 0;
+
+       for (loop = 0; loop < 10; loop++) {
+               report = saa_readl(SAA7134_IRQ_REPORT);
+               status = saa_readl(SAA7134_IRQ_STATUS);
+
+               if (report & SAA7134_IRQ_REPORT_DONE_RA3) {
+                       handled = 1;
+                       saa_writel(SAA7134_IRQ_REPORT,report);
+                       saa7134_irq_alsa_done(dev, status);
+               } else {
+                       goto out;
+               }
+       }
+
+       if (loop == 10) {
+               dprintk("error! looping IRQ!");
+       }
+
+out:
+       return IRQ_RETVAL(handled);
+}
+
+/*
+ * ALSA capture trigger
+ *
+ *   - One of the ALSA capture callbacks.
+ *
+ *   Called whenever a capture is started or stopped. Must be defined,
+ *   but there's nothing we want to do here
+ *
+ */
+
+static int snd_card_saa7134_capture_trigger(snd_pcm_substream_t * substream,
+                                         int cmd)
+{
+       snd_pcm_runtime_t *runtime = substream->runtime;
+       snd_card_saa7134_pcm_t *saapcm = runtime->private_data;
+       struct saa7134_dev *dev=saapcm->saadev;
+       int err = 0;
+
+       spin_lock_irq(&dev->slock);
+        if (cmd == SNDRV_PCM_TRIGGER_START) {
+               /* start dma */
+               saa7134_dma_start(dev);
+        } else if (cmd == SNDRV_PCM_TRIGGER_STOP) {
+               /* stop dma */
+               saa7134_dma_stop(dev);
+        } else {
+                err = -EINVAL;
+        }
+       spin_unlock_irq(&dev->slock);
+
+        return err;
+}
+
+/*
+ * DMA buffer config
+ *
+ *   Sets the values that will later be used as the size of the buffer,
+ *  size of the fragments, and total number of fragments.
+ *   Must be called during the preparation stage, before memory is
+ *  allocated
+ *
+ *   - Copied verbatim from saa7134-oss. Can be dropped
+ *     if we just share dsp_buffer_conf from OSS.
+ */
+
+static int dsp_buffer_conf(struct saa7134_dev *dev, int blksize, int blocks)
+{
+       if (blksize < 0x100)
+               blksize = 0x100;
+       if (blksize > 0x10000)
+               blksize = 0x10000;
+
+       if (blocks < 2)
+               blocks = 2;
+       if ((blksize * blocks) > 1024*1024)
+               blocks = 1024*1024 / blksize;
+
+       dev->dmasound.blocks  = blocks;
+       dev->dmasound.blksize = blksize;
+       dev->dmasound.bufsize = blksize * blocks;
+
+       dprintk("buffer config: %d blocks / %d bytes, %d kB total\n",
+               blocks,blksize,blksize * blocks / 1024);
+       return 0;
+}
+
+/*
+ * DMA buffer initialization
+ *
+ *   Uses V4L functions to initialize the DMA. Shouldn't be necessary in
+ *  ALSA, but I was unable to use ALSA's own DMA, and had to force the
+ *  usage of V4L's
+ *
+ *   - Copied verbatim from saa7134-oss. Can be dropped
+ *     if we just share dsp_buffer_init from OSS.
+ */
+
+static int dsp_buffer_init(struct saa7134_dev *dev)
+{
+       int err;
+
+       if (!dev->dmasound.bufsize)
+               BUG();
+       videobuf_dma_init(&dev->dmasound.dma);
+       err = videobuf_dma_init_kernel(&dev->dmasound.dma, PCI_DMA_FROMDEVICE,
+                                      (dev->dmasound.bufsize + PAGE_SIZE) >> PAGE_SHIFT);
+       if (0 != err)
+               return err;
+       return 0;
+}
+
+/*
+ * ALSA PCM preparation
+ *
+ *   - One of the ALSA capture callbacks.
+ *
+ *   Called right after the capture device is opened, this function configures
+ *  the buffer using the previously defined functions, allocates the memory,
+ *  sets up the hardware registers, and then starts the DMA. When this function
+ *  returns, the audio should be flowing.
+ *
+ */
+
+static int snd_card_saa7134_capture_prepare(snd_pcm_substream_t * substream)
+{
+       snd_pcm_runtime_t *runtime = substream->runtime;
+       int err, bswap, sign;
+       u32 fmt, control;
+       snd_card_saa7134_t *saa7134 = snd_pcm_substream_chip(substream);
+       struct saa7134_dev *dev;
+       snd_card_saa7134_pcm_t *saapcm = runtime->private_data;
+       unsigned int bps;
+       unsigned long size;
+       unsigned count;
+
+       size = snd_pcm_lib_buffer_bytes(substream);
+       count = snd_pcm_lib_period_bytes(substream);
+
+       saapcm->saadev->dmasound.substream = substream;
+       bps = runtime->rate * runtime->channels;
+       bps *= snd_pcm_format_width(runtime->format);
+       bps /= 8;
+       if (bps <= 0)
+               return -EINVAL;
+       saapcm->pcm_bps = bps;
+       saapcm->pcm_size = snd_pcm_lib_buffer_bytes(substream);
+       saapcm->pcm_count = snd_pcm_lib_period_bytes(substream);
+
+
+       dev=saa7134->saadev;
+
+       dsp_buffer_conf(dev,saapcm->pcm_count,(saapcm->pcm_size/saapcm->pcm_count));
+
+       err = dsp_buffer_init(dev);
+       if (0 != err)
+               goto fail2;
+
+       /* prepare buffer */
+       if (0 != (err = videobuf_dma_pci_map(dev->pci,&dev->dmasound.dma)))
+               return err;
+       if (0 != (err = saa7134_pgtable_alloc(dev->pci,&dev->dmasound.pt)))
+               goto fail1;
+       if (0 != (err = saa7134_pgtable_build(dev->pci,&dev->dmasound.pt,
+                                             dev->dmasound.dma.sglist,
+                                             dev->dmasound.dma.sglen,
+                                             0)))
+               goto fail2;
+
+
+
+       switch (runtime->format) {
+         case SNDRV_PCM_FORMAT_U8:
+         case SNDRV_PCM_FORMAT_S8:
+               fmt = 0x00;
+               break;
+         case SNDRV_PCM_FORMAT_U16_LE:
+         case SNDRV_PCM_FORMAT_U16_BE:
+         case SNDRV_PCM_FORMAT_S16_LE:
+         case SNDRV_PCM_FORMAT_S16_BE:
+               fmt = 0x01;
+               break;
+         default:
+               err = -EINVAL;
+               return 1;
+       }
+
+       switch (runtime->format) {
+         case SNDRV_PCM_FORMAT_S8:
+         case SNDRV_PCM_FORMAT_S16_LE:
+         case SNDRV_PCM_FORMAT_S16_BE:
+               sign = 1;
+               break;
+         default:
+               sign = 0;
+               break;
+       }
+
+       switch (runtime->format) {
+         case SNDRV_PCM_FORMAT_U16_BE:
+         case SNDRV_PCM_FORMAT_S16_BE:
+               bswap = 1; break;
+         default:
+               bswap = 0; break;
+       }
+
+       switch (dev->pci->device) {
+         case PCI_DEVICE_ID_PHILIPS_SAA7134:
+               if (1 == runtime->channels)
+                       fmt |= (1 << 3);
+               if (2 == runtime->channels)
+                       fmt |= (3 << 3);
+               if (sign)
+                       fmt |= 0x04;
+
+               fmt |= (MIXER_ADDR_TVTUNER == dev->dmasound.input) ? 0xc0 : 0x80;
+               saa_writeb(SAA7134_NUM_SAMPLES0, ((dev->dmasound.blksize - 1) & 0x0000ff));
+               saa_writeb(SAA7134_NUM_SAMPLES1, ((dev->dmasound.blksize - 1) & 0x00ff00) >>  8);
+               saa_writeb(SAA7134_NUM_SAMPLES2, ((dev->dmasound.blksize - 1) & 0xff0000) >> 16);
+               saa_writeb(SAA7134_AUDIO_FORMAT_CTRL, fmt);
+
+               break;
+         case PCI_DEVICE_ID_PHILIPS_SAA7133:
+         case PCI_DEVICE_ID_PHILIPS_SAA7135:
+               if (1 == runtime->channels)
+                       fmt |= (1 << 4);
+               if (2 == runtime->channels)
+                       fmt |= (2 << 4);
+               if (!sign)
+                       fmt |= 0x04;
+               saa_writel(SAA7133_NUM_SAMPLES, dev->dmasound.blksize -1);
+               saa_writel(SAA7133_AUDIO_CHANNEL, 0x543210 | (fmt << 24));
+               //saa_writel(SAA7133_AUDIO_CHANNEL, 0x543210);
+               break;
+       }
+
+       dprintk("rec_start: afmt=%d ch=%d  =>  fmt=0x%x swap=%c\n",
+               runtime->format, runtime->channels, fmt,
+               bswap ? 'b' : '-');
+       /* dma: setup channel 6 (= AUDIO) */
+       control = SAA7134_RS_CONTROL_BURST_16 |
+               SAA7134_RS_CONTROL_ME |
+               (dev->dmasound.pt.dma >> 12);
+       if (bswap)
+               control |= SAA7134_RS_CONTROL_BSWAP;
+
+       /* I should be able to use runtime->dma_addr in the control
+          byte, but it doesn't work. So I allocate the DMA using the
+          V4L functions, and force ALSA to use that as the DMA area */
+
+       runtime->dma_area = dev->dmasound.dma.vmalloc;
+
+       saa_writel(SAA7134_RS_BA1(6),0);
+       saa_writel(SAA7134_RS_BA2(6),dev->dmasound.blksize);
+       saa_writel(SAA7134_RS_PITCH(6),0);
+       saa_writel(SAA7134_RS_CONTROL(6),control);
+
+       dev->dmasound.rate = runtime->rate;
+
+       return 0;
+ fail2:
+       saa7134_pgtable_free(dev->pci,&dev->dmasound.pt);
+ fail1:
+       videobuf_dma_pci_unmap(dev->pci,&dev->dmasound.dma);
+       return err;
+
+
+}
+
+/*
+ * ALSA pointer fetching
+ *
+ *   - One of the ALSA capture callbacks.
+ *
+ *   Called whenever a period elapses, it must return the current hardware
+ *  position of the buffer.
+ *   Also resets the read counter used to prevent overruns
+ *
+ */
+
+static snd_pcm_uframes_t snd_card_saa7134_capture_pointer(snd_pcm_substream_t * substream)
+{
+       snd_pcm_runtime_t *runtime = substream->runtime;
+       snd_card_saa7134_pcm_t *saapcm = runtime->private_data;
+       struct saa7134_dev *dev=saapcm->saadev;
+
+
+
+       if (dev->dmasound.read_count) {
+               dev->dmasound.read_count  -= snd_pcm_lib_period_bytes(substream);
+               dev->dmasound.read_offset += snd_pcm_lib_period_bytes(substream);
+               if (dev->dmasound.read_offset == dev->dmasound.bufsize)
+                       dev->dmasound.read_offset = 0;
+       }
+
+       return bytes_to_frames(runtime, dev->dmasound.read_offset);
+}
+
+/*
+ * ALSA hardware capabilities definition
+ */
+
+static snd_pcm_hardware_t snd_card_saa7134_capture =
+{
+       .info =                 (SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_INTERLEAVED |
+                                SNDRV_PCM_INFO_BLOCK_TRANSFER |
+                                SNDRV_PCM_INFO_MMAP_VALID),
+       .formats =              SNDRV_PCM_FMTBIT_S16_LE | \
+                               SNDRV_PCM_FMTBIT_S16_BE | \
+                               SNDRV_PCM_FMTBIT_S8 | \
+                               SNDRV_PCM_FMTBIT_U8 | \
+                               SNDRV_PCM_FMTBIT_U16_LE | \
+                               SNDRV_PCM_FMTBIT_U16_BE,
+       .rates =                SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_48000,
+       .rate_min =             32000,
+       .rate_max =             48000,
+       .channels_min =         1,
+       .channels_max =         2,
+       .buffer_bytes_max =     (256*1024),
+       .period_bytes_min =     64,
+       .period_bytes_max =     (256*1024),
+       .periods_min =          2,
+       .periods_max =          1024,
+};
+
+static void snd_card_saa7134_runtime_free(snd_pcm_runtime_t *runtime)
+{
+       snd_card_saa7134_pcm_t *saapcm = runtime->private_data;
+
+       kfree(saapcm);
+}
+
+
+/*
+ * ALSA hardware params
+ *
+ *   - One of the ALSA capture callbacks.
+ *
+ *   Called on initialization, right before the PCM preparation
+ *   Usually used in ALSA to allocate the DMA, but since we don't use the
+ *  ALSA DMA it does nothing
+ *
+ */
+
+static int snd_card_saa7134_hw_params(snd_pcm_substream_t * substream,
+                                   snd_pcm_hw_params_t * hw_params)
+{
+
+       return 0;
+
+
+}
+
+/*
+ * ALSA hardware release
+ *
+ *   - One of the ALSA capture callbacks.
+ *
+ *   Called after closing the device, but before snd_card_saa7134_capture_close
+ *   Usually used in ALSA to free the DMA, but since we don't use the
+ *  ALSA DMA I'm almost sure this isn't necessary.
+ *
+ */
+
+static int snd_card_saa7134_hw_free(snd_pcm_substream_t * substream)
+{
+       return 0;
+}
+
+/*
+ * DMA buffer release
+ *
+ *   Called after closing the device, during snd_card_saa7134_capture_close
+ *
+ */
+
+static int dsp_buffer_free(struct saa7134_dev *dev)
+{
+       if (!dev->dmasound.blksize)
+               BUG();
+
+       videobuf_dma_free(&dev->dmasound.dma);
+
+       dev->dmasound.blocks  = 0;
+       dev->dmasound.blksize = 0;
+       dev->dmasound.bufsize = 0;
+
+       return 0;
+}
+
+/*
+ * ALSA capture finish
+ *
+ *   - One of the ALSA capture callbacks.
+ *
+ *   Called after closing the device. It stops the DMA audio and releases
+ *  the buffers
+ *
+ */
+
+static int snd_card_saa7134_capture_close(snd_pcm_substream_t * substream)
+{
+       snd_card_saa7134_t *chip = snd_pcm_substream_chip(substream);
+       struct saa7134_dev *dev = chip->saadev;
+
+       /* unlock buffer */
+       saa7134_pgtable_free(dev->pci,&dev->dmasound.pt);
+       videobuf_dma_pci_unmap(dev->pci,&dev->dmasound.dma);
+
+       dsp_buffer_free(dev);
+       return 0;
+}
+
+/*
+ * ALSA capture start
+ *
+ *   - One of the ALSA capture callbacks.
+ *
+ *   Called when opening the device. It creates and populates the PCM
+ *  structure
+ *
+ */
+
+static int snd_card_saa7134_capture_open(snd_pcm_substream_t * substream)
+{
+       snd_pcm_runtime_t *runtime = substream->runtime;
+       snd_card_saa7134_pcm_t *saapcm;
+       snd_card_saa7134_t *saa7134 = snd_pcm_substream_chip(substream);
+       struct saa7134_dev *dev = saa7134->saadev;
+       int err;
+
+       down(&dev->dmasound.lock);
+
+       dev->dmasound.afmt        = SNDRV_PCM_FORMAT_U8;
+       dev->dmasound.channels    = 2;
+       dev->dmasound.read_count  = 0;
+       dev->dmasound.read_offset = 0;
+
+       up(&dev->dmasound.lock);
+
+       saapcm = kzalloc(sizeof(*saapcm), GFP_KERNEL);
+       if (saapcm == NULL)
+               return -ENOMEM;
+       saapcm->saadev=saa7134->saadev;
+
+       spin_lock_init(&saapcm->lock);
+
+       saapcm->substream = substream;
+       runtime->private_data = saapcm;
+       runtime->private_free = snd_card_saa7134_runtime_free;
+       runtime->hw = snd_card_saa7134_capture;
+
+       if ((err = snd_pcm_hw_constraint_integer(runtime, SNDRV_PCM_HW_PARAM_PERIODS)) < 0)
+               return err;
+
+       return 0;
+}
+
+/*
+ * ALSA capture callbacks definition
+ */
+
+static snd_pcm_ops_t snd_card_saa7134_capture_ops = {
+       .open =                 snd_card_saa7134_capture_open,
+       .close =                snd_card_saa7134_capture_close,
+       .ioctl =                snd_pcm_lib_ioctl,
+       .hw_params =            snd_card_saa7134_hw_params,
+       .hw_free =              snd_card_saa7134_hw_free,
+       .prepare =              snd_card_saa7134_capture_prepare,
+       .trigger =              snd_card_saa7134_capture_trigger,
+       .pointer =              snd_card_saa7134_capture_pointer,
+};
+
+/*
+ * ALSA PCM setup
+ *
+ *   Called when initializing the board. Sets up the name and hooks up
+ *  the callbacks
+ *
+ */
+
+static int snd_card_saa7134_pcm(snd_card_saa7134_t *saa7134, int device)
+{
+       snd_pcm_t *pcm;
+       int err;
+
+       if ((err = snd_pcm_new(saa7134->card, "SAA7134 PCM", device, 0, 1, &pcm)) < 0)
+               return err;
+       snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &snd_card_saa7134_capture_ops);
+       pcm->private_data = saa7134;
+       pcm->info_flags = 0;
+       strcpy(pcm->name, "SAA7134 PCM");
+       return 0;
+}
+
+#define SAA713x_VOLUME(xname, xindex, addr) \
+{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = xindex, \
+  .info = snd_saa7134_volume_info, \
+  .get = snd_saa7134_volume_get, .put = snd_saa7134_volume_put, \
+  .private_value = addr }
+
+static int snd_saa7134_volume_info(snd_kcontrol_t * kcontrol, snd_ctl_elem_info_t * uinfo)
+{
+       uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
+       uinfo->count = 2;
+       uinfo->value.integer.min = 0;
+       uinfo->value.integer.max = 20;
+       return 0;
+}
+
+static int snd_saa7134_volume_get(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol)
+{
+       snd_card_saa7134_t *chip = snd_kcontrol_chip(kcontrol);
+       int addr = kcontrol->private_value;
+
+       ucontrol->value.integer.value[0] = chip->mixer_volume[addr][0];
+       ucontrol->value.integer.value[1] = chip->mixer_volume[addr][1];
+       return 0;
+}
+
+static int snd_saa7134_volume_put(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol)
+{
+       snd_card_saa7134_t *chip = snd_kcontrol_chip(kcontrol);
+       unsigned long flags;
+       int change, addr = kcontrol->private_value;
+       int left, right;
+
+       left = ucontrol->value.integer.value[0];
+       if (left < 0)
+               left = 0;
+       if (left > 20)
+               left = 20;
+       right = ucontrol->value.integer.value[1];
+       if (right < 0)
+               right = 0;
+       if (right > 20)
+               right = 20;
+       spin_lock_irqsave(&chip->mixer_lock, flags);
+       change = chip->mixer_volume[addr][0] != left ||
+                chip->mixer_volume[addr][1] != right;
+       chip->mixer_volume[addr][0] = left;
+       chip->mixer_volume[addr][1] = right;
+       spin_unlock_irqrestore(&chip->mixer_lock, flags);
+       return change;
+}
+
+#define SAA713x_CAPSRC(xname, xindex, addr) \
+{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = xindex, \
+  .info = snd_saa7134_capsrc_info, \
+  .get = snd_saa7134_capsrc_get, .put = snd_saa7134_capsrc_put, \
+  .private_value = addr }
+
+static int snd_saa7134_capsrc_info(snd_kcontrol_t * kcontrol, snd_ctl_elem_info_t * uinfo)
+{
+       uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN;
+       uinfo->count = 2;
+       uinfo->value.integer.min = 0;
+       uinfo->value.integer.max = 1;
+       return 0;
+}
+
+static int snd_saa7134_capsrc_get(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol)
+{
+       snd_card_saa7134_t *chip = snd_kcontrol_chip(kcontrol);
+       unsigned long flags;
+       int addr = kcontrol->private_value;
+
+       spin_lock_irqsave(&chip->mixer_lock, flags);
+       ucontrol->value.integer.value[0] = chip->capture_source[addr][0];
+       ucontrol->value.integer.value[1] = chip->capture_source[addr][1];
+       spin_unlock_irqrestore(&chip->mixer_lock, flags);
+       return 0;
+}
+
+static int snd_saa7134_capsrc_put(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol)
+{
+       snd_card_saa7134_t *chip = snd_kcontrol_chip(kcontrol);
+       unsigned long flags;
+       int change, addr = kcontrol->private_value;
+       int left, right;
+       u32 anabar, xbarin;
+       int analog_io, rate;
+       struct saa7134_dev *dev;
+
+       dev = chip->saadev;
+
+       left = ucontrol->value.integer.value[0] & 1;
+       right = ucontrol->value.integer.value[1] & 1;
+       spin_lock_irqsave(&chip->mixer_lock, flags);
+
+       change = chip->capture_source[addr][0] != left ||
+                chip->capture_source[addr][1] != right;
+       chip->capture_source[addr][0] = left;
+       chip->capture_source[addr][1] = right;
+       dev->dmasound.input=addr;
+       spin_unlock_irqrestore(&chip->mixer_lock, flags);
+
+
+       if (change) {
+         switch (dev->pci->device) {
+
+          case PCI_DEVICE_ID_PHILIPS_SAA7134:
+               switch (addr) {
+                       case MIXER_ADDR_TVTUNER:
+                               saa_andorb(SAA7134_AUDIO_FORMAT_CTRL, 0xc0, 0xc0);
+                               saa_andorb(SAA7134_SIF_SAMPLE_FREQ,   0x03, 0x00);
+                               break;
+                       case MIXER_ADDR_LINE1:
+                       case MIXER_ADDR_LINE2:
+                               analog_io = (MIXER_ADDR_LINE1 == addr) ? 0x00 : 0x08;
+                               rate = (32000 == dev->dmasound.rate) ? 0x01 : 0x03;
+                               saa_andorb(SAA7134_ANALOG_IO_SELECT,  0x08, analog_io);
+                               saa_andorb(SAA7134_AUDIO_FORMAT_CTRL, 0xc0, 0x80);
+                               saa_andorb(SAA7134_SIF_SAMPLE_FREQ,   0x03, rate);
+                               break;
+               }
+
+               break;
+          case PCI_DEVICE_ID_PHILIPS_SAA7133:
+          case PCI_DEVICE_ID_PHILIPS_SAA7135:
+               xbarin = 0x03; // adc
+               anabar = 0;
+               switch (addr) {
+                       case MIXER_ADDR_TVTUNER:
+                               xbarin = 0; // Demodulator
+                               anabar = 2; // DACs
+                               break;
+                       case MIXER_ADDR_LINE1:
+                               anabar = 0;  // aux1, aux1
+                               break;
+                       case MIXER_ADDR_LINE2:
+                               anabar = 9;  // aux2, aux2
+                               break;
+               }
+
+               /* output xbar always main channel */
+               saa_dsp_writel(dev, SAA7133_DIGITAL_OUTPUT_SEL1, 0xbbbb10);
+
+               if (left || right) { // We've got data, turn the input on
+                 saa_dsp_writel(dev, SAA7133_DIGITAL_INPUT_XBAR1, xbarin);
+                 saa_writel(SAA7133_ANALOG_IO_SELECT, anabar);
+               } else {
+                 saa_dsp_writel(dev, SAA7133_DIGITAL_INPUT_XBAR1, 0);
+                 saa_writel(SAA7133_ANALOG_IO_SELECT, 0);
+               }
+               break;
+         }
+       }
+
+       return change;
+}
+
+static snd_kcontrol_new_t snd_saa7134_controls[] = {
+SAA713x_VOLUME("Video Volume", 0, MIXER_ADDR_TVTUNER),
+SAA713x_CAPSRC("Video Capture Switch", 0, MIXER_ADDR_TVTUNER),
+SAA713x_VOLUME("Line Volume", 1, MIXER_ADDR_LINE1),
+SAA713x_CAPSRC("Line Capture Switch", 1, MIXER_ADDR_LINE1),
+SAA713x_VOLUME("Line Volume", 2, MIXER_ADDR_LINE2),
+SAA713x_CAPSRC("Line Capture Switch", 2, MIXER_ADDR_LINE2),
+};
+
+/*
+ * ALSA mixer setup
+ *
+ *   Called when initializing the board. Sets up the name and hooks up
+ *  the callbacks
+ *
+ */
+
+static int snd_card_saa7134_new_mixer(snd_card_saa7134_t * chip)
+{
+       snd_card_t *card = chip->card;
+       unsigned int idx;
+       int err;
+
+       snd_assert(chip != NULL, return -EINVAL);
+       strcpy(card->mixername, "SAA7134 Mixer");
+
+       for (idx = 0; idx < ARRAY_SIZE(snd_saa7134_controls); idx++) {
+               if ((err = snd_ctl_add(card, snd_ctl_new1(&snd_saa7134_controls[idx], chip))) < 0)
+                       return err;
+       }
+       return 0;
+}
+
+static int snd_saa7134_free(snd_card_saa7134_t *chip)
+{
+       return 0;
+}
+
+static int snd_saa7134_dev_free(snd_device_t *device)
+{
+       snd_card_saa7134_t *chip = device->device_data;
+       return snd_saa7134_free(chip);
+}
+
+/*
+ * ALSA initialization
+ *
+ *   Called by saa7134-core, it creates the basic structures and registers
+ *  the ALSA devices
+ *
+ */
+
+int alsa_card_saa7134_create (struct saa7134_dev *saadev)
+{
+       static int dev;
+
+       snd_card_t *card;
+       snd_card_saa7134_t *chip;
+       int err;
+       static snd_device_ops_t ops = {
+               .dev_free =     snd_saa7134_dev_free,
+       };
+
+
+       if (dev >= SNDRV_CARDS)
+               return -ENODEV;
+       if (!enable[dev])
+               return -ENODEV;
+
+       card = snd_card_new(index[dev], id[dev], THIS_MODULE, 0);
+
+       if (card == NULL)
+               return -ENOMEM;
+
+       strcpy(card->driver, "SAA7134");
+
+       /* Card "creation" */
+
+       chip = kcalloc(1, sizeof(*chip), GFP_KERNEL);
+       if (chip == NULL) {
+               return -ENOMEM;
+       }
+
+       spin_lock_init(&chip->lock);
+       spin_lock_init(&chip->mixer_lock);
+
+       chip->saadev = saadev;
+
+       chip->card = card;
+
+       chip->pci = saadev->pci;
+       chip->irq = saadev->pci->irq;
+       chip->iobase = pci_resource_start(saadev->pci, 0);
+
+       err = request_irq(saadev->pci->irq, saa7134_alsa_irq,
+                               SA_SHIRQ | SA_INTERRUPT, saadev->name, saadev);
+
+       if (err < 0) {
+               printk(KERN_ERR "%s: can't get IRQ %d for ALSA\n",
+                       saadev->name, saadev->pci->irq);
+               goto __nodev;
+       }
+
+       if ((err = snd_device_new(card, SNDRV_DEV_LOWLEVEL, chip, &ops)) < 0) {
+               goto __nodev;
+       }
+
+       if ((err = snd_card_saa7134_new_mixer(chip)) < 0)
+               goto __nodev;
+
+       if ((err = snd_card_saa7134_pcm(chip, 0)) < 0)
+               goto __nodev;
+
+       snd_card_set_dev(card, &chip->pci->dev);
+
+       /* End of "creation" */
+
+       strcpy(card->shortname, "SAA7134");
+       sprintf(card->longname, "%s at 0x%lx irq %d",
+               chip->saadev->name, chip->iobase, chip->irq);
+
+       if ((err = snd_card_register(card)) == 0) {
+               snd_saa7134_cards[dev] = card;
+               return 0;
+       }
+
+__nodev:
+       snd_card_free(card);
+       kfree(chip);
+       return err;
+}
+
+/*
+ * Module initializer
+ *
+ * Loops through present saa7134 cards, and assigns an ALSA device
+ * to each one
+ *
+ */
+
+static int saa7134_alsa_init(void)
+{
+        struct saa7134_dev *saadev = NULL;
+        struct list_head *list;
+
+       printk(KERN_INFO "saa7134 ALSA driver for DMA sound loaded\n");
+
+        list_for_each(list,&saa7134_devlist) {
+                saadev = list_entry(list, struct saa7134_dev, devlist);
+               alsa_card_saa7134_create(saadev);
+        }
+
+       if (saadev == NULL)
+               printk(KERN_INFO "saa7134 ALSA: no saa7134 cards found\n");
+
+       return 0;
+
+}
+
+/*
+ * Module destructor
+ */
+
+void saa7134_alsa_exit(void)
+{
+       int idx;
+
+       for (idx = 0; idx < SNDRV_CARDS; idx++) {
+               snd_card_free(snd_saa7134_cards[idx]);
+       }
+
+       printk(KERN_INFO "saa7134 ALSA driver for DMA sound unloaded\n");
+
+       return;
+}
+
+module_init(saa7134_alsa_init);
+module_exit(saa7134_alsa_exit);
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Ricardo Cerqueira");
index acc7a4335e230ec3514ad06923fe0adba74f4af0..663d03e5bc67331fced022c7143953e93d184adc 100644 (file)
@@ -191,9 +191,13 @@ struct saa7134_board saa7134_boards[] = {
                        .amux = TV,
                        .tv   = 1,
                },{
-                       .name = name_comp1,
+                       .name = name_comp1,     /* Composite signal on S-Video input */
                        .vmux = 0,
                        .amux = LINE2,
+               },{
+                       .name = name_comp2,     /* Composite input */
+                       .vmux = 3,
+                       .amux = LINE2,
                },{
                        .name = name_svideo,
                        .vmux = 8,
@@ -2109,8 +2113,423 @@ struct saa7134_board saa7134_boards[] = {
                        .gpio = 0x01,
                },
        },
-};
+       [SAA7134_BOARD_BEHOLD_409FM] = {
+               /* <http://tuner.beholder.ru>, Sergey <skiv@orel.ru> */
+               .name           = "Beholder BeholdTV 409 FM",
+               .audio_clock    = 0x00187de7,
+               .tuner_type     = TUNER_PHILIPS_FM1216ME_MK3,
+               .radio_type     = UNSET,
+               .tuner_addr     = ADDR_UNSET,
+               .radio_addr     = ADDR_UNSET,
+               .tda9887_conf   = TDA9887_PRESENT,
+               .inputs         = {{
+                         .name = name_tv,
+                         .vmux = 3,
+                         .amux = TV,
+                         .tv   = 1,
+               },{
+                         .name = name_comp1,
+                         .vmux = 1,
+                         .amux = LINE1,
+               },{
+                         .name = name_svideo,
+                         .vmux = 8,
+                         .amux = LINE1,
+               }},
+               .radio = {
+                         .name = name_radio,
+                         .amux = LINE2,
+               },
+       },
+       [SAA7134_BOARD_GOTVIEW_7135] = {
+               /* Mike Baikov <mike@baikov.com> */
+               /* Andrey Cvetcov <ays14@yandex.ru> */
+               .name            = "GoTView 7135 PCI",
+               .audio_clock     = 0x00187de7,
+               .tuner_type      = TUNER_PHILIPS_FM1216ME_MK3,
+               .radio_type      = UNSET,
+               .tuner_addr      = ADDR_UNSET,
+               .radio_addr      = ADDR_UNSET,
+               .tda9887_conf    = TDA9887_PRESENT,
+               .gpiomask        = 0x00200003,
+               .inputs          = {{
+                       .name = name_tv,
+                       .vmux = 1,
+                       .amux = TV,
+                       .tv   = 1,
+                       .gpio = 0x00200003,
+               },{
+                       .name = name_tv_mono,
+                       .vmux = 1,
+                       .amux = LINE2,
+                       .gpio = 0x00200003,
+               },{
+                       .name = name_comp1,
+                       .vmux = 3,
+                       .amux = LINE1,
+                       .gpio = 0x00200003,
+               },{
+                       .name = name_svideo,
+                       .vmux = 8,
+                       .amux = LINE1,
+                       .gpio = 0x00200003,
+               }},
+               .radio = {
+                       .name = name_radio,
+                       .amux = LINE2,
+                       .gpio = 0x00200003,
+               },
+               .mute = {
+                       .name = name_mute,
+                       .amux = TV,
+                       .gpio = 0x00200003,
+               },
+       },
+       [SAA7134_BOARD_PHILIPS_EUROPA] = {
+               .name           = "Philips EUROPA V3 reference design",
+               .audio_clock    = 0x00187de7,
+               .tuner_type     = TUNER_PHILIPS_TD1316,
+               .radio_type     = UNSET,
+               .tuner_addr     = 0x61,
+               .radio_addr     = ADDR_UNSET,
+               .tda9887_conf   = TDA9887_PRESENT,
+               .mpeg           = SAA7134_MPEG_DVB,
+               .inputs = {{
+                       .name   = name_tv,
+                       .vmux   = 3,
+                       .amux   = TV,
+                       .tv     = 1,
+               },{
+                       .name   = name_comp1,
+                       .vmux   = 0,
+                       .amux   = LINE2,
+               },{
+                       .name   = name_svideo,
+                       .vmux   = 8,
+                       .amux   = LINE2,
+               }},
+       },
+       [SAA7134_BOARD_VIDEOMATE_DVBT_300] = {
+               .name           = "Compro Videomate DVB-T300",
+               .audio_clock    = 0x00187de7,
+               .tuner_type     = TUNER_PHILIPS_TD1316,
+               .radio_type     = UNSET,
+               .tuner_addr     = 0x61,
+               .radio_addr     = ADDR_UNSET,
+               .tda9887_conf   = TDA9887_PRESENT,
+               .mpeg           = SAA7134_MPEG_DVB,
+               .inputs = {{
+                       .name   = name_tv,
+                       .vmux   = 3,
+                       .amux   = TV,
+                       .tv     = 1,
+               },{
+                       .name   = name_comp1,
+                       .vmux   = 1,
+                       .amux   = LINE2,
+               },{
+                       .name   = name_svideo,
+                       .vmux   = 8,
+                       .amux   = LINE2,
+               }},
+       },
+       [SAA7134_BOARD_VIDEOMATE_DVBT_200] = {
+               .name           = "Compro Videomate DVB-T200",
+               .tuner_type     = TUNER_ABSENT,
+               .audio_clock    = 0x00187de7,
+               .radio_type     = UNSET,
+               .tuner_addr     = ADDR_UNSET,
+               .radio_addr     = ADDR_UNSET,
+               .mpeg           = SAA7134_MPEG_DVB,
+               .inputs = {{
+                       .name   = name_comp1,
+                       .vmux   = 0,
+                       .amux   = LINE1,
+               },{
+                       .name   = name_svideo,
+                       .vmux   = 8,
+                       .amux   = LINE1,
+               }},
+       },
+       [SAA7134_BOARD_RTD_VFG7350] = {
+               .name           = "RTD Embedded Technologies VFG7350",
+               .audio_clock    = 0x00200000,
+               .tuner_type     = TUNER_ABSENT,
+               .radio_type     = UNSET,
+               .tuner_addr     = ADDR_UNSET,
+               .radio_addr     = ADDR_UNSET,
+               .inputs         = {{
+                       .name   = "Composite 0",
+                       .vmux   = 0,
+                       .amux   = LINE1,
+               },{
+                       .name   = "Composite 1",
+                       .vmux   = 1,
+                       .amux   = LINE2,
+               },{
+                       .name   = "Composite 2",
+                       .vmux   = 2,
+                       .amux   = LINE1,
+               },{
+                       .name   = "Composite 3",
+                       .vmux   = 3,
+                       .amux   = LINE2,
+               },{
+                       .name   = "S-Video 0",
+                       .vmux   = 8,
+                       .amux   = LINE1,
+               },{
+                       .name   = "S-Video 1",
+                       .vmux   = 9,
+                       .amux   = LINE2,
+               }},
+               .mpeg           = SAA7134_MPEG_EMPRESS,
+               .video_out      = CCIR656,
+               .vid_port_opts  = ( SET_T_CODE_POLARITY_NON_INVERTED |
+                                   SET_CLOCK_NOT_DELAYED |
+                                   SET_CLOCK_INVERTED |
+                                   SET_VSYNC_OFF ),
+       },
+       [SAA7134_BOARD_RTD_VFG7330] = {
+               .name           = "RTD Embedded Technologies VFG7330",
+               .audio_clock    = 0x00200000,
+               .tuner_type     = TUNER_ABSENT,
+               .radio_type     = UNSET,
+               .tuner_addr     = ADDR_UNSET,
+               .radio_addr     = ADDR_UNSET,
+               .inputs         = {{
+                       .name   = "Composite 0",
+                       .vmux   = 0,
+                       .amux   = LINE1,
+               },{
+                       .name   = "Composite 1",
+                       .vmux   = 1,
+                       .amux   = LINE2,
+               },{
+                       .name   = "Composite 2",
+                       .vmux   = 2,
+                       .amux   = LINE1,
+               },{
+                       .name   = "Composite 3",
+                       .vmux   = 3,
+                       .amux   = LINE2,
+               },{
+                       .name   = "S-Video 0",
+                       .vmux   = 8,
+                       .amux   = LINE1,
+               },{
+                       .name   = "S-Video 1",
+                       .vmux   = 9,
+                       .amux   = LINE2,
+               }},
+       },
+       [SAA7134_BOARD_FLYTVPLATINUM_MINI2] = {
+               .name           = "LifeView FlyTV Platinum Mini2",
+               .audio_clock    = 0x00200000,
+               .tuner_type     = TUNER_PHILIPS_TDA8290,
+               .radio_type     = UNSET,
+               .tuner_addr     = ADDR_UNSET,
+               .radio_addr     = ADDR_UNSET,
 
+               .inputs         = {{
+                       .name = name_tv,
+                       .vmux = 1,
+                       .amux = TV,
+                       .tv   = 1,
+               },{
+                       .name = name_comp1,     /* Composite signal on S-Video input */
+                       .vmux = 0,
+                       .amux = LINE2,
+               },{
+                       .name = name_comp2,     /* Composite input */
+                       .vmux = 3,
+                       .amux = LINE2,
+               },{
+                       .name = name_svideo,
+                       .vmux = 8,
+                       .amux = LINE2,
+               }},
+       },
+       [SAA7134_BOARD_AVERMEDIA_AVERTVHD_A180] = {
+               /* Michael Krufky <mkrufky@m1k.net>
+                * Uses Alps Electric TDHU2, containing NXT2004 ATSC Decoder
+                * AFAIK, there is no analog demod, thus,
+                * no support for analog television.
+                */
+               .name           = "AVerMedia AVerTVHD MCE A180",
+               .audio_clock    = 0x00187de7,
+               .tuner_type     = TUNER_ABSENT,
+               .radio_type     = UNSET,
+               .tuner_addr     = ADDR_UNSET,
+               .radio_addr     = ADDR_UNSET,
+               .mpeg           = SAA7134_MPEG_DVB,
+               .inputs         = {{
+                       .name = name_comp1,
+                       .vmux = 3,
+                       .amux = LINE2,
+               },{
+                       .name = name_svideo,
+                       .vmux = 8,
+                       .amux = LINE2,
+               }},
+       },
+       [SAA7134_BOARD_MONSTERTV_MOBILE] = {
+               .name           = "SKNet MonsterTV Mobile",
+               .audio_clock    = 0x00187de7,
+               .tuner_type     = TUNER_PHILIPS_TDA8290,
+               .radio_type     = UNSET,
+               .tuner_addr     = ADDR_UNSET,
+               .radio_addr     = ADDR_UNSET,
+
+               .inputs         = {{
+                         .name = name_tv,
+                         .vmux = 1,
+                         .amux = TV,
+                         .tv   = 1,
+               },{
+                         .name = name_comp1,
+                         .vmux = 3,
+                         .amux = LINE1,
+               },{
+                         .name = name_svideo,
+                         .vmux = 6,
+                         .amux = LINE1,
+               }},
+       },
+       [SAA7134_BOARD_PINNACLE_PCTV_110i] = {
+               .name           = "Pinnacle PCTV 110i (saa7133)",
+               .audio_clock    = 0x00187de7,
+               .tuner_type     = TUNER_PHILIPS_TDA8290,
+               .radio_type     = UNSET,
+               .tuner_addr     = ADDR_UNSET,
+               .radio_addr     = ADDR_UNSET,
+               .gpiomask       = 0x080200000,
+               .inputs         = {{
+                         .name = name_tv,
+                         .vmux = 4,
+                         .amux = TV,
+                         .tv   = 1,
+               },{
+                         .name = name_comp1,
+                         .vmux = 1,
+                         .amux = LINE2,
+               },{
+                         .name = name_svideo,
+                         .vmux = 8,
+                         .amux = LINE2,
+               }},
+               .radio = {
+                         .name = name_radio,
+                         .amux = LINE1,
+               },
+       },
+       [SAA7134_BOARD_ASUSTeK_P7131_DUAL] = {
+               .name           = "ASUSTeK P7131 Dual",
+               .audio_clock    = 0x00187de7,
+               .tuner_type     = TUNER_PHILIPS_TDA8290,
+               .radio_type     = UNSET,
+               .tuner_addr     = ADDR_UNSET,
+               .radio_addr     = ADDR_UNSET,
+               .gpiomask       = 1 << 21,
+               .mpeg           = SAA7134_MPEG_DVB,
+               .inputs         = {{
+                       .name = name_tv,
+                       .vmux = 1,
+                       .amux = TV,
+                       .tv   = 1,
+               },{
+                       .name = name_comp1,
+                       .vmux = 3,
+                       .amux = LINE2,
+               },{
+                       .name = name_svideo,
+                       .vmux = 8,
+                       .amux = LINE2,
+               }},
+               .radio = {
+                       .name = name_radio,
+                       .amux = TV,
+                       .gpio = 0x0200000,
+               },
+       },
+       [SAA7134_BOARD_SEDNA_PC_TV_CARDBUS] = {
+               /* Paul Tom Zalac <pzalac@gmail.com> */
+               /* Pavel Mihaylov <bin@bash.info> */
+               .name           = "Sedna/MuchTV PC TV Cardbus TV/Radio (ITO25 Rev:2B)",
+                               /* Sedna/MuchTV (OEM) Cardbus TV Tuner */
+               .audio_clock    = 0x00187de7,
+               .tuner_type     = TUNER_PHILIPS_TDA8290,
+               .radio_type     = UNSET,
+               .tuner_addr     = ADDR_UNSET,
+               .radio_addr     = ADDR_UNSET,
+               .gpiomask       = 0xe880c0,
+               .inputs         = {{
+                       .name = name_tv,
+                       .vmux = 3,
+                       .amux = TV,
+                       .tv   = 1,
+               },{
+                       .name = name_comp1,
+                       .vmux = 1,
+                       .amux = LINE1,
+               },{
+                       .name = name_svideo,
+                       .vmux = 6,
+                       .amux = LINE1,
+               }},
+               .radio = {
+                       .name = name_radio,
+                       .amux = LINE2,
+               },
+       },
+       [SAA7134_BOARD_ASUSTEK_DIGIMATRIX_TV] = {
+               /* "Cyril Lacoux (Yack)" <clacoux@ifeelgood.org> */
+               .name           = "ASUS Digimatrix TV",
+               .audio_clock    = 0x00200000,
+               .tuner_type     = TUNER_PHILIPS_FQ1216ME,
+               .tda9887_conf   = TDA9887_PRESENT,
+               .radio_type     = UNSET,
+               .tuner_addr     = ADDR_UNSET,
+               .radio_addr     = ADDR_UNSET,
+               .inputs         = {{
+                       .name = name_tv,
+                       .vmux = 1,
+                       .amux = TV,
+                       .tv   = 1,
+               },{
+                       .name = name_comp1,
+                       .vmux = 3,
+                       .amux = LINE1,
+               },{
+                       .name = name_svideo,
+                       .vmux = 8,
+                       .amux = LINE1,
+               }},
+       },
+       [SAA7134_BOARD_PHILIPS_TIGER] = {
+               .name           = "Philips Tiger reference design",
+               .audio_clock    = 0x00187de7,
+               .tuner_type     = TUNER_PHILIPS_TDA8290,
+               .radio_type     = UNSET,
+               .tuner_addr     = ADDR_UNSET,
+               .radio_addr     = ADDR_UNSET,
+               .mpeg           = SAA7134_MPEG_DVB,
+               .inputs = {{
+                       .name   = name_tv,
+                       .vmux   = 1,
+                       .amux   = TV,
+                       .tv     = 1,
+               },{
+                       .name   = name_comp1,
+                       .vmux   = 3,
+                       .amux   = LINE1,
+               },{
+                       .name   = name_svideo,
+                       .vmux   = 8,
+                       .amux   = LINE1,
+               }},
+       },
+};
 
 const unsigned int saa7134_bcount = ARRAY_SIZE(saa7134_boards);
 
@@ -2145,19 +2564,19 @@ struct pci_device_id saa7134_pci_tbl[] = {
        },{
                .vendor       = PCI_VENDOR_ID_PHILIPS,
                .device       = PCI_DEVICE_ID_PHILIPS_SAA7134,
-               .subvendor    = 0x153B,
+               .subvendor    = 0x153b,
                .subdevice    = 0x1142,
                .driver_data  = SAA7134_BOARD_CINERGY400,
        },{
                .vendor       = PCI_VENDOR_ID_PHILIPS,
                .device       = PCI_DEVICE_ID_PHILIPS_SAA7134,
-               .subvendor    = 0x153B,
+               .subvendor    = 0x153b,
                .subdevice    = 0x1143,
                .driver_data  = SAA7134_BOARD_CINERGY600,
        },{
                .vendor       = PCI_VENDOR_ID_PHILIPS,
                .device       = PCI_DEVICE_ID_PHILIPS_SAA7134,
-               .subvendor    = 0x153B,
+               .subvendor    = 0x153b,
                .subdevice    = 0x1158,
                .driver_data  = SAA7134_BOARD_CINERGY600_MK3,
        },{
@@ -2190,6 +2609,18 @@ struct pci_device_id saa7134_pci_tbl[] = {
                .subvendor    = 0x5168,
                .subdevice    = 0x0212, /* minipci, LR212 */
                .driver_data  = SAA7134_BOARD_FLYTVPLATINUM_MINI,
+       },{
+               .vendor       = PCI_VENDOR_ID_PHILIPS,
+               .device       = PCI_DEVICE_ID_PHILIPS_SAA7133,
+               .subvendor    = 0x14c0,
+               .subdevice    = 0x1212, /* minipci, LR1212 */
+               .driver_data  = SAA7134_BOARD_FLYTVPLATINUM_MINI2,
+       },{
+               .vendor       = PCI_VENDOR_ID_PHILIPS,
+               .device       = PCI_DEVICE_ID_PHILIPS_SAA7133,
+               .subvendor    = 0x4e42,
+               .subdevice    = 0x0212, /* OEM minipci, LR212 */
+               .driver_data  = SAA7134_BOARD_FLYTVPLATINUM_MINI,
        },{
                .vendor       = PCI_VENDOR_ID_PHILIPS,
                .device       = PCI_DEVICE_ID_PHILIPS_SAA7133,
@@ -2369,7 +2800,7 @@ struct pci_device_id saa7134_pci_tbl[] = {
        },{
                .vendor       = PCI_VENDOR_ID_PHILIPS,
                .device       = PCI_DEVICE_ID_PHILIPS_SAA7130,
-               .subvendor    = 0x153B,
+               .subvendor    = 0x153b,
                .subdevice    = 0x1152,
                .driver_data  = SAA7134_BOARD_CINERGY200,
        },{
@@ -2434,13 +2865,18 @@ struct pci_device_id saa7134_pci_tbl[] = {
                .subvendor    = 0x1421,
                .subdevice    = 0x0350,         /* PCI version */
                .driver_data  = SAA7134_BOARD_ADS_INSTANT_TV,
-
        },{
                .vendor       = PCI_VENDOR_ID_PHILIPS,
                .device       = PCI_DEVICE_ID_PHILIPS_SAA7133,
                .subvendor    = 0x1421,
                .subdevice    = 0x0370,         /* cardbus version */
                .driver_data  = SAA7134_BOARD_ADS_INSTANT_TV,
+       },{
+               .vendor       = PCI_VENDOR_ID_PHILIPS,
+               .device       = PCI_DEVICE_ID_PHILIPS_SAA7133,
+               .subvendor    = 0x1421,
+               .subdevice    = 0x1370,        /* cardbus version */
+               .driver_data  = SAA7134_BOARD_ADS_INSTANT_TV,
 
        },{     /* Typhoon DVB-T Duo Digital/Analog Cardbus */
                .vendor       = PCI_VENDOR_ID_PHILIPS,
@@ -2459,8 +2895,80 @@ struct pci_device_id saa7134_pci_tbl[] = {
                .device       = PCI_DEVICE_ID_PHILIPS_SAA7134,
                .subvendor    = 0x1043,
                .subdevice    = 0x0210,         /* mini pci PAL/SECAM version */
-               .driver_data  = SAA7134_BOARD_FLYTV_DIGIMATRIX,
+               .driver_data  = SAA7134_BOARD_ASUSTEK_DIGIMATRIX_TV,
 
+       },{
+               .vendor       = PCI_VENDOR_ID_PHILIPS,
+               .device       = PCI_DEVICE_ID_PHILIPS_SAA7133,
+               .subvendor    = 0x0000, /* It shouldn't break anything, since subdevice id seems unique */
+               .subdevice    = 0x4091,
+               .driver_data  = SAA7134_BOARD_BEHOLD_409FM,
+       },{
+               .vendor       = PCI_VENDOR_ID_PHILIPS,
+               .device       = PCI_DEVICE_ID_PHILIPS_SAA7133,
+               .subvendor    = 0x5456, /* GoTView */
+               .subdevice    = 0x7135,
+               .driver_data  = SAA7134_BOARD_GOTVIEW_7135,
+       },{
+               .vendor       = PCI_VENDOR_ID_PHILIPS,
+               .device       = PCI_DEVICE_ID_PHILIPS_SAA7134,
+               .subvendor    = PCI_VENDOR_ID_PHILIPS,
+               .subdevice    = 0x2004,
+               .driver_data  = SAA7134_BOARD_PHILIPS_EUROPA,
+       },{
+               .vendor       = PCI_VENDOR_ID_PHILIPS,
+               .device       = PCI_DEVICE_ID_PHILIPS_SAA7134,
+               .subvendor    = 0x185b,
+               .subdevice    = 0xc900,
+               .driver_data  = SAA7134_BOARD_VIDEOMATE_DVBT_300,
+       },{
+               .vendor       = PCI_VENDOR_ID_PHILIPS,
+               .device       = PCI_DEVICE_ID_PHILIPS_SAA7130,
+               .subvendor    = 0x185b,
+               .subdevice    = 0xc901,
+               .driver_data  = SAA7134_BOARD_VIDEOMATE_DVBT_200,
+       },{
+               .vendor       = PCI_VENDOR_ID_PHILIPS,
+               .device       = PCI_DEVICE_ID_PHILIPS_SAA7133,
+               .subvendor    = 0x1435,
+               .subdevice    = 0x7350,
+               .driver_data  = SAA7134_BOARD_RTD_VFG7350,
+       },{
+               .vendor       = PCI_VENDOR_ID_PHILIPS,
+               .device       = PCI_DEVICE_ID_PHILIPS_SAA7133,
+               .subvendor    = 0x1435,
+               .subdevice    = 0x7330,
+               .driver_data  = SAA7134_BOARD_RTD_VFG7330,
+       },{
+               .vendor       = PCI_VENDOR_ID_PHILIPS,
+               .device       = PCI_DEVICE_ID_PHILIPS_SAA7133,
+               .subvendor    = 0x1461,
+               .subdevice    = 0x1044,
+               .driver_data  = SAA7134_BOARD_AVERMEDIA_AVERTVHD_A180,
+       },{
+               .vendor       = PCI_VENDOR_ID_PHILIPS,
+               .device       = PCI_DEVICE_ID_PHILIPS_SAA7133,
+               .subvendor    = 0x1131,
+               .subdevice    = 0x4ee9,
+               .driver_data  = SAA7134_BOARD_MONSTERTV_MOBILE,
+       },{
+               .vendor       = PCI_VENDOR_ID_PHILIPS,
+               .device       = PCI_DEVICE_ID_PHILIPS_SAA7133,
+               .subvendor    = 0x11bd,
+               .subdevice    = 0x002e,
+               .driver_data  = SAA7134_BOARD_PINNACLE_PCTV_110i,
+       },{
+               .vendor       = PCI_VENDOR_ID_PHILIPS,
+               .device       = PCI_DEVICE_ID_PHILIPS_SAA7133,
+               .subvendor    = 0x1043,
+               .subdevice    = 0x4862,
+               .driver_data  = SAA7134_BOARD_ASUSTeK_P7131_DUAL,
+       },{
+               .vendor       = PCI_VENDOR_ID_PHILIPS,
+               .device       = PCI_DEVICE_ID_PHILIPS_SAA7133,
+               .subvendor    = PCI_VENDOR_ID_PHILIPS,
+               .subdevice    = 0x2018,
+               .driver_data  = SAA7134_BOARD_PHILIPS_TIGER,
        },{
                /* --- boards without eeprom + subsystem ID --- */
                .vendor       = PCI_VENDOR_ID_PHILIPS,
@@ -2530,9 +3038,10 @@ int saa7134_board_init1(struct saa7134_dev *dev)
        switch (dev->board) {
        case SAA7134_BOARD_FLYVIDEO2000:
        case SAA7134_BOARD_FLYVIDEO3000:
-               dev->has_remote = 1;
+               dev->has_remote = SAA7134_REMOTE_GPIO;
                board_flyvideo(dev);
                break;
+       case SAA7134_BOARD_FLYTVPLATINUM_MINI2:
        case SAA7134_BOARD_FLYTVPLATINUM_FM:
        case SAA7134_BOARD_CINERGY400:
        case SAA7134_BOARD_CINERGY600:
@@ -2550,10 +3059,16 @@ int saa7134_board_init1(struct saa7134_dev *dev)
 /*      case SAA7134_BOARD_SABRENT_SBTTVFM:  */ /* not finished yet */
        case SAA7134_BOARD_VIDEOMATE_TV_PVR:
        case SAA7134_BOARD_VIDEOMATE_TV_GOLD_PLUSII:
+       case SAA7134_BOARD_VIDEOMATE_DVBT_300:
+       case SAA7134_BOARD_VIDEOMATE_DVBT_200:
        case SAA7134_BOARD_MANLI_MTV001:
        case SAA7134_BOARD_MANLI_MTV002:
+       case SAA7134_BOARD_BEHOLD_409FM:
        case SAA7134_BOARD_AVACSSMARTTV:
-               dev->has_remote = 1;
+       case SAA7134_BOARD_GOTVIEW_7135:
+       case SAA7134_BOARD_KWORLD_TERMINATOR:
+       case SAA7134_BOARD_SEDNA_PC_TV_CARDBUS:
+               dev->has_remote = SAA7134_REMOTE_GPIO;
                break;
        case SAA7134_BOARD_MD5044:
                printk("%s: seems there are two different versions of the MD5044\n"
@@ -2565,11 +3080,14 @@ int saa7134_board_init1(struct saa7134_dev *dev)
                /* power-up tuner chip */
                saa_andorl(SAA7134_GPIO_GPMODE0 >> 2,   0x00040000, 0x00040000);
                saa_andorl(SAA7134_GPIO_GPSTATUS0 >> 2, 0x00040000, 0x00000000);
-               msleep(1);
+       case SAA7134_BOARD_MONSTERTV_MOBILE:
+               /* power-up tuner chip */
+               saa_andorl(SAA7134_GPIO_GPMODE0 >> 2,   0x00040000, 0x00040000);
+               saa_andorl(SAA7134_GPIO_GPSTATUS0 >> 2, 0x00040000, 0x00000004);
                break;
        case SAA7134_BOARD_FLYDVBTDUO:
        case SAA7134_BOARD_THYPHOON_DVBT_DUO_CARDBUS:
-       /* turn the fan on Hac: static for the time being */
+               /* turn the fan on */
                saa_writeb(SAA7134_GPIO_GPMODE3, 0x08);
                saa_writeb(SAA7134_GPIO_GPSTATUS3, 0x06);
                break;
@@ -2579,6 +3097,22 @@ int saa7134_board_init1(struct saa7134_dev *dev)
                saa_andorl(SAA7134_GPIO_GPSTATUS0 >> 2, 0xffffffff, 0xffffffff);
                msleep(1);
                break;
+       case SAA7134_BOARD_RTD_VFG7350:
+
+               /*
+                * Make sure Production Test Register at offset 0x1D1 is cleared
+                * to take chip out of test mode.  Clearing bit 4 (TST_EN_AOUT)
+                * prevents pin 105 from remaining low; keeping pin 105 low
+                * continually resets the SAA6752 chip.
+                */
+
+               saa_writeb (SAA7134_PRODUCTION_TEST_MODE, 0x00);
+               break;
+       /* i2c remotes */
+       case SAA7134_BOARD_PINNACLE_PCTV_110i:
+       case SAA7134_BOARD_UPMOST_PURPLE_TV:
+               dev->has_remote = SAA7134_REMOTE_I2C;
+               break;
        }
        return 0;
 }
@@ -2613,7 +3147,7 @@ int saa7134_board_init2(struct saa7134_dev *dev)
                                saa7134_i2c_call_clients (dev, TUNER_SET_TYPE_ADDR, &tun_setup);
                }
                break;
-case SAA7134_BOARD_MD7134:
+       case SAA7134_BOARD_MD7134:
                {
                struct tuner_setup tun_setup;
                u8 subaddr;
@@ -2680,6 +3214,33 @@ case SAA7134_BOARD_MD7134:
                saa7134_i2c_call_clients (dev, TUNER_SET_TYPE_ADDR,&tun_setup);
                }
                break;
+       case SAA7134_BOARD_PHILIPS_EUROPA:
+       case SAA7134_BOARD_VIDEOMATE_DVBT_300:
+               /* The Philips EUROPA based hybrid boards have the tuner connected through
+                * the channel decoder. We have to make it transparent to find it
+                */
+               {
+               struct tuner_setup tun_setup;
+               u8 data[] = { 0x07, 0x02};
+               struct i2c_msg msg = {.addr=0x08, .flags=0, .buf=data, .len = sizeof(data)};
+               i2c_transfer(&dev->i2c_adap, &msg, 1);
+
+               tun_setup.mode_mask = T_ANALOG_TV | T_DIGITAL_TV;
+               tun_setup.type = dev->tuner_type;
+               tun_setup.addr = dev->tuner_addr;
+
+               saa7134_i2c_call_clients (dev, TUNER_SET_TYPE_ADDR,&tun_setup);
+               }
+               break;
+       case SAA7134_BOARD_PHILIPS_TIGER:
+       case SAA7134_BOARD_ASUSTeK_P7131_DUAL:
+               /* this is a hybrid board, initialize to analog mode */
+               {
+               u8 data[] = { 0x3c, 0x33, 0x68};
+               struct i2c_msg msg = {.addr=0x08, .flags=0, .buf=data, .len = sizeof(data)};
+               i2c_transfer(&dev->i2c_adap, &msg, 1);
+               }
+               break;
        }
        return 0;
 }
index e5e36f3c6250cd534bc5cc79e30de08363ef16c4..19b88744fb31ab3f252b02aa5e5f6b458011b537 100644 (file)
@@ -57,6 +57,10 @@ static unsigned int oss = 0;
 module_param(oss, int, 0444);
 MODULE_PARM_DESC(oss,"register oss devices (default: no)");
 
+static unsigned int alsa = 0;
+module_param(alsa, int, 0444);
+MODULE_PARM_DESC(alsa,"register alsa devices (default: no)");
+
 static unsigned int latency = UNSET;
 module_param(latency, int, 0444);
 MODULE_PARM_DESC(latency,"pci latency timer");
@@ -190,6 +194,7 @@ void saa7134_track_gpio(struct saa7134_dev *dev, char *msg)
 
 static int need_empress;
 static int need_dvb;
+static int need_alsa;
 
 static int pending_call(struct notifier_block *self, unsigned long state,
                        void *module)
@@ -197,10 +202,12 @@ static int pending_call(struct notifier_block *self, unsigned long state,
        if (module != THIS_MODULE || state != MODULE_STATE_LIVE)
                return NOTIFY_DONE;
 
-        if (need_empress)
-                request_module("saa7134-empress");
-        if (need_dvb)
-                request_module("saa7134-dvb");
+       if (need_empress)
+               request_module("saa7134-empress");
+       if (need_dvb)
+               request_module("saa7134-dvb");
+       if (need_alsa)
+               request_module("saa7134-alsa");
        return NOTIFY_DONE;
 }
 
@@ -275,8 +282,8 @@ unsigned long saa7134_buffer_base(struct saa7134_buf *buf)
 
 int saa7134_pgtable_alloc(struct pci_dev *pci, struct saa7134_pgtable *pt)
 {
-        __le32       *cpu;
-        dma_addr_t   dma_addr;
+       __le32       *cpu;
+       dma_addr_t   dma_addr;
 
        cpu = pci_alloc_consistent(pci, SAA7134_PGTABLE_SIZE, &dma_addr);
        if (NULL == cpu)
@@ -436,7 +443,7 @@ int saa7134_set_dmabits(struct saa7134_dev *dev)
                ctrl |= SAA7134_MAIN_CTRL_TE0;
                irq  |= SAA7134_IRQ1_INTE_RA0_1 |
                        SAA7134_IRQ1_INTE_RA0_0;
-               cap = dev->video_q.curr->vb.field;
+               cap = dev->video_q.curr->vb.field;
        }
 
        /* video capture -- dma 1+2 (planar modes) */
@@ -465,7 +472,7 @@ int saa7134_set_dmabits(struct saa7134_dev *dev)
        }
 
        /* audio capture -- dma 3 */
-       if (dev->oss.dma_running) {
+       if (dev->dmasound.dma_running) {
                ctrl |= SAA7134_MAIN_CTRL_TE6;
                irq  |= SAA7134_IRQ1_INTE_RA3_1 |
                        SAA7134_IRQ1_INTE_RA3_0;
@@ -570,6 +577,17 @@ static irqreturn_t saa7134_irq(int irq, void *dev_id, struct pt_regs *regs)
                                       dev->name);
                        goto out;
                }
+
+               /* If alsa support is active and we get a sound report, exit
+                  and let the saa7134-alsa module deal with it */
+
+               if ((report & SAA7134_IRQ_REPORT_DONE_RA3) && alsa)  {
+                       if (irq_debug > 1)
+                               printk(KERN_DEBUG "%s/irq: ignoring interrupt for ALSA\n",
+                                      dev->name);
+                       goto out;
+               }
+
                handled = 1;
                saa_writel(SAA7134_IRQ_REPORT,report);
                if (irq_debug)
@@ -591,13 +609,17 @@ static irqreturn_t saa7134_irq(int irq, void *dev_id, struct pt_regs *regs)
                    card_has_mpeg(dev))
                        saa7134_irq_ts_done(dev,status);
 
-               if ((report & SAA7134_IRQ_REPORT_DONE_RA3))
-                       saa7134_irq_oss_done(dev,status);
+               if ((report & SAA7134_IRQ_REPORT_DONE_RA3))  {
+                       if (oss) {
+                               saa7134_irq_oss_done(dev,status);
+                       }
+               }
 
                if ((report & (SAA7134_IRQ_REPORT_GPIO16 |
                               SAA7134_IRQ_REPORT_GPIO18)) &&
                    dev->remote)
                        saa7134_input_irq(dev);
+
        }
 
        if (10 == loop) {
@@ -636,7 +658,7 @@ static int saa7134_hwinit1(struct saa7134_dev *dev)
 
        saa_writel(SAA7134_IRQ1, 0);
        saa_writel(SAA7134_IRQ2, 0);
-        init_MUTEX(&dev->lock);
+       init_MUTEX(&dev->lock);
        spin_lock_init(&dev->slock);
 
        saa7134_track_gpio(dev,"pre-init");
@@ -646,14 +668,6 @@ static int saa7134_hwinit1(struct saa7134_dev *dev)
                saa7134_ts_init1(dev);
        saa7134_input_init1(dev);
 
-       switch (dev->pci->device) {
-       case PCI_DEVICE_ID_PHILIPS_SAA7134:
-       case PCI_DEVICE_ID_PHILIPS_SAA7133:
-       case PCI_DEVICE_ID_PHILIPS_SAA7135:
-               saa7134_oss_init1(dev);
-               break;
-       }
-
        /* RAM FIFO config */
        saa_writel(SAA7134_FIFO_SIZE, 0x08070503);
        saa_writel(SAA7134_THRESHOULD,0x02020202);
@@ -668,6 +682,21 @@ static int saa7134_hwinit1(struct saa7134_dev *dev)
                   SAA7134_MAIN_CTRL_ESFE  |
                   SAA7134_MAIN_CTRL_EBDAC);
 
+       /*
+        * Initialize OSS _after_ enabling audio clock PLL and audio processing.
+        * OSS initialization writes to registers via the audio DSP; these
+        * writes will fail unless the audio clock has been started.  At worst,
+        * audio will not work.
+        */
+
+       switch (dev->pci->device) {
+       case PCI_DEVICE_ID_PHILIPS_SAA7134:
+       case PCI_DEVICE_ID_PHILIPS_SAA7133:
+       case PCI_DEVICE_ID_PHILIPS_SAA7135:
+               saa7134_oss_init1(dev);
+               break;
+       }
+
        /* enable peripheral devices */
        saa_writeb(SAA7134_SPECIAL_MODE, 0x01);
 
@@ -687,7 +716,7 @@ static int saa7134_hwinit2(struct saa7134_dev *dev)
        saa7134_tvaudio_init2(dev);
 
        /* enable IRQ's */
-       irq2_mask =
+       irq2_mask =
                SAA7134_IRQ2_INTE_DEC3    |
                SAA7134_IRQ2_INTE_DEC2    |
                SAA7134_IRQ2_INTE_DEC1    |
@@ -695,10 +724,12 @@ static int saa7134_hwinit2(struct saa7134_dev *dev)
                SAA7134_IRQ2_INTE_PE      |
                SAA7134_IRQ2_INTE_AR;
 
-       if (dev->has_remote)
+       if (dev->has_remote == SAA7134_REMOTE_GPIO)
                irq2_mask |= (SAA7134_IRQ2_INTE_GPIO18  |
                              SAA7134_IRQ2_INTE_GPIO18A |
                              SAA7134_IRQ2_INTE_GPIO16  );
+       else if (dev->has_remote == SAA7134_REMOTE_I2C)
+               request_module("ir-kbd-i2c");
 
        saa_writel(SAA7134_IRQ1, 0);
        saa_writel(SAA7134_IRQ2, irq2_mask);
@@ -872,8 +903,8 @@ static int __devinit saa7134_initdev(struct pci_dev *pci_dev,
 
        /* print pci info */
        pci_read_config_byte(pci_dev, PCI_CLASS_REVISION, &dev->pci_rev);
-        pci_read_config_byte(pci_dev, PCI_LATENCY_TIMER,  &dev->pci_lat);
-        printk(KERN_INFO "%s: found at %s, rev: %d, irq: %d, "
+       pci_read_config_byte(pci_dev, PCI_LATENCY_TIMER,  &dev->pci_lat);
+       printk(KERN_INFO "%s: found at %s, rev: %d, irq: %d, "
               "latency: %d, mmio: 0x%lx\n", dev->name,
               pci_name(pci_dev), dev->pci_rev, pci_dev->irq,
               dev->pci_lat,pci_resource_start(pci_dev,0));
@@ -897,7 +928,7 @@ static int __devinit saa7134_initdev(struct pci_dev *pci_dev,
        dev->tda9887_conf = saa7134_boards[dev->board].tda9887_conf;
        if (UNSET != tuner[dev->nr])
                dev->tuner_type = tuner[dev->nr];
-        printk(KERN_INFO "%s: subsystem: %04x:%04x, board: %s [card=%d,%s]\n",
+       printk(KERN_INFO "%s: subsystem: %04x:%04x, board: %s [card=%d,%s]\n",
               dev->name,pci_dev->subsystem_vendor,
               pci_dev->subsystem_device,saa7134_boards[dev->board].name,
               dev->board, card[dev->nr] == dev->board ?
@@ -947,14 +978,20 @@ static int __devinit saa7134_initdev(struct pci_dev *pci_dev,
                request_module("tuner");
        if (dev->tda9887_conf)
                request_module("tda9887");
-       if (card_is_empress(dev)) {
+       if (card_is_empress(dev)) {
                request_module("saa6752hs");
                request_module_depend("saa7134-empress",&need_empress);
        }
 
-       if (card_is_dvb(dev))
+       if (card_is_dvb(dev))
                request_module_depend("saa7134-dvb",&need_dvb);
 
+       if (!oss && alsa) {
+               dprintk("Requesting ALSA module\n");
+               request_module_depend("saa7134-alsa",&need_alsa);
+       }
+
+
        v4l2_prio_init(&dev->prio);
 
        /* register v4l devices */
@@ -993,22 +1030,22 @@ static int __devinit saa7134_initdev(struct pci_dev *pci_dev,
        case PCI_DEVICE_ID_PHILIPS_SAA7133:
        case PCI_DEVICE_ID_PHILIPS_SAA7135:
                if (oss) {
-                       err = dev->oss.minor_dsp =
+                       err = dev->dmasound.minor_dsp =
                                register_sound_dsp(&saa7134_dsp_fops,
                                                   dsp_nr[dev->nr]);
                        if (err < 0) {
                                goto fail4;
                        }
                        printk(KERN_INFO "%s: registered device dsp%d\n",
-                              dev->name,dev->oss.minor_dsp >> 4);
+                              dev->name,dev->dmasound.minor_dsp >> 4);
 
-                       err = dev->oss.minor_mixer =
+                       err = dev->dmasound.minor_mixer =
                                register_sound_mixer(&saa7134_mixer_fops,
                                                     mixer_nr[dev->nr]);
                        if (err < 0)
                                goto fail5;
                        printk(KERN_INFO "%s: registered device mixer%d\n",
-                              dev->name,dev->oss.minor_mixer >> 4);
+                              dev->name,dev->dmasound.minor_mixer >> 4);
                }
                break;
        }
@@ -1035,7 +1072,7 @@ static int __devinit saa7134_initdev(struct pci_dev *pci_dev,
        case PCI_DEVICE_ID_PHILIPS_SAA7133:
        case PCI_DEVICE_ID_PHILIPS_SAA7135:
                if (oss)
-                       unregister_sound_dsp(dev->oss.minor_dsp);
+                       unregister_sound_dsp(dev->dmasound.minor_dsp);
                break;
        }
  fail4:
@@ -1055,7 +1092,7 @@ static int __devinit saa7134_initdev(struct pci_dev *pci_dev,
 
 static void __devexit saa7134_finidev(struct pci_dev *pci_dev)
 {
-        struct saa7134_dev *dev = pci_get_drvdata(pci_dev);
+       struct saa7134_dev *dev = pci_get_drvdata(pci_dev);
        struct list_head *item;
        struct saa7134_mpeg_ops *mops;
 
@@ -1093,8 +1130,8 @@ static void __devexit saa7134_finidev(struct pci_dev *pci_dev)
        case PCI_DEVICE_ID_PHILIPS_SAA7133:
        case PCI_DEVICE_ID_PHILIPS_SAA7135:
                if (oss) {
-                       unregister_sound_mixer(dev->oss.minor_mixer);
-                       unregister_sound_dsp(dev->oss.minor_dsp);
+                       unregister_sound_mixer(dev->dmasound.minor_mixer);
+                       unregister_sound_dsp(dev->dmasound.minor_dsp);
                }
                break;
        }
@@ -1149,10 +1186,10 @@ EXPORT_SYMBOL(saa7134_ts_unregister);
 /* ----------------------------------------------------------- */
 
 static struct pci_driver saa7134_pci_driver = {
-        .name     = "saa7134",
-        .id_table = saa7134_pci_tbl,
-        .probe    = saa7134_initdev,
-        .remove   = __devexit_p(saa7134_finidev),
+       .name     = "saa7134",
+       .id_table = saa7134_pci_tbl,
+       .probe    = saa7134_initdev,
+       .remove   = __devexit_p(saa7134_finidev),
 };
 
 static int saa7134_init(void)
@@ -1188,6 +1225,13 @@ EXPORT_SYMBOL(saa7134_i2c_call_clients);
 EXPORT_SYMBOL(saa7134_devlist);
 EXPORT_SYMBOL(saa7134_boards);
 
+/* ----------------- For ALSA -------------------------------- */
+
+EXPORT_SYMBOL(saa7134_pgtable_free);
+EXPORT_SYMBOL(saa7134_pgtable_build);
+EXPORT_SYMBOL(saa7134_pgtable_alloc);
+EXPORT_SYMBOL(saa7134_set_dmabits);
+
 /* ----------------------------------------------------------- */
 /*
  * Local variables:
index 639ae51a052da0e74fb4606a5cb86e28f1dcaf7a..e016480c3468139c9f85b1650c29e6b300a1053e 100644 (file)
@@ -29,7 +29,6 @@
 #include <linux/kthread.h>
 #include <linux/suspend.h>
 
-
 #include "saa7134-reg.h"
 #include "saa7134.h"
 
 #ifdef HAVE_TDA1004X
 # include "tda1004x.h"
 #endif
+#ifdef HAVE_NXT200X
+# include "nxt200x.h"
+# include "dvb-pll.h"
+#endif
 
 MODULE_AUTHOR("Gerd Knorr <kraxel@bytesex.org> [SuSE Labs]");
 MODULE_LICENSE("GPL");
@@ -151,25 +154,12 @@ static struct mt352_config pinnacle_300i = {
 /* ------------------------------------------------------------------ */
 
 #ifdef HAVE_TDA1004X
-static int philips_tu1216_pll_init(struct dvb_frontend *fe)
-{
-       struct saa7134_dev *dev = fe->dvb->priv;
-       static u8 tu1216_init[] = { 0x0b, 0xf5, 0x85, 0xab };
-       struct i2c_msg tuner_msg = {.addr = 0x60,.flags = 0,.buf = tu1216_init,.len = sizeof(tu1216_init) };
-
-       /* setup PLL configuration */
-       if (i2c_transfer(&dev->i2c_adap, &tuner_msg, 1) != 1)
-               return -EIO;
-       msleep(1);
 
-       return 0;
-}
-
-static int philips_tu1216_pll_set(struct dvb_frontend *fe, struct dvb_frontend_parameters *params)
+static int philips_tda6651_pll_set(u8 addr, struct dvb_frontend *fe, struct dvb_frontend_parameters *params)
 {
        struct saa7134_dev *dev = fe->dvb->priv;
        u8 tuner_buf[4];
-       struct i2c_msg tuner_msg = {.addr = 0x60,.flags = 0,.buf = tuner_buf,.len =
+       struct i2c_msg tuner_msg = {.addr = addr,.flags = 0,.buf = tuner_buf,.len =
                        sizeof(tuner_buf) };
        int tuner_frequency = 0;
        u8 band, cp, filter;
@@ -242,11 +232,36 @@ static int philips_tu1216_pll_set(struct dvb_frontend *fe, struct dvb_frontend_p
 
        if (i2c_transfer(&dev->i2c_adap, &tuner_msg, 1) != 1)
                return -EIO;
+       msleep(1);
+       return 0;
+}
 
+static int philips_tda6651_pll_init(u8 addr, struct dvb_frontend *fe)
+{
+       struct saa7134_dev *dev = fe->dvb->priv;
+       static u8 tu1216_init[] = { 0x0b, 0xf5, 0x85, 0xab };
+       struct i2c_msg tuner_msg = {.addr = addr,.flags = 0,.buf = tu1216_init,.len = sizeof(tu1216_init) };
+
+       /* setup PLL configuration */
+       if (i2c_transfer(&dev->i2c_adap, &tuner_msg, 1) != 1)
+               return -EIO;
        msleep(1);
+
        return 0;
 }
 
+/* ------------------------------------------------------------------ */
+
+static int philips_tu1216_pll_60_init(struct dvb_frontend *fe)
+{
+       return philips_tda6651_pll_init(0x60, fe);
+}
+
+static int philips_tu1216_pll_60_set(struct dvb_frontend *fe, struct dvb_frontend_parameters *params)
+{
+       return philips_tda6651_pll_set(0x60, fe, params);
+}
+
 static int philips_tu1216_request_firmware(struct dvb_frontend *fe,
                                           const struct firmware **fw, char *name)
 {
@@ -254,22 +269,108 @@ static int philips_tu1216_request_firmware(struct dvb_frontend *fe,
        return request_firmware(fw, name, &dev->pci->dev);
 }
 
-static struct tda1004x_config philips_tu1216_config = {
+static struct tda1004x_config philips_tu1216_60_config = {
+
+       .demod_address = 0x8,
+       .invert        = 1,
+       .invert_oclk   = 0,
+       .xtal_freq     = TDA10046_XTAL_4M,
+       .agc_config    = TDA10046_AGC_DEFAULT,
+       .if_freq       = TDA10046_FREQ_3617,
+       .pll_init      = philips_tu1216_pll_60_init,
+       .pll_set       = philips_tu1216_pll_60_set,
+       .pll_sleep     = NULL,
+       .request_firmware = philips_tu1216_request_firmware,
+};
+
+/* ------------------------------------------------------------------ */
+
+static int philips_tu1216_pll_61_init(struct dvb_frontend *fe)
+{
+       return philips_tda6651_pll_init(0x61, fe);
+}
+
+static int philips_tu1216_pll_61_set(struct dvb_frontend *fe, struct dvb_frontend_parameters *params)
+{
+       return philips_tda6651_pll_set(0x61, fe, params);
+}
+
+static struct tda1004x_config philips_tu1216_61_config = {
 
        .demod_address = 0x8,
        .invert        = 1,
-       .invert_oclk   = 1,
+       .invert_oclk   = 0,
        .xtal_freq     = TDA10046_XTAL_4M,
        .agc_config    = TDA10046_AGC_DEFAULT,
        .if_freq       = TDA10046_FREQ_3617,
-       .pll_init      = philips_tu1216_pll_init,
-       .pll_set       = philips_tu1216_pll_set,
+       .pll_init      = philips_tu1216_pll_61_init,
+       .pll_set       = philips_tu1216_pll_61_set,
        .pll_sleep     = NULL,
        .request_firmware = philips_tu1216_request_firmware,
 };
 
 /* ------------------------------------------------------------------ */
 
+static int philips_europa_pll_init(struct dvb_frontend *fe)
+{
+       struct saa7134_dev *dev = fe->dvb->priv;
+       static u8 msg[] = { 0x0b, 0xf5, 0x86, 0xab };
+       struct i2c_msg init_msg = {.addr = 0x61,.flags = 0,.buf = msg,.len = sizeof(msg) };
+
+       /* setup PLL configuration */
+       if (i2c_transfer(&dev->i2c_adap, &init_msg, 1) != 1)
+               return -EIO;
+       msleep(1);
+
+       /* switch the board to dvb mode */
+       init_msg.addr = 0x43;
+       init_msg.len  = 0x02;
+       msg[0] = 0x00;
+       msg[1] = 0x40;
+       if (i2c_transfer(&dev->i2c_adap, &init_msg, 1) != 1)
+               return -EIO;
+
+       return 0;
+}
+
+static int philips_td1316_pll_set(struct dvb_frontend *fe, struct dvb_frontend_parameters *params)
+{
+       return philips_tda6651_pll_set(0x61, fe, params);
+}
+
+static void philips_europa_analog(struct dvb_frontend *fe)
+{
+       struct saa7134_dev *dev = fe->dvb->priv;
+       /* this message actually turns the tuner back to analog mode */
+       static u8 msg[] = { 0x0b, 0xdc, 0x86, 0xa4 };
+       struct i2c_msg analog_msg = {.addr = 0x61,.flags = 0,.buf = msg,.len = sizeof(msg) };
+
+       i2c_transfer(&dev->i2c_adap, &analog_msg, 1);
+       msleep(1);
+
+       /* switch the board to analog mode */
+       analog_msg.addr = 0x43;
+       analog_msg.len  = 0x02;
+       msg[0] = 0x00;
+       msg[1] = 0x14;
+       i2c_transfer(&dev->i2c_adap, &analog_msg, 1);
+}
+
+static struct tda1004x_config philips_europa_config = {
+
+       .demod_address = 0x8,
+       .invert        = 0,
+       .invert_oclk   = 0,
+       .xtal_freq     = TDA10046_XTAL_4M,
+       .agc_config    = TDA10046_AGC_IFO_AUTO_POS,
+       .if_freq       = TDA10046_FREQ_052,
+       .pll_init      = philips_europa_pll_init,
+       .pll_set       = philips_td1316_pll_set,
+       .pll_sleep     = philips_europa_analog,
+       .request_firmware = NULL,
+};
+
+/* ------------------------------------------------------------------ */
 
 static int philips_fmd1216_pll_init(struct dvb_frontend *fe)
 {
@@ -382,7 +483,6 @@ static int philips_fmd1216_pll_set(struct dvb_frontend *fe, struct dvb_frontend_
        return 0;
 }
 
-#ifdef HAVE_TDA1004X
 static struct tda1004x_config medion_cardbus = {
        .demod_address = 0x08,
        .invert        = 1,
@@ -395,7 +495,6 @@ static struct tda1004x_config medion_cardbus = {
        .pll_sleep         = philips_fmd1216_analog,
        .request_firmware = NULL,
 };
-#endif
 
 /* ------------------------------------------------------------------ */
 
@@ -452,7 +551,7 @@ static int philips_tda827x_pll_set(struct dvb_frontend *fe, struct dvb_frontend_
        u8 tuner_buf[14];
 
        struct i2c_msg tuner_msg = {.addr = 0x60,.flags = 0,.buf = tuner_buf,
-                                       .len = sizeof(tuner_buf) };
+                                       .len = sizeof(tuner_buf) };
        int i, tuner_freq, if_freq;
        u32 N;
        switch (params->u.ofdm.bandwidth) {
@@ -511,7 +610,7 @@ static void philips_tda827x_pll_sleep(struct dvb_frontend *fe)
        struct saa7134_dev *dev = fe->dvb->priv;
        static u8 tda827x_sleep[] = { 0x30, 0xd0};
        struct i2c_msg tuner_msg = {.addr = 0x60,.flags = 0,.buf = tda827x_sleep,
-                                   .len = sizeof(tda827x_sleep) };
+                                   .len = sizeof(tda827x_sleep) };
        i2c_transfer(&dev->i2c_adap, &tuner_msg, 1);
 }
 
@@ -527,6 +626,202 @@ static struct tda1004x_config tda827x_lifeview_config = {
        .pll_sleep         = philips_tda827x_pll_sleep,
        .request_firmware = NULL,
 };
+
+/* ------------------------------------------------------------------ */
+
+struct tda827xa_data {
+       u32 lomax;
+       u8  svco;
+       u8  spd;
+       u8  scr;
+       u8  sbs;
+       u8  gc3;
+};
+
+static struct tda827xa_data tda827xa_dvbt[] = {
+       { .lomax =  56875000, .svco = 3, .spd = 4, .scr = 0, .sbs = 0, .gc3 = 1},
+       { .lomax =  67250000, .svco = 0, .spd = 3, .scr = 0, .sbs = 0, .gc3 = 1},
+       { .lomax =  81250000, .svco = 1, .spd = 3, .scr = 0, .sbs = 0, .gc3 = 1},
+       { .lomax =  97500000, .svco = 2, .spd = 3, .scr = 0, .sbs = 0, .gc3 = 1},
+       { .lomax = 113750000, .svco = 3, .spd = 3, .scr = 0, .sbs = 1, .gc3 = 1},
+       { .lomax = 134500000, .svco = 0, .spd = 2, .scr = 0, .sbs = 1, .gc3 = 1},
+       { .lomax = 154000000, .svco = 1, .spd = 2, .scr = 0, .sbs = 1, .gc3 = 1},
+       { .lomax = 162500000, .svco = 1, .spd = 2, .scr = 0, .sbs = 1, .gc3 = 1},
+       { .lomax = 183000000, .svco = 2, .spd = 2, .scr = 0, .sbs = 1, .gc3 = 1},
+       { .lomax = 195000000, .svco = 2, .spd = 2, .scr = 0, .sbs = 2, .gc3 = 1},
+       { .lomax = 227500000, .svco = 3, .spd = 2, .scr = 0, .sbs = 2, .gc3 = 1},
+       { .lomax = 269000000, .svco = 0, .spd = 1, .scr = 0, .sbs = 2, .gc3 = 1},
+       { .lomax = 290000000, .svco = 1, .spd = 1, .scr = 0, .sbs = 2, .gc3 = 1},
+       { .lomax = 325000000, .svco = 1, .spd = 1, .scr = 0, .sbs = 3, .gc3 = 1},
+       { .lomax = 390000000, .svco = 2, .spd = 1, .scr = 0, .sbs = 3, .gc3 = 1},
+       { .lomax = 455000000, .svco = 3, .spd = 1, .scr = 0, .sbs = 3, .gc3 = 1},
+       { .lomax = 520000000, .svco = 0, .spd = 0, .scr = 0, .sbs = 3, .gc3 = 1},
+       { .lomax = 538000000, .svco = 0, .spd = 0, .scr = 1, .sbs = 3, .gc3 = 1},
+       { .lomax = 550000000, .svco = 1, .spd = 0, .scr = 0, .sbs = 3, .gc3 = 1},
+       { .lomax = 620000000, .svco = 1, .spd = 0, .scr = 0, .sbs = 4, .gc3 = 0},
+       { .lomax = 650000000, .svco = 1, .spd = 0, .scr = 1, .sbs = 4, .gc3 = 0},
+       { .lomax = 700000000, .svco = 2, .spd = 0, .scr = 0, .sbs = 4, .gc3 = 0},
+       { .lomax = 780000000, .svco = 2, .spd = 0, .scr = 1, .sbs = 4, .gc3 = 0},
+       { .lomax = 820000000, .svco = 3, .spd = 0, .scr = 0, .sbs = 4, .gc3 = 0},
+       { .lomax = 870000000, .svco = 3, .spd = 0, .scr = 1, .sbs = 4, .gc3 = 0},
+       { .lomax = 911000000, .svco = 3, .spd = 0, .scr = 2, .sbs = 4, .gc3 = 0},
+       { .lomax =         0, .svco = 0, .spd = 0, .scr = 0, .sbs = 0, .gc3 = 0}};
+
+
+static int philips_tda827xa_pll_set(u8 addr, struct dvb_frontend *fe, struct dvb_frontend_parameters *params)
+{
+       struct saa7134_dev *dev = fe->dvb->priv;
+       u8 tuner_buf[14];
+       unsigned char reg2[2];
+
+       struct i2c_msg msg = {.addr = addr,.flags = 0,.buf = tuner_buf};
+       int i, tuner_freq, if_freq;
+       u32 N;
+
+       switch (params->u.ofdm.bandwidth) {
+       case BANDWIDTH_6_MHZ:
+               if_freq = 4000000;
+               break;
+       case BANDWIDTH_7_MHZ:
+               if_freq = 4500000;
+               break;
+       default:                   /* 8 MHz or Auto */
+               if_freq = 5000000;
+               break;
+       }
+       tuner_freq = params->frequency + if_freq;
+
+       i = 0;
+       while (tda827xa_dvbt[i].lomax < tuner_freq) {
+               if(tda827xa_dvbt[i + 1].lomax == 0)
+                       break;
+               i++;
+       }
+
+       N = ((tuner_freq + 31250) / 62500) << tda827xa_dvbt[i].spd;
+       tuner_buf[0] = 0;            // subaddress
+       tuner_buf[1] = N >> 8;
+       tuner_buf[2] = N & 0xff;
+       tuner_buf[3] = 0;
+       tuner_buf[4] = 0x16;
+       tuner_buf[5] = (tda827xa_dvbt[i].spd << 5) + (tda827xa_dvbt[i].svco << 3) +
+                       tda827xa_dvbt[i].sbs;
+       tuner_buf[6] = 0x4b + (tda827xa_dvbt[i].gc3 << 4);
+       tuner_buf[7] = 0x0c;
+       tuner_buf[8] = 0x06;
+       tuner_buf[9] = 0x24;
+       tuner_buf[10] = 0xff;
+       tuner_buf[11] = 0x60;
+       tuner_buf[12] = 0x00;
+       tuner_buf[13] = 0x39;  // lpsel
+       msg.len = 14;
+       if (i2c_transfer(&dev->i2c_adap, &msg, 1) != 1)
+               return -EIO;
+
+       msg.buf= reg2;
+       msg.len = 2;
+       reg2[0] = 0x60;
+       reg2[1] = 0x3c;
+       i2c_transfer(&dev->i2c_adap, &msg, 1);
+
+       reg2[0] = 0xa0;
+       reg2[1] = 0x40;
+       i2c_transfer(&dev->i2c_adap, &msg, 1);
+
+       msleep(2);
+       /* correct CP value */
+       reg2[0] = 0x30;
+       reg2[1] = 0x10 + tda827xa_dvbt[i].scr;
+       msg.len = 2;
+       i2c_transfer(&dev->i2c_adap, &msg, 1);
+
+       msleep(550);
+       reg2[0] = 0x50;
+       reg2[1] = 0x4f + (tda827xa_dvbt[i].gc3 << 4);
+       i2c_transfer(&dev->i2c_adap, &msg, 1);
+
+       return 0;
+
+}
+
+static void philips_tda827xa_pll_sleep(u8 addr, struct dvb_frontend *fe)
+{
+       struct saa7134_dev *dev = fe->dvb->priv;
+       static u8 tda827xa_sleep[] = { 0x30, 0x90};
+       struct i2c_msg tuner_msg = {.addr = addr,.flags = 0,.buf = tda827xa_sleep,
+                                   .len = sizeof(tda827xa_sleep) };
+       i2c_transfer(&dev->i2c_adap, &tuner_msg, 1);
+
+}
+
+/* ------------------------------------------------------------------ */
+
+static int philips_tiger_pll_set(struct dvb_frontend *fe, struct dvb_frontend_parameters *params)
+{
+       int ret;
+       struct saa7134_dev *dev = fe->dvb->priv;
+       static u8 tda8290_close[] = { 0x21, 0xc0};
+       static u8 tda8290_open[]  = { 0x21, 0x80};
+       struct i2c_msg tda8290_msg = {.addr = 0x4b,.flags = 0, .len = 2};
+       /* close tda8290 i2c bridge */
+       tda8290_msg.buf = tda8290_close;
+       ret = i2c_transfer(&dev->i2c_adap, &tda8290_msg, 1);
+       if (ret != 1)
+               return -EIO;
+       msleep(20);
+       ret = philips_tda827xa_pll_set(0x61, fe, params);
+       if (ret != 0)
+               return ret;
+       /* open tda8290 i2c bridge */
+       tda8290_msg.buf = tda8290_open;
+       i2c_transfer(&dev->i2c_adap, &tda8290_msg, 1);
+       return ret;
+};
+
+static int philips_tiger_dvb_mode(struct dvb_frontend *fe)
+{
+       struct saa7134_dev *dev = fe->dvb->priv;
+       static u8 data[] = { 0x3c, 0x33, 0x6a};
+       struct i2c_msg msg = {.addr=0x08, .flags=0, .buf=data, .len = sizeof(data)};
+
+       if (i2c_transfer(&dev->i2c_adap, &msg, 1) != 1)
+               return -EIO;
+       return 0;
+}
+
+static void philips_tiger_analog_mode(struct dvb_frontend *fe)
+{
+       struct saa7134_dev *dev = fe->dvb->priv;
+       static u8 data[] = { 0x3c, 0x33, 0x68};
+       struct i2c_msg msg = {.addr=0x08, .flags=0, .buf=data, .len = sizeof(data)};
+
+       i2c_transfer(&dev->i2c_adap, &msg, 1);
+       philips_tda827xa_pll_sleep( 0x61, fe);
+}
+
+static struct tda1004x_config philips_tiger_config = {
+       .demod_address = 0x08,
+       .invert        = 1,
+       .invert_oclk   = 0,
+       .xtal_freq     = TDA10046_XTAL_16M,
+       .agc_config    = TDA10046_AGC_TDA827X,
+       .if_freq       = TDA10046_FREQ_045,
+       .pll_init      = philips_tiger_dvb_mode,
+       .pll_set       = philips_tiger_pll_set,
+       .pll_sleep     = philips_tiger_analog_mode,
+       .request_firmware = NULL,
+};
+
+#endif
+
+/* ------------------------------------------------------------------ */
+
+#ifdef HAVE_NXT200X
+static struct nxt200x_config avertvhda180 = {
+       .demod_address    = 0x0a,
+       .pll_address      = 0x61,
+       .pll_desc         = &dvb_pll_tdhu2,
+};
 #endif
 
 /* ------------------------------------------------------------------ */
@@ -558,7 +853,7 @@ static int dvb_init(struct saa7134_dev *dev)
                                                    &dev->i2c_adap);
                break;
        case SAA7134_BOARD_PHILIPS_TOUGH:
-               dev->dvb.frontend = tda10046_attach(&philips_tu1216_config,
+               dev->dvb.frontend = tda10046_attach(&philips_tu1216_60_config,
                                                    &dev->i2c_adap);
                break;
        case SAA7134_BOARD_FLYDVBTDUO:
@@ -569,6 +864,31 @@ static int dvb_init(struct saa7134_dev *dev)
                dev->dvb.frontend = tda10046_attach(&tda827x_lifeview_config,
                                                    &dev->i2c_adap);
                break;
+       case SAA7134_BOARD_PHILIPS_EUROPA:
+               dev->dvb.frontend = tda10046_attach(&philips_europa_config,
+                                                   &dev->i2c_adap);
+               break;
+       case SAA7134_BOARD_VIDEOMATE_DVBT_300:
+               dev->dvb.frontend = tda10046_attach(&philips_europa_config,
+                                                   &dev->i2c_adap);
+               break;
+       case SAA7134_BOARD_VIDEOMATE_DVBT_200:
+               dev->dvb.frontend = tda10046_attach(&philips_tu1216_61_config,
+                                                   &dev->i2c_adap);
+               break;
+       case SAA7134_BOARD_PHILIPS_TIGER:
+               dev->dvb.frontend = tda10046_attach(&philips_tiger_config,
+                                                   &dev->i2c_adap);
+               break;
+       case SAA7134_BOARD_ASUSTeK_P7131_DUAL:
+               dev->dvb.frontend = tda10046_attach(&philips_tiger_config,
+                                                   &dev->i2c_adap);
+               break;
+#endif
+#ifdef HAVE_NXT200X
+       case SAA7134_BOARD_AVERMEDIA_AVERTVHD_A180:
+               dev->dvb.frontend = nxt200x_attach(&avertvhda180, &dev->i2c_adap);
+               break;
 #endif
        default:
                printk("%s: Huh? unknown DVB card?\n",dev->name);
index 77b627eb6483c38c259d7ea9c6f2614d3f8f7170..e9ec69efb4c92052f4cc90f8ad8ff152324b38e6 100644 (file)
@@ -55,7 +55,7 @@ static void ts_reset_encoder(struct saa7134_dev* dev)
 
        saa_writeb(SAA7134_SPECIAL_MODE, 0x00);
        msleep(10);
-       saa_writeb(SAA7134_SPECIAL_MODE, 0x01);
+       saa_writeb(SAA7134_SPECIAL_MODE, 0x01);
        msleep(100);
        dev->empress_started = 0;
 }
@@ -65,7 +65,7 @@ static int ts_init_encoder(struct saa7134_dev* dev)
        ts_reset_encoder(dev);
        saa7134_i2c_call_clients(dev, VIDIOC_S_MPEGCOMP, NULL);
        dev->empress_started = 1;
-       return 0;
+       return 0;
 }
 
 /* ------------------------------------------------------------------ */
@@ -169,7 +169,7 @@ static int ts_do_ioctl(struct inode *inode, struct file *file,
                struct v4l2_capability *cap = arg;
 
                memset(cap,0,sizeof(*cap));
-                strcpy(cap->driver, "saa7134");
+               strcpy(cap->driver, "saa7134");
                strlcpy(cap->card, saa7134_boards[dev->board].name,
                        sizeof(cap->card));
                sprintf(cap->bus_info,"PCI:%s",pci_name(dev->pci));
index 711aa8e85fac3c801d87b5c45641cfb5d39560c9..7575043f0874985c6a38f00c2b9c85c2891098b6 100644 (file)
@@ -239,7 +239,7 @@ static int saa7134_i2c_xfer(struct i2c_adapter *i2c_adap,
        unsigned char data;
        int addr,rc,i,byte;
 
-       status = i2c_get_status(dev);
+       status = i2c_get_status(dev);
        if (!i2c_is_idle(status))
                if (!i2c_reset(dev))
                        return -EIO;
@@ -296,7 +296,7 @@ static int saa7134_i2c_xfer(struct i2c_adapter *i2c_adap,
        rc = -EIO;
        if (!i2c_is_busy_wait(dev))
                goto err;
-       status = i2c_get_status(dev);
+       status = i2c_get_status(dev);
        if (i2c_is_error(status))
                goto err;
        /* ensure that the bus is idle for at least one bit slot */
@@ -335,6 +335,20 @@ static int attach_inform(struct i2c_client *client)
        d1printk( "%s i2c attach [addr=0x%x,client=%s]\n",
                 client->driver->name, client->addr, client->name);
 
+       /* Am I an i2c remote control? */
+
+       switch (client->addr) {
+               case 0x7a:
+               case 0x47:
+               {
+                       struct IR_i2c *ir = i2c_get_clientdata(client);
+                       d1printk("%s i2c IR detected (%s).\n",
+                                client->driver->name,ir->phys);
+                       saa7134_set_i2c_ir(dev,ir);
+                       break;
+               }
+       }
+
        if (!client->driver->command)
                return 0;
 
@@ -348,12 +362,12 @@ static int attach_inform(struct i2c_client *client)
 
                        client->driver->command(client, TUNER_SET_TYPE_ADDR, &tun_setup);
                }
-        }
+       }
 
        if (tuner != UNSET) {
 
-               tun_setup.type = tuner;
-               tun_setup.addr = saa7134_boards[dev->board].tuner_addr;
+               tun_setup.type = tuner;
+               tun_setup.addr = saa7134_boards[dev->board].tuner_addr;
 
                if ((tun_setup.addr == ADDR_UNSET)||(tun_setup.addr == client->addr)) {
 
@@ -361,11 +375,11 @@ static int attach_inform(struct i2c_client *client)
 
                        client->driver->command(client,TUNER_SET_TYPE_ADDR, &tun_setup);
                }
-        }
+       }
 
        client->driver->command(client, TDA9887_SET_CONFIG, &conf);
 
-        return 0;
+       return 0;
 }
 
 static struct i2c_algorithm saa7134_algo = {
index 242cb235cf926226b48819be95efed9b07316e22..329accda6d45a73774bf1bf28cd90c496e3f6582 100644 (file)
@@ -39,6 +39,8 @@ MODULE_PARM_DESC(ir_debug,"enable debug messages [IR]");
 
 #define dprintk(fmt, arg...)   if (ir_debug) \
        printk(KERN_DEBUG "%s/ir: " fmt, dev->name , ## arg)
+#define i2cdprintk(fmt, arg...)    if (ir_debug) \
+       printk(KERN_DEBUG "%s/ir: " fmt, ir->c.name , ## arg)
 
 /* ---------------------------------------------------------------------- */
 
@@ -114,24 +116,24 @@ static IR_KEYTAB_TYPE cinergy_codes[IR_KEYTAB_SIZE] = {
 /* Alfons Geser <a.geser@cox.net>
  * updates from Job D. R. Borges <jobdrb@ig.com.br> */
 static IR_KEYTAB_TYPE eztv_codes[IR_KEYTAB_SIZE] = {
-        [ 18 ] = KEY_POWER,
-        [  1 ] = KEY_TV,             // DVR
-        [ 21 ] = KEY_DVD,            // DVD
-        [ 23 ] = KEY_AUDIO,          // music
-                                     // DVR mode / DVD mode / music mode
-
-        [ 27 ] = KEY_MUTE,           // mute
-        [  2 ] = KEY_LANGUAGE,       // MTS/SAP / audio / autoseek
-        [ 30 ] = KEY_SUBTITLE,       // closed captioning / subtitle / seek
-        [ 22 ] = KEY_ZOOM,           // full screen
-        [ 28 ] = KEY_VIDEO,          // video source / eject / delall
-        [ 29 ] = KEY_RESTART,        // playback / angle / del
-        [ 47 ] = KEY_SEARCH,         // scan / menu / playlist
-        [ 48 ] = KEY_CHANNEL,        // CH surfing / bookmark / memo
-
-        [ 49 ] = KEY_HELP,           // help
-        [ 50 ] = KEY_MODE,           // num/memo
-        [ 51 ] = KEY_ESC,            // cancel
+       [ 18 ] = KEY_POWER,
+       [  1 ] = KEY_TV,             // DVR
+       [ 21 ] = KEY_DVD,            // DVD
+       [ 23 ] = KEY_AUDIO,          // music
+                                    // DVR mode / DVD mode / music mode
+
+       [ 27 ] = KEY_MUTE,           // mute
+       [  2 ] = KEY_LANGUAGE,       // MTS/SAP / audio / autoseek
+       [ 30 ] = KEY_SUBTITLE,       // closed captioning / subtitle / seek
+       [ 22 ] = KEY_ZOOM,           // full screen
+       [ 28 ] = KEY_VIDEO,          // video source / eject / delall
+       [ 29 ] = KEY_RESTART,        // playback / angle / del
+       [ 47 ] = KEY_SEARCH,         // scan / menu / playlist
+       [ 48 ] = KEY_CHANNEL,        // CH surfing / bookmark / memo
+
+       [ 49 ] = KEY_HELP,           // help
+       [ 50 ] = KEY_MODE,           // num/memo
+       [ 51 ] = KEY_ESC,            // cancel
 
        [ 12 ] = KEY_UP,             // up
        [ 16 ] = KEY_DOWN,           // down
@@ -148,24 +150,24 @@ static IR_KEYTAB_TYPE eztv_codes[IR_KEYTAB_SIZE] = {
        [ 45 ] = KEY_PLAY,           // play
        [ 46 ] = KEY_SHUFFLE,        // snapshot / shuffle
 
-        [  0 ] = KEY_KP0,
-        [  5 ] = KEY_KP1,
-        [  6 ] = KEY_KP2,
-        [  7 ] = KEY_KP3,
-        [  9 ] = KEY_KP4,
-        [ 10 ] = KEY_KP5,
-        [ 11 ] = KEY_KP6,
-        [ 13 ] = KEY_KP7,
-        [ 14 ] = KEY_KP8,
-        [ 15 ] = KEY_KP9,
-
-        [ 42 ] = KEY_VOLUMEUP,
-        [ 17 ] = KEY_VOLUMEDOWN,
-        [ 24 ] = KEY_CHANNELUP,      // CH.tracking up
-        [ 25 ] = KEY_CHANNELDOWN,    // CH.tracking down
-
-        [ 19 ] = KEY_KPENTER,        // enter
-        [ 33 ] = KEY_KPDOT,          // . (decimal dot)
+       [  0 ] = KEY_KP0,
+       [  5 ] = KEY_KP1,
+       [  6 ] = KEY_KP2,
+       [  7 ] = KEY_KP3,
+       [  9 ] = KEY_KP4,
+       [ 10 ] = KEY_KP5,
+       [ 11 ] = KEY_KP6,
+       [ 13 ] = KEY_KP7,
+       [ 14 ] = KEY_KP8,
+       [ 15 ] = KEY_KP9,
+
+       [ 42 ] = KEY_VOLUMEUP,
+       [ 17 ] = KEY_VOLUMEDOWN,
+       [ 24 ] = KEY_CHANNELUP,      // CH.tracking up
+       [ 25 ] = KEY_CHANNELDOWN,    // CH.tracking down
+
+       [ 19 ] = KEY_KPENTER,        // enter
+       [ 33 ] = KEY_KPDOT,          // . (decimal dot)
 };
 
 static IR_KEYTAB_TYPE avacssmart_codes[IR_KEYTAB_SIZE] = {
@@ -401,7 +403,183 @@ static IR_KEYTAB_TYPE manli_codes[IR_KEYTAB_SIZE] = {
 
        // 0x1d unused ?
 };
-/* ---------------------------------------------------------------------- */
+
+
+/* Mike Baikov <mike@baikov.com> */
+static IR_KEYTAB_TYPE gotview7135_codes[IR_KEYTAB_SIZE] = {
+
+       [ 33 ] = KEY_POWER,
+       [ 105] = KEY_TV,
+       [ 51 ] = KEY_KP0,
+       [ 81 ] = KEY_KP1,
+       [ 49 ] = KEY_KP2,
+       [ 113] = KEY_KP3,
+       [ 59 ] = KEY_KP4,
+       [ 88 ] = KEY_KP5,
+       [ 65 ] = KEY_KP6,
+       [ 72 ] = KEY_KP7,
+       [ 48 ] = KEY_KP8,
+       [ 83 ] = KEY_KP9,
+       [ 115] = KEY_AGAIN, /* LOOP */
+       [ 10 ] = KEY_AUDIO,
+       [ 97 ] = KEY_PRINT, /* PREVIEW */
+       [ 122] = KEY_VIDEO,
+       [ 32 ] = KEY_CHANNELUP,
+       [ 64 ] = KEY_CHANNELDOWN,
+       [ 24 ] = KEY_VOLUMEDOWN,
+       [ 80 ] = KEY_VOLUMEUP,
+       [ 16 ] = KEY_MUTE,
+       [ 74 ] = KEY_SEARCH,
+       [ 123] = KEY_SHUFFLE, /* SNAPSHOT */
+       [ 34 ] = KEY_RECORD,
+       [ 98 ] = KEY_STOP,
+       [ 120] = KEY_PLAY,
+       [ 57 ] = KEY_REWIND,
+       [ 89 ] = KEY_PAUSE,
+       [ 25 ] = KEY_FORWARD,
+       [  9 ] = KEY_ZOOM,
+
+       [ 82 ] = KEY_F21, /* LIVE TIMESHIFT */
+       [ 26 ] = KEY_F22, /* MIN TIMESHIFT */
+       [ 58 ] = KEY_F23, /* TIMESHIFT */
+       [ 112] = KEY_F24, /* NORMAL TIMESHIFT */
+};
+
+static IR_KEYTAB_TYPE ir_codes_purpletv[IR_KEYTAB_SIZE] = {
+       [ 0x3  ] = KEY_POWER,
+       [ 0x6f ] = KEY_MUTE,
+       [ 0x10 ] = KEY_BACKSPACE,       /* Recall */
+
+       [ 0x11 ] = KEY_KP0,
+       [ 0x4  ] = KEY_KP1,
+       [ 0x5  ] = KEY_KP2,
+       [ 0x6  ] = KEY_KP3,
+       [ 0x8  ] = KEY_KP4,
+       [ 0x9  ] = KEY_KP5,
+       [ 0xa  ] = KEY_KP6,
+       [ 0xc  ] = KEY_KP7,
+       [ 0xd  ] = KEY_KP8,
+       [ 0xe  ] = KEY_KP9,
+       [ 0x12 ] = KEY_KPDOT,           /* 100+ */
+
+       [ 0x7  ] = KEY_VOLUMEUP,
+       [ 0xb  ] = KEY_VOLUMEDOWN,
+       [ 0x1a ] = KEY_KPPLUS,
+       [ 0x18 ] = KEY_KPMINUS,
+       [ 0x15 ] = KEY_UP,
+       [ 0x1d ] = KEY_DOWN,
+       [ 0xf  ] = KEY_CHANNELUP,
+       [ 0x13 ] = KEY_CHANNELDOWN,
+       [ 0x48 ] = KEY_ZOOM,
+
+       [ 0x1b ] = KEY_VIDEO,           /* Video source */
+       [ 0x49 ] = KEY_LANGUAGE,        /* MTS Select */
+       [ 0x19 ] = KEY_SEARCH,          /* Auto Scan */
+
+       [ 0x4b ] = KEY_RECORD,
+       [ 0x46 ] = KEY_PLAY,
+       [ 0x45 ] = KEY_PAUSE,           /* Pause */
+       [ 0x44 ] = KEY_STOP,
+       [ 0x40 ] = KEY_FORWARD,         /* Forward ? */
+       [ 0x42 ] = KEY_REWIND,          /* Backward ? */
+
+};
+
+static IR_KEYTAB_TYPE ir_codes_pinnacle[IR_KEYTAB_SIZE] = {
+       [ 0x59 ] = KEY_MUTE,
+       [ 0x4a ] = KEY_POWER,
+
+       [ 0x18 ] = KEY_TEXT,
+       [ 0x26 ] = KEY_TV,
+       [ 0x3d ] = KEY_PRINT,
+
+       [ 0x48 ] = KEY_RED,
+       [ 0x04 ] = KEY_GREEN,
+       [ 0x11 ] = KEY_YELLOW,
+       [ 0x00 ] = KEY_BLUE,
+
+       [ 0x2d ] = KEY_VOLUMEUP,
+       [ 0x1e ] = KEY_VOLUMEDOWN,
+
+       [ 0x49 ] = KEY_MENU,
+
+       [ 0x16 ] = KEY_CHANNELUP,
+       [ 0x17 ] = KEY_CHANNELDOWN,
+
+       [ 0x20 ] = KEY_UP,
+       [ 0x21 ] = KEY_DOWN,
+       [ 0x22 ] = KEY_LEFT,
+       [ 0x23 ] = KEY_RIGHT,
+       [ 0x0d ] = KEY_SELECT,
+
+
+
+       [ 0x08 ] = KEY_BACK,
+       [ 0x07 ] = KEY_REFRESH,
+
+       [ 0x2f ] = KEY_ZOOM,
+       [ 0x29 ] = KEY_RECORD,
+
+       [ 0x4b ] = KEY_PAUSE,
+       [ 0x4d ] = KEY_REWIND,
+       [ 0x2e ] = KEY_PLAY,
+       [ 0x4e ] = KEY_FORWARD,
+       [ 0x53 ] = KEY_PREVIOUS,
+       [ 0x4c ] = KEY_STOP,
+       [ 0x54 ] = KEY_NEXT,
+
+       [ 0x69 ] = KEY_KP0,
+       [ 0x6a ] = KEY_KP1,
+       [ 0x6b ] = KEY_KP2,
+       [ 0x6c ] = KEY_KP3,
+       [ 0x6d ] = KEY_KP4,
+       [ 0x6e ] = KEY_KP5,
+       [ 0x6f ] = KEY_KP6,
+       [ 0x70 ] = KEY_KP7,
+       [ 0x71 ] = KEY_KP8,
+       [ 0x72 ] = KEY_KP9,
+
+       [ 0x74 ] = KEY_CHANNEL,
+       [ 0x0a ] = KEY_BACKSPACE,
+};
+
+/* Mapping for the 28 key remote control as seen at
+   http://www.sednacomputer.com/photo/cardbus-tv.jpg
+   Pavel Mihaylov <bin@bash.info> */
+static IR_KEYTAB_TYPE pctv_sedna_codes[IR_KEYTAB_SIZE] = {
+       [    0 ] = KEY_KP0,
+       [    1 ] = KEY_KP1,
+       [    2 ] = KEY_KP2,
+       [    3 ] = KEY_KP3,
+       [    4 ] = KEY_KP4,
+       [    5 ] = KEY_KP5,
+       [    6 ] = KEY_KP6,
+       [    7 ] = KEY_KP7,
+       [    8 ] = KEY_KP8,
+       [    9 ] = KEY_KP9,
+
+       [ 0x0a ] = KEY_AGAIN,          /* Recall */
+       [ 0x0b ] = KEY_CHANNELUP,
+       [ 0x0c ] = KEY_VOLUMEUP,
+       [ 0x0d ] = KEY_MODE,           /* Stereo */
+       [ 0x0e ] = KEY_STOP,
+       [ 0x0f ] = KEY_PREVIOUSSONG,
+       [ 0x10 ] = KEY_ZOOM,
+       [ 0x11 ] = KEY_TUNER,          /* Source */
+       [ 0x12 ] = KEY_POWER,
+       [ 0x13 ] = KEY_MUTE,
+       [ 0x15 ] = KEY_CHANNELDOWN,
+       [ 0x18 ] = KEY_VOLUMEDOWN,
+       [ 0x19 ] = KEY_SHUFFLE,        /* Snapshot */
+       [ 0x1a ] = KEY_NEXTSONG,
+       [ 0x1b ] = KEY_TEXT,           /* Time Shift */
+       [ 0x1c ] = KEY_RADIO,          /* FM Radio */
+       [ 0x1d ] = KEY_RECORD,
+       [ 0x1e ] = KEY_PAUSE,
+};
+
+
+/* -------------------- GPIO generic keycode builder -------------------- */
 
 static int build_key(struct saa7134_dev *dev)
 {
@@ -413,13 +591,13 @@ static int build_key(struct saa7134_dev *dev)
        saa_setb(SAA7134_GPIO_GPMODE3,SAA7134_GPIO_GPRESCAN);
 
        gpio = saa_readl(SAA7134_GPIO_GPSTATUS0 >> 2);
-        if (ir->polling) {
-                if (ir->last_gpio == gpio)
-                        return 0;
-                ir->last_gpio = gpio;
-        }
+       if (ir->polling) {
+               if (ir->last_gpio == gpio)
+                       return 0;
+               ir->last_gpio = gpio;
+       }
 
-       data = ir_extract_bits(gpio, ir->mask_keycode);
+       data = ir_extract_bits(gpio, ir->mask_keycode);
        dprintk("build_key gpio=0x%x mask=0x%x data=%d\n",
                gpio, ir->mask_keycode, data);
 
@@ -432,13 +610,87 @@ static int build_key(struct saa7134_dev *dev)
        return 0;
 }
 
-/* ---------------------------------------------------------------------- */
+/* --------------------- Chip specific I2C key builders ----------------- */
+
+static int get_key_purpletv(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw)
+{
+       unsigned char b;
+
+       /* poll IR chip */
+       if (1 != i2c_master_recv(&ir->c,&b,1)) {
+               i2cdprintk("read error\n");
+               return -EIO;
+       }
+
+       /* no button press */
+       if (b==0)
+               return 0;
+
+       /* repeating */
+       if (b & 0x80)
+               return 1;
+
+       *ir_key = b;
+       *ir_raw = b;
+       return 1;
+}
+
+/* The new pinnacle PCTV remote (with the colored buttons)
+ *
+ * Ricardo Cerqueira <v4l@cerqueira.org>
+ */
+
+static int get_key_pinnacle(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw)
+{
+       unsigned char b[4];
+       unsigned int start = 0,parity = 0,code = 0;
+
+       /* poll IR chip */
+       if (4 != i2c_master_recv(&ir->c,b,4)) {
+               i2cdprintk("read error\n");
+               return -EIO;
+       }
+
+       for (start = 0; start<4; start++) {
+               if (b[start] == 0x80) {
+                       code=b[(start+3)%4];
+                       parity=b[(start+2)%4];
+               }
+       }
+
+       /* Empty Request */
+       if (parity==0)
+               return 0;
+
+       /* Repeating... */
+       if (ir->old == parity)
+               return 0;
+
+
+       ir->old = parity;
+
+       /* Reduce code value to fit inside IR_KEYTAB_SIZE
+        *
+        * this is the only value that results in 42 unique
+        * codes < 128
+        */
+
+       code %= 0x88;
+
+       *ir_raw = code;
+       *ir_key = code;
+
+       i2cdprintk("Pinnacle PCTV key %02x\n", code);
+
+       return 1;
+}
+
 
 void saa7134_input_irq(struct saa7134_dev *dev)
 {
-        struct saa7134_ir *ir = dev->remote;
+       struct saa7134_ir *ir = dev->remote;
 
-        if (!ir->polling)
+       if (!ir->polling)
                build_key(dev);
 }
 
@@ -464,7 +716,7 @@ int saa7134_input_init1(struct saa7134_dev *dev)
        int polling      = 0;
        int ir_type      = IR_TYPE_OTHER;
 
-       if (!dev->has_remote)
+       if (dev->has_remote != SAA7134_REMOTE_GPIO)
                return -ENODEV;
        if (disable_ir)
                return -ENODEV;
@@ -473,7 +725,8 @@ int saa7134_input_init1(struct saa7134_dev *dev)
        switch (dev->board) {
        case SAA7134_BOARD_FLYVIDEO2000:
        case SAA7134_BOARD_FLYVIDEO3000:
-        case SAA7134_BOARD_FLYTVPLATINUM_FM:
+       case SAA7134_BOARD_FLYTVPLATINUM_FM:
+       case SAA7134_BOARD_FLYTVPLATINUM_MINI2:
                ir_codes     = flyvideo_codes;
                mask_keycode = 0xEC00000;
                mask_keydown = 0x0040000;
@@ -514,14 +767,33 @@ int saa7134_input_init1(struct saa7134_dev *dev)
                saa_setb(SAA7134_GPIO_GPMODE0, 0x4);
                saa_setb(SAA7134_GPIO_GPSTATUS0, 0x4);
                break;
+       case SAA7134_BOARD_KWORLD_TERMINATOR:
+               ir_codes     = avacssmart_codes;
+               mask_keycode = 0x00001f;
+               mask_keyup   = 0x000060;
+               polling      = 50; // ms
+               break;
        case SAA7134_BOARD_MANLI_MTV001:
        case SAA7134_BOARD_MANLI_MTV002:
+       case SAA7134_BOARD_BEHOLD_409FM:
                ir_codes     = manli_codes;
                mask_keycode = 0x001f00;
                mask_keyup   = 0x004000;
-               mask_keydown = 0x002000;
                polling      = 50; // ms
                break;
+       case SAA7134_BOARD_SEDNA_PC_TV_CARDBUS:
+               ir_codes     = pctv_sedna_codes;
+               mask_keycode = 0x001f00;
+               mask_keyup   = 0x004000;
+               polling      = 50; // ms
+               break;
+       case SAA7134_BOARD_GOTVIEW_7135:
+               ir_codes     = gotview7135_codes;
+               mask_keycode = 0x0003EC;
+               mask_keyup   = 0x008000;
+               mask_keydown = 0x000010;
+               polling      = 50; // ms
+               break;
        case SAA7134_BOARD_VIDEOMATE_TV_PVR:
        case SAA7134_BOARD_VIDEOMATE_TV_GOLD_PLUSII:
                ir_codes     = videomate_tv_pvr_codes;
@@ -529,6 +801,12 @@ int saa7134_input_init1(struct saa7134_dev *dev)
                mask_keyup   = 0x400000;
                polling      = 50; // ms
                break;
+       case SAA7134_BOARD_VIDEOMATE_DVBT_300:
+       case SAA7134_BOARD_VIDEOMATE_DVBT_200:
+               ir_codes     = videomate_tv_pvr_codes;
+               mask_keycode = 0x003F00;
+               mask_keyup   = 0x040000;
+               break;
        }
        if (NULL == ir_codes) {
                printk("%s: Oops: IR config error [card=%d]\n",
@@ -548,7 +826,7 @@ int saa7134_input_init1(struct saa7134_dev *dev)
        ir->mask_keycode = mask_keycode;
        ir->mask_keydown = mask_keydown;
        ir->mask_keyup   = mask_keyup;
-        ir->polling      = polling;
+       ir->polling      = polling;
 
        /* init input device */
        snprintf(ir->name, sizeof(ir->name), "saa7134 IR (%s)",
@@ -596,6 +874,31 @@ void saa7134_input_fini(struct saa7134_dev *dev)
        dev->remote = NULL;
 }
 
+void saa7134_set_i2c_ir(struct saa7134_dev *dev, struct IR_i2c *ir)
+{
+       if (disable_ir) {
+               dprintk("Found supported i2c remote, but IR has been disabled\n");
+               ir->get_key=NULL;
+               return;
+       }
+
+       switch (dev->board) {
+       case SAA7134_BOARD_PINNACLE_PCTV_110i:
+               snprintf(ir->c.name, sizeof(ir->c.name), "Pinnacle PCTV");
+               ir->get_key   = get_key_pinnacle;
+               ir->ir_codes  = ir_codes_pinnacle;
+               break;
+       case SAA7134_BOARD_UPMOST_PURPLE_TV:
+               snprintf(ir->c.name, sizeof(ir->c.name), "Purple TV");
+               ir->get_key   = get_key_purpletv;
+               ir->ir_codes  = ir_codes_purpletv;
+               break;
+       default:
+               dprintk("Shouldn't get here: Unknown board %x for I2C IR?\n",dev->board);
+               break;
+       }
+
+}
 /* ----------------------------------------------------------------------
  * Local variables:
  * c-basic-offset: 8
index c20630c82f1c4007e1de79b36a59e4faadaef101..fd53dfcc16444eb175a03239cf922991ddf0a425 100644 (file)
@@ -44,6 +44,7 @@ MODULE_PARM_DESC(oss_rate,"sample rate (valid are: 32000,48000)");
 #define dprintk(fmt, arg...)   if (oss_debug) \
        printk(KERN_DEBUG "%s/oss: " fmt, dev->name , ## arg)
 
+
 /* ------------------------------------------------------------------ */
 
 static int dsp_buffer_conf(struct saa7134_dev *dev, int blksize, int blocks)
@@ -58,12 +59,12 @@ static int dsp_buffer_conf(struct saa7134_dev *dev, int blksize, int blocks)
        if ((blksize * blocks) > 1024*1024)
                blocks = 1024*1024 / blksize;
 
-       dev->oss.blocks  = blocks;
-       dev->oss.blksize = blksize;
-       dev->oss.bufsize = blksize * blocks;
+       dev->dmasound.blocks  = blocks;
+       dev->dmasound.blksize = blksize;
+       dev->dmasound.bufsize = blksize * blocks;
 
        dprintk("buffer config: %d blocks / %d bytes, %d kB total\n",
-               blocks,blksize,blksize * blocks / 1024);
+               blocks,blksize,blksize * blocks / 1024);
        return 0;
 }
 
@@ -71,11 +72,11 @@ static int dsp_buffer_init(struct saa7134_dev *dev)
 {
        int err;
 
-       if (!dev->oss.bufsize)
+       if (!dev->dmasound.bufsize)
                BUG();
-       videobuf_dma_init(&dev->oss.dma);
-       err = videobuf_dma_init_kernel(&dev->oss.dma, PCI_DMA_FROMDEVICE,
-                                      (dev->oss.bufsize + PAGE_SIZE) >> PAGE_SHIFT);
+       videobuf_dma_init(&dev->dmasound.dma);
+       err = videobuf_dma_init_kernel(&dev->dmasound.dma, PCI_DMA_FROMDEVICE,
+                                      (dev->dmasound.bufsize + PAGE_SIZE) >> PAGE_SHIFT);
        if (0 != err)
                return err;
        return 0;
@@ -83,26 +84,26 @@ static int dsp_buffer_init(struct saa7134_dev *dev)
 
 static int dsp_buffer_free(struct saa7134_dev *dev)
 {
-       if (!dev->oss.blksize)
+       if (!dev->dmasound.blksize)
                BUG();
-       videobuf_dma_free(&dev->oss.dma);
-       dev->oss.blocks  = 0;
-       dev->oss.blksize = 0;
-       dev->oss.bufsize = 0;
+       videobuf_dma_free(&dev->dmasound.dma);
+       dev->dmasound.blocks  = 0;
+       dev->dmasound.blksize = 0;
+       dev->dmasound.bufsize = 0;
        return 0;
 }
 
 static void dsp_dma_start(struct saa7134_dev *dev)
 {
-       dev->oss.dma_blk     = 0;
-       dev->oss.dma_running = 1;
+       dev->dmasound.dma_blk     = 0;
+       dev->dmasound.dma_running = 1;
        saa7134_set_dmabits(dev);
 }
 
 static void dsp_dma_stop(struct saa7134_dev *dev)
 {
-       dev->oss.dma_blk     = -1;
-       dev->oss.dma_running = 0;
+       dev->dmasound.dma_blk     = -1;
+       dev->dmasound.dma_running = 0;
        saa7134_set_dmabits(dev);
 }
 
@@ -113,18 +114,18 @@ static int dsp_rec_start(struct saa7134_dev *dev)
        unsigned long flags;
 
        /* prepare buffer */
-       if (0 != (err = videobuf_dma_pci_map(dev->pci,&dev->oss.dma)))
+       if (0 != (err = videobuf_dma_pci_map(dev->pci,&dev->dmasound.dma)))
                return err;
-       if (0 != (err = saa7134_pgtable_alloc(dev->pci,&dev->oss.pt)))
+       if (0 != (err = saa7134_pgtable_alloc(dev->pci,&dev->dmasound.pt)))
                goto fail1;
-       if (0 != (err = saa7134_pgtable_build(dev->pci,&dev->oss.pt,
-                                             dev->oss.dma.sglist,
-                                             dev->oss.dma.sglen,
+       if (0 != (err = saa7134_pgtable_build(dev->pci,&dev->dmasound.pt,
+                                             dev->dmasound.dma.sglist,
+                                             dev->dmasound.dma.sglen,
                                              0)))
                goto fail2;
 
        /* sample format */
-       switch (dev->oss.afmt) {
+       switch (dev->dmasound.afmt) {
        case AFMT_U8:
        case AFMT_S8:     fmt = 0x00;  break;
        case AFMT_U16_LE:
@@ -136,14 +137,14 @@ static int dsp_rec_start(struct saa7134_dev *dev)
                goto fail2;
        }
 
-       switch (dev->oss.afmt) {
+       switch (dev->dmasound.afmt) {
        case AFMT_S8:
        case AFMT_S16_LE:
        case AFMT_S16_BE: sign = 1; break;
        default:          sign = 0; break;
        }
 
-       switch (dev->oss.afmt) {
+       switch (dev->dmasound.afmt) {
        case AFMT_U16_BE:
        case AFMT_S16_BE: bswap = 1; break;
        default:          bswap = 0; break;
@@ -151,58 +152,58 @@ static int dsp_rec_start(struct saa7134_dev *dev)
 
        switch (dev->pci->device) {
        case PCI_DEVICE_ID_PHILIPS_SAA7134:
-               if (1 == dev->oss.channels)
+               if (1 == dev->dmasound.channels)
                        fmt |= (1 << 3);
-               if (2 == dev->oss.channels)
+               if (2 == dev->dmasound.channels)
                        fmt |= (3 << 3);
                if (sign)
                        fmt |= 0x04;
-               fmt |= (TV == dev->oss.input) ? 0xc0 : 0x80;
+               fmt |= (TV == dev->dmasound.input) ? 0xc0 : 0x80;
 
-               saa_writeb(SAA7134_NUM_SAMPLES0, ((dev->oss.blksize - 1) & 0x0000ff));
-               saa_writeb(SAA7134_NUM_SAMPLES1, ((dev->oss.blksize - 1) & 0x00ff00) >>  8);
-               saa_writeb(SAA7134_NUM_SAMPLES2, ((dev->oss.blksize - 1) & 0xff0000) >> 16);
+               saa_writeb(SAA7134_NUM_SAMPLES0, ((dev->dmasound.blksize - 1) & 0x0000ff));
+               saa_writeb(SAA7134_NUM_SAMPLES1, ((dev->dmasound.blksize - 1) & 0x00ff00) >>  8);
+               saa_writeb(SAA7134_NUM_SAMPLES2, ((dev->dmasound.blksize - 1) & 0xff0000) >> 16);
                saa_writeb(SAA7134_AUDIO_FORMAT_CTRL, fmt);
 
                break;
        case PCI_DEVICE_ID_PHILIPS_SAA7133:
        case PCI_DEVICE_ID_PHILIPS_SAA7135:
-               if (1 == dev->oss.channels)
+               if (1 == dev->dmasound.channels)
                        fmt |= (1 << 4);
-               if (2 == dev->oss.channels)
+               if (2 == dev->dmasound.channels)
                        fmt |= (2 << 4);
                if (!sign)
                        fmt |= 0x04;
-               saa_writel(0x588 >> 2, dev->oss.blksize -4);
-               saa_writel(0x58c >> 2, 0x543210 | (fmt << 24));
+               saa_writel(SAA7133_NUM_SAMPLES, dev->dmasound.blksize -4);
+               saa_writel(SAA7133_AUDIO_CHANNEL, 0x543210 | (fmt << 24));
                break;
        }
        dprintk("rec_start: afmt=%d ch=%d  =>  fmt=0x%x swap=%c\n",
-               dev->oss.afmt, dev->oss.channels, fmt,
+               dev->dmasound.afmt, dev->dmasound.channels, fmt,
                bswap ? 'b' : '-');
 
        /* dma: setup channel 6 (= AUDIO) */
        control = SAA7134_RS_CONTROL_BURST_16 |
                SAA7134_RS_CONTROL_ME |
-               (dev->oss.pt.dma >> 12);
+               (dev->dmasound.pt.dma >> 12);
        if (bswap)
                control |= SAA7134_RS_CONTROL_BSWAP;
        saa_writel(SAA7134_RS_BA1(6),0);
-       saa_writel(SAA7134_RS_BA2(6),dev->oss.blksize);
+       saa_writel(SAA7134_RS_BA2(6),dev->dmasound.blksize);
        saa_writel(SAA7134_RS_PITCH(6),0);
        saa_writel(SAA7134_RS_CONTROL(6),control);
 
        /* start dma */
-       dev->oss.recording_on = 1;
+       dev->dmasound.recording_on = 1;
        spin_lock_irqsave(&dev->slock,flags);
        dsp_dma_start(dev);
        spin_unlock_irqrestore(&dev->slock,flags);
        return 0;
 
  fail2:
-       saa7134_pgtable_free(dev->pci,&dev->oss.pt);
+       saa7134_pgtable_free(dev->pci,&dev->dmasound.pt);
  fail1:
-       videobuf_dma_pci_unmap(dev->pci,&dev->oss.dma);
+       videobuf_dma_pci_unmap(dev->pci,&dev->dmasound.dma);
        return err;
 }
 
@@ -210,17 +211,17 @@ static int dsp_rec_stop(struct saa7134_dev *dev)
 {
        unsigned long flags;
 
-       dprintk("rec_stop dma_blk=%d\n",dev->oss.dma_blk);
+       dprintk("rec_stop dma_blk=%d\n",dev->dmasound.dma_blk);
 
        /* stop dma */
-       dev->oss.recording_on = 0;
+       dev->dmasound.recording_on = 0;
        spin_lock_irqsave(&dev->slock,flags);
        dsp_dma_stop(dev);
        spin_unlock_irqrestore(&dev->slock,flags);
 
        /* unlock buffer */
-       saa7134_pgtable_free(dev->pci,&dev->oss.pt);
-       videobuf_dma_pci_unmap(dev->pci,&dev->oss.dma);
+       saa7134_pgtable_free(dev->pci,&dev->dmasound.pt);
+       videobuf_dma_pci_unmap(dev->pci,&dev->dmasound.dma);
        return 0;
 }
 
@@ -235,35 +236,35 @@ static int dsp_open(struct inode *inode, struct file *file)
 
        list_for_each(list,&saa7134_devlist) {
                h = list_entry(list, struct saa7134_dev, devlist);
-               if (h->oss.minor_dsp == minor)
+               if (h->dmasound.minor_dsp == minor)
                        dev = h;
        }
        if (NULL == dev)
                return -ENODEV;
 
-       down(&dev->oss.lock);
+       down(&dev->dmasound.lock);
        err = -EBUSY;
-       if (dev->oss.users_dsp)
+       if (dev->dmasound.users_dsp)
                goto fail1;
-       dev->oss.users_dsp++;
+       dev->dmasound.users_dsp++;
        file->private_data = dev;
 
-       dev->oss.afmt        = AFMT_U8;
-       dev->oss.channels    = 1;
-       dev->oss.read_count  = 0;
-       dev->oss.read_offset = 0;
+       dev->dmasound.afmt        = AFMT_U8;
+       dev->dmasound.channels    = 1;
+       dev->dmasound.read_count  = 0;
+       dev->dmasound.read_offset = 0;
        dsp_buffer_conf(dev,PAGE_SIZE,64);
        err = dsp_buffer_init(dev);
        if (0 != err)
                goto fail2;
 
-       up(&dev->oss.lock);
+       up(&dev->dmasound.lock);
        return 0;
 
  fail2:
-       dev->oss.users_dsp--;
+       dev->dmasound.users_dsp--;
  fail1:
-       up(&dev->oss.lock);
+       up(&dev->dmasound.lock);
        return err;
 }
 
@@ -271,13 +272,13 @@ static int dsp_release(struct inode *inode, struct file *file)
 {
        struct saa7134_dev *dev = file->private_data;
 
-       down(&dev->oss.lock);
-       if (dev->oss.recording_on)
+       down(&dev->dmasound.lock);
+       if (dev->dmasound.recording_on)
                dsp_rec_stop(dev);
        dsp_buffer_free(dev);
-       dev->oss.users_dsp--;
+       dev->dmasound.users_dsp--;
        file->private_data = NULL;
-       up(&dev->oss.lock);
+       up(&dev->dmasound.lock);
        return 0;
 }
 
@@ -290,12 +291,12 @@ static ssize_t dsp_read(struct file *file, char __user *buffer,
        unsigned long flags;
        int err,ret = 0;
 
-       add_wait_queue(&dev->oss.wq, &wait);
-       down(&dev->oss.lock);
+       add_wait_queue(&dev->dmasound.wq, &wait);
+       down(&dev->dmasound.lock);
        while (count > 0) {
                /* wait for data if needed */
-               if (0 == dev->oss.read_count) {
-                       if (!dev->oss.recording_on) {
+               if (0 == dev->dmasound.read_count) {
+                       if (!dev->dmasound.recording_on) {
                                err = dsp_rec_start(dev);
                                if (err < 0) {
                                        if (0 == ret)
@@ -303,8 +304,8 @@ static ssize_t dsp_read(struct file *file, char __user *buffer,
                                        break;
                                }
                        }
-                       if (dev->oss.recording_on &&
-                           !dev->oss.dma_running) {
+                       if (dev->dmasound.recording_on &&
+                           !dev->dmasound.dma_running) {
                                /* recover from overruns */
                                spin_lock_irqsave(&dev->slock,flags);
                                dsp_dma_start(dev);
@@ -315,12 +316,12 @@ static ssize_t dsp_read(struct file *file, char __user *buffer,
                                        ret = -EAGAIN;
                                break;
                        }
-                       up(&dev->oss.lock);
+                       up(&dev->dmasound.lock);
                        set_current_state(TASK_INTERRUPTIBLE);
-                       if (0 == dev->oss.read_count)
+                       if (0 == dev->dmasound.read_count)
                                schedule();
                        set_current_state(TASK_RUNNING);
-                       down(&dev->oss.lock);
+                       down(&dev->dmasound.lock);
                        if (signal_pending(current)) {
                                if (0 == ret)
                                        ret = -EINTR;
@@ -330,12 +331,12 @@ static ssize_t dsp_read(struct file *file, char __user *buffer,
 
                /* copy data to userspace */
                bytes = count;
-               if (bytes > dev->oss.read_count)
-                       bytes = dev->oss.read_count;
-               if (bytes > dev->oss.bufsize - dev->oss.read_offset)
-                       bytes = dev->oss.bufsize - dev->oss.read_offset;
+               if (bytes > dev->dmasound.read_count)
+                       bytes = dev->dmasound.read_count;
+               if (bytes > dev->dmasound.bufsize - dev->dmasound.read_offset)
+                       bytes = dev->dmasound.bufsize - dev->dmasound.read_offset;
                if (copy_to_user(buffer + ret,
-                                dev->oss.dma.vmalloc + dev->oss.read_offset,
+                                dev->dmasound.dma.vmalloc + dev->dmasound.read_offset,
                                 bytes)) {
                        if (0 == ret)
                                ret = -EFAULT;
@@ -344,13 +345,13 @@ static ssize_t dsp_read(struct file *file, char __user *buffer,
 
                ret   += bytes;
                count -= bytes;
-               dev->oss.read_count  -= bytes;
-               dev->oss.read_offset += bytes;
-               if (dev->oss.read_offset == dev->oss.bufsize)
-                       dev->oss.read_offset = 0;
+               dev->dmasound.read_count  -= bytes;
+               dev->dmasound.read_offset += bytes;
+               if (dev->dmasound.read_offset == dev->dmasound.bufsize)
+                       dev->dmasound.read_offset = 0;
        }
-       up(&dev->oss.lock);
-       remove_wait_queue(&dev->oss.wq, &wait);
+       up(&dev->dmasound.lock);
+       remove_wait_queue(&dev->dmasound.wq, &wait);
        return ret;
 }
 
@@ -370,53 +371,53 @@ static int dsp_ioctl(struct inode *inode, struct file *file,
 
        if (oss_debug > 1)
                saa7134_print_ioctl(dev->name,cmd);
-        switch (cmd) {
-        case OSS_GETVERSION:
-                return put_user(SOUND_VERSION, p);
-        case SNDCTL_DSP_GETCAPS:
+       switch (cmd) {
+       case OSS_GETVERSION:
+               return put_user(SOUND_VERSION, p);
+       case SNDCTL_DSP_GETCAPS:
                return 0;
 
-        case SNDCTL_DSP_SPEED:
+       case SNDCTL_DSP_SPEED:
                if (get_user(val, p))
                        return -EFAULT;
                /* fall through */
-        case SOUND_PCM_READ_RATE:
-               return put_user(dev->oss.rate, p);
+       case SOUND_PCM_READ_RATE:
+               return put_user(dev->dmasound.rate, p);
 
-        case SNDCTL_DSP_STEREO:
+       case SNDCTL_DSP_STEREO:
                if (get_user(val, p))
                        return -EFAULT;
-               down(&dev->oss.lock);
-               dev->oss.channels = val ? 2 : 1;
-               if (dev->oss.recording_on) {
+               down(&dev->dmasound.lock);
+               dev->dmasound.channels = val ? 2 : 1;
+               if (dev->dmasound.recording_on) {
                        dsp_rec_stop(dev);
                        dsp_rec_start(dev);
                }
-               up(&dev->oss.lock);
-               return put_user(dev->oss.channels-1, p);
+               up(&dev->dmasound.lock);
+               return put_user(dev->dmasound.channels-1, p);
 
-        case SNDCTL_DSP_CHANNELS:
+       case SNDCTL_DSP_CHANNELS:
                if (get_user(val, p))
                        return -EFAULT;
                if (val != 1 && val != 2)
                        return -EINVAL;
-               down(&dev->oss.lock);
-               dev->oss.channels = val;
-               if (dev->oss.recording_on) {
+               down(&dev->dmasound.lock);
+               dev->dmasound.channels = val;
+               if (dev->dmasound.recording_on) {
                        dsp_rec_stop(dev);
                        dsp_rec_start(dev);
                }
-               up(&dev->oss.lock);
+               up(&dev->dmasound.lock);
                /* fall through */
-        case SOUND_PCM_READ_CHANNELS:
-               return put_user(dev->oss.channels, p);
+       case SOUND_PCM_READ_CHANNELS:
+               return put_user(dev->dmasound.channels, p);
 
-        case SNDCTL_DSP_GETFMTS: /* Returns a mask */
+       case SNDCTL_DSP_GETFMTS: /* Returns a mask */
                return put_user(AFMT_U8     | AFMT_S8     |
                                AFMT_U16_LE | AFMT_U16_BE |
                                AFMT_S16_LE | AFMT_S16_BE, p);
 
-        case SNDCTL_DSP_SETFMT: /* Selects ONE fmt */
+       case SNDCTL_DSP_SETFMT: /* Selects ONE fmt */
                if (get_user(val, p))
                        return -EFAULT;
                switch (val) {
@@ -429,20 +430,20 @@ static int dsp_ioctl(struct inode *inode, struct file *file,
                case AFMT_U16_BE:
                case AFMT_S16_LE:
                case AFMT_S16_BE:
-                       down(&dev->oss.lock);
-                       dev->oss.afmt = val;
-                       if (dev->oss.recording_on) {
+                       down(&dev->dmasound.lock);
+                       dev->dmasound.afmt = val;
+                       if (dev->dmasound.recording_on) {
                                dsp_rec_stop(dev);
                                dsp_rec_start(dev);
                        }
-                       up(&dev->oss.lock);
-                       return put_user(dev->oss.afmt, p);
+                       up(&dev->dmasound.lock);
+                       return put_user(dev->dmasound.afmt, p);
                default:
                        return -EINVAL;
                }
 
-        case SOUND_PCM_READ_BITS:
-               switch (dev->oss.afmt) {
+       case SOUND_PCM_READ_BITS:
+               switch (dev->dmasound.afmt) {
                case AFMT_U8:
                case AFMT_S8:
                        return put_user(8, p);
@@ -455,23 +456,23 @@ static int dsp_ioctl(struct inode *inode, struct file *file,
                        return -EINVAL;
                }
 
-        case SNDCTL_DSP_NONBLOCK:
-                file->f_flags |= O_NONBLOCK;
-                return 0;
+       case SNDCTL_DSP_NONBLOCK:
+               file->f_flags |= O_NONBLOCK;
+               return 0;
 
-        case SNDCTL_DSP_RESET:
-               down(&dev->oss.lock);
-               if (dev->oss.recording_on)
+       case SNDCTL_DSP_RESET:
+               down(&dev->dmasound.lock);
+               if (dev->dmasound.recording_on)
                        dsp_rec_stop(dev);
-               up(&dev->oss.lock);
+               up(&dev->dmasound.lock);
                return 0;
-        case SNDCTL_DSP_GETBLKSIZE:
-               return put_user(dev->oss.blksize, p);
+       case SNDCTL_DSP_GETBLKSIZE:
+               return put_user(dev->dmasound.blksize, p);
 
-        case SNDCTL_DSP_SETFRAGMENT:
+       case SNDCTL_DSP_SETFRAGMENT:
                if (get_user(val, p))
                        return -EFAULT;
-               if (dev->oss.recording_on)
+               if (dev->dmasound.recording_on)
                        return -EBUSY;
                dsp_buffer_free(dev);
                /* used to be arg >> 16 instead of val >> 16; fixed */
@@ -479,16 +480,16 @@ static int dsp_ioctl(struct inode *inode, struct file *file,
                dsp_buffer_init(dev);
                return 0;
 
-        case SNDCTL_DSP_SYNC:
+       case SNDCTL_DSP_SYNC:
                /* NOP */
                return 0;
 
        case SNDCTL_DSP_GETISPACE:
        {
                audio_buf_info info;
-               info.fragsize   = dev->oss.blksize;
-               info.fragstotal = dev->oss.blocks;
-               info.bytes      = dev->oss.read_count;
+               info.fragsize   = dev->dmasound.blksize;
+               info.fragstotal = dev->dmasound.blocks;
+               info.bytes      = dev->dmasound.read_count;
                info.fragments  = info.bytes / info.fragsize;
                if (copy_to_user(argp, &info, sizeof(info)))
                        return -EFAULT;
@@ -504,13 +505,13 @@ static unsigned int dsp_poll(struct file *file, struct poll_table_struct *wait)
        struct saa7134_dev *dev = file->private_data;
        unsigned int mask = 0;
 
-       poll_wait(file, &dev->oss.wq, wait);
+       poll_wait(file, &dev->dmasound.wq, wait);
 
-       if (0 == dev->oss.read_count) {
-               down(&dev->oss.lock);
-               if (!dev->oss.recording_on)
+       if (0 == dev->dmasound.read_count) {
+               down(&dev->dmasound.lock);
+               if (!dev->dmasound.recording_on)
                        dsp_rec_start(dev);
-               up(&dev->oss.lock);
+               up(&dev->dmasound.lock);
        } else
                mask |= (POLLIN | POLLRDNORM);
        return mask;
@@ -534,7 +535,7 @@ mixer_recsrc_7134(struct saa7134_dev *dev)
 {
        int analog_io,rate;
 
-       switch (dev->oss.input) {
+       switch (dev->dmasound.input) {
        case TV:
                saa_andorb(SAA7134_AUDIO_FORMAT_CTRL, 0xc0, 0xc0);
                saa_andorb(SAA7134_SIF_SAMPLE_FREQ,   0x03, 0x00);
@@ -542,8 +543,8 @@ mixer_recsrc_7134(struct saa7134_dev *dev)
        case LINE1:
        case LINE2:
        case LINE2_LEFT:
-               analog_io = (LINE1 == dev->oss.input) ? 0x00 : 0x08;
-               rate = (32000 == dev->oss.rate) ? 0x01 : 0x03;
+               analog_io = (LINE1 == dev->dmasound.input) ? 0x00 : 0x08;
+               rate = (32000 == dev->dmasound.rate) ? 0x01 : 0x03;
                saa_andorb(SAA7134_ANALOG_IO_SELECT,  0x08, analog_io);
                saa_andorb(SAA7134_AUDIO_FORMAT_CTRL, 0xc0, 0x80);
                saa_andorb(SAA7134_SIF_SAMPLE_FREQ,   0x03, rate);
@@ -559,10 +560,10 @@ mixer_recsrc_7133(struct saa7134_dev *dev)
 
        xbarin = 0x03; // adc
     anabar = 0;
-       switch (dev->oss.input) {
+       switch (dev->dmasound.input) {
        case TV:
                xbarin = 0; // Demodulator
-        anabar = 2; // DACs
+       anabar = 2; // DACs
                break;
        case LINE1:
                anabar = 0;  // aux1, aux1
@@ -585,9 +586,9 @@ mixer_recsrc(struct saa7134_dev *dev, enum saa7134_audio_in src)
 {
        static const char *iname[] = { "Oops", "TV", "LINE1", "LINE2" };
 
-       dev->oss.count++;
-       dev->oss.input = src;
-       dprintk("mixer input = %s\n",iname[dev->oss.input]);
+       dev->dmasound.count++;
+       dev->dmasound.input = src;
+       dprintk("mixer input = %s\n",iname[dev->dmasound.input]);
 
        switch (dev->pci->device) {
        case PCI_DEVICE_ID_PHILIPS_SAA7134:
@@ -639,7 +640,7 @@ static int mixer_open(struct inode *inode, struct file *file)
 
        list_for_each(list,&saa7134_devlist) {
                h = list_entry(list, struct saa7134_dev, devlist);
-               if (h->oss.minor_mixer == minor)
+               if (h->dmasound.minor_mixer == minor)
                        dev = h;
        }
        if (NULL == dev)
@@ -666,28 +667,28 @@ static int mixer_ioctl(struct inode *inode, struct file *file,
 
        if (oss_debug > 1)
                saa7134_print_ioctl(dev->name,cmd);
-        switch (cmd) {
-        case OSS_GETVERSION:
-                return put_user(SOUND_VERSION, p);
+       switch (cmd) {
+       case OSS_GETVERSION:
+               return put_user(SOUND_VERSION, p);
        case SOUND_MIXER_INFO:
        {
                mixer_info info;
                memset(&info,0,sizeof(info));
-                strlcpy(info.id,   "TV audio", sizeof(info.id));
-                strlcpy(info.name, dev->name,  sizeof(info.name));
-                info.modify_counter = dev->oss.count;
-                if (copy_to_user(argp, &info, sizeof(info)))
-                        return -EFAULT;
+               strlcpy(info.id,   "TV audio", sizeof(info.id));
+               strlcpy(info.name, dev->name,  sizeof(info.name));
+               info.modify_counter = dev->dmasound.count;
+               if (copy_to_user(argp, &info, sizeof(info)))
+                       return -EFAULT;
                return 0;
        }
        case SOUND_OLD_MIXER_INFO:
        {
                _old_mixer_info info;
                memset(&info,0,sizeof(info));
-                strlcpy(info.id,   "TV audio", sizeof(info.id));
-                strlcpy(info.name, dev->name,  sizeof(info.name));
-                if (copy_to_user(argp, &info, sizeof(info)))
-                        return -EFAULT;
+               strlcpy(info.id,   "TV audio", sizeof(info.id));
+               strlcpy(info.name, dev->name,  sizeof(info.name));
+               if (copy_to_user(argp, &info, sizeof(info)))
+                       return -EFAULT;
                return 0;
        }
        case MIXER_READ(SOUND_MIXER_CAPS):
@@ -697,26 +698,26 @@ static int mixer_ioctl(struct inode *inode, struct file *file,
        case MIXER_READ(SOUND_MIXER_RECMASK):
        case MIXER_READ(SOUND_MIXER_DEVMASK):
                val = SOUND_MASK_LINE1 | SOUND_MASK_LINE2;
-               if (32000 == dev->oss.rate)
+               if (32000 == dev->dmasound.rate)
                        val |= SOUND_MASK_VIDEO;
                return put_user(val, p);
 
        case MIXER_WRITE(SOUND_MIXER_RECSRC):
                if (get_user(val, p))
                        return -EFAULT;
-               input = dev->oss.input;
-               if (32000 == dev->oss.rate  &&
-                   val & SOUND_MASK_VIDEO  &&  dev->oss.input != TV)
+               input = dev->dmasound.input;
+               if (32000 == dev->dmasound.rate  &&
+                   val & SOUND_MASK_VIDEO  &&  dev->dmasound.input != TV)
                        input = TV;
-               if (val & SOUND_MASK_LINE1  &&  dev->oss.input != LINE1)
+               if (val & SOUND_MASK_LINE1  &&  dev->dmasound.input != LINE1)
                        input = LINE1;
-               if (val & SOUND_MASK_LINE2  &&  dev->oss.input != LINE2)
+               if (val & SOUND_MASK_LINE2  &&  dev->dmasound.input != LINE2)
                        input = LINE2;
-               if (input != dev->oss.input)
+               if (input != dev->dmasound.input)
                        mixer_recsrc(dev,input);
                /* fall throuth */
        case MIXER_READ(SOUND_MIXER_RECSRC):
-               switch (dev->oss.input) {
+               switch (dev->dmasound.input) {
                case TV:    ret = SOUND_MASK_VIDEO; break;
                case LINE1: ret = SOUND_MASK_LINE1; break;
                case LINE2: ret = SOUND_MASK_LINE2; break;
@@ -726,7 +727,7 @@ static int mixer_ioctl(struct inode *inode, struct file *file,
 
        case MIXER_WRITE(SOUND_MIXER_VIDEO):
        case MIXER_READ(SOUND_MIXER_VIDEO):
-               if (32000 != dev->oss.rate)
+               if (32000 != dev->dmasound.rate)
                        return -EINVAL;
                return put_user(100 | 100 << 8, p);
 
@@ -735,22 +736,22 @@ static int mixer_ioctl(struct inode *inode, struct file *file,
                        return -EFAULT;
                val &= 0xff;
                val = (val <= 50) ? 50 : 100;
-               dev->oss.line1 = val;
-               mixer_level(dev,LINE1,dev->oss.line1);
+               dev->dmasound.line1 = val;
+               mixer_level(dev,LINE1,dev->dmasound.line1);
                /* fall throuth */
        case MIXER_READ(SOUND_MIXER_LINE1):
-               return put_user(dev->oss.line1 | dev->oss.line1 << 8, p);
+               return put_user(dev->dmasound.line1 | dev->dmasound.line1 << 8, p);
 
        case MIXER_WRITE(SOUND_MIXER_LINE2):
                if (get_user(val, p))
                        return -EFAULT;
                val &= 0xff;
                val = (val <= 50) ? 50 : 100;
-               dev->oss.line2 = val;
-               mixer_level(dev,LINE2,dev->oss.line2);
+               dev->dmasound.line2 = val;
+               mixer_level(dev,LINE2,dev->dmasound.line2);
                /* fall throuth */
        case MIXER_READ(SOUND_MIXER_LINE2):
-               return put_user(dev->oss.line2 | dev->oss.line2 << 8, p);
+               return put_user(dev->dmasound.line2 | dev->dmasound.line2 << 8, p);
 
        default:
                return -EINVAL;
@@ -770,8 +771,8 @@ struct file_operations saa7134_mixer_fops = {
 int saa7134_oss_init1(struct saa7134_dev *dev)
 {
        /* general */
-        init_MUTEX(&dev->oss.lock);
-       init_waitqueue_head(&dev->oss.wq);
+       init_MUTEX(&dev->dmasound.lock);
+       init_waitqueue_head(&dev->dmasound.wq);
 
        switch (dev->pci->device) {
        case PCI_DEVICE_ID_PHILIPS_SAA7133:
@@ -783,17 +784,17 @@ int saa7134_oss_init1(struct saa7134_dev *dev)
        }
 
        /* dsp */
-       dev->oss.rate = 32000;
+       dev->dmasound.rate = 32000;
        if (oss_rate)
-               dev->oss.rate = oss_rate;
-       dev->oss.rate = (dev->oss.rate > 40000) ? 48000 : 32000;
+               dev->dmasound.rate = oss_rate;
+       dev->dmasound.rate = (dev->dmasound.rate > 40000) ? 48000 : 32000;
 
        /* mixer */
-       dev->oss.line1 = 50;
-       dev->oss.line2 = 50;
-       mixer_level(dev,LINE1,dev->oss.line1);
-       mixer_level(dev,LINE2,dev->oss.line2);
-       mixer_recsrc(dev, (dev->oss.rate == 32000) ? TV : LINE2);
+       dev->dmasound.line1 = 50;
+       dev->dmasound.line2 = 50;
+       mixer_level(dev,LINE1,dev->dmasound.line1);
+       mixer_level(dev,LINE2,dev->dmasound.line2);
+       mixer_recsrc(dev, (dev->dmasound.rate == 32000) ? TV : LINE2);
 
        return 0;
 }
@@ -809,7 +810,7 @@ void saa7134_irq_oss_done(struct saa7134_dev *dev, unsigned long status)
        int next_blk, reg = 0;
 
        spin_lock(&dev->slock);
-       if (UNSET == dev->oss.dma_blk) {
+       if (UNSET == dev->dmasound.dma_blk) {
                dprintk("irq: recording stopped\n");
                goto done;
        }
@@ -817,11 +818,11 @@ void saa7134_irq_oss_done(struct saa7134_dev *dev, unsigned long status)
                dprintk("irq: lost %ld\n", (status >> 24) & 0x0f);
        if (0 == (status & 0x10000000)) {
                /* odd */
-               if (0 == (dev->oss.dma_blk & 0x01))
+               if (0 == (dev->dmasound.dma_blk & 0x01))
                        reg = SAA7134_RS_BA1(6);
        } else {
                /* even */
-               if (1 == (dev->oss.dma_blk & 0x01))
+               if (1 == (dev->dmasound.dma_blk & 0x01))
                        reg = SAA7134_RS_BA2(6);
        }
        if (0 == reg) {
@@ -829,25 +830,25 @@ void saa7134_irq_oss_done(struct saa7134_dev *dev, unsigned long status)
                        (status & 0x10000000) ? "even" : "odd");
                goto done;
        }
-       if (dev->oss.read_count >= dev->oss.blksize * (dev->oss.blocks-2)) {
-               dprintk("irq: overrun [full=%d/%d]\n",dev->oss.read_count,
-                       dev->oss.bufsize);
+       if (dev->dmasound.read_count >= dev->dmasound.blksize * (dev->dmasound.blocks-2)) {
+               dprintk("irq: overrun [full=%d/%d]\n",dev->dmasound.read_count,
+                       dev->dmasound.bufsize);
                dsp_dma_stop(dev);
                goto done;
        }
 
        /* next block addr */
-       next_blk = (dev->oss.dma_blk + 2) % dev->oss.blocks;
-       saa_writel(reg,next_blk * dev->oss.blksize);
+       next_blk = (dev->dmasound.dma_blk + 2) % dev->dmasound.blocks;
+       saa_writel(reg,next_blk * dev->dmasound.blksize);
        if (oss_debug > 2)
                dprintk("irq: ok, %s, next_blk=%d, addr=%x\n",
                        (status & 0x10000000) ? "even" : "odd ", next_blk,
-                       next_blk * dev->oss.blksize);
+                       next_blk * dev->dmasound.blksize);
 
        /* update status & wake waiting readers */
-       dev->oss.dma_blk = (dev->oss.dma_blk + 1) % dev->oss.blocks;
-       dev->oss.read_count += dev->oss.blksize;
-       wake_up(&dev->oss.wq);
+       dev->dmasound.dma_blk = (dev->dmasound.dma_blk + 1) % dev->dmasound.blocks;
+       dev->dmasound.read_count += dev->dmasound.blksize;
+       wake_up(&dev->dmasound.wq);
 
  done:
        spin_unlock(&dev->slock);
index ae0c7a165390a2f88fd1a7326eec51738c524710..ac6431ba4fc37e9467b1c43b3ebb76582ff424f1 100644 (file)
@@ -27,7 +27,7 @@
 
 /* DMA channels, n = 0 ... 6 */
 #define SAA7134_RS_BA1(n)                      ((0x200 >> 2) + 4*n)
-#define SAA7134_RS_BA2(n)                      ((0x204 >> 2) + 4*n)
+#define SAA7134_RS_BA2(n)                      ((0x204 >> 2) + 4*n)
 #define SAA7134_RS_PITCH(n)                    ((0x208 >> 2) + 4*n)
 #define SAA7134_RS_CONTROL(n)                  ((0x20c >> 2) + 4*n)
 #define   SAA7134_RS_CONTROL_WSWAP             (0x01 << 25)
 #define SAA7134_FIFO_SIZE                       (0x2a0 >> 2)
 #define SAA7134_THRESHOULD                      (0x2a4 >> 2)
 
+#define SAA7133_NUM_SAMPLES                    (0x588 >> 2)
+#define SAA7133_AUDIO_CHANNEL                  (0x58c >> 2)
+#define SAA7133_AUDIO_FORMAT                   (0x58f >> 2)
+#define SAA7133_DIGITAL_OUTPUT_SEL1            (0x46c >> 2)
+#define SAA7133_DIGITAL_OUTPUT_SEL2            (0x470 >> 2)
+#define SAA7133_DIGITAL_INPUT_XBAR1            (0x464 >> 2)
+#define SAA7133_ANALOG_IO_SELECT                (0x594 >> 2)
+
 /* main control */
 #define SAA7134_MAIN_CTRL                       (0x2a8 >> 2)
-#define   SAA7134_MAIN_CTRL_VPLLE              (1 << 15)
-#define   SAA7134_MAIN_CTRL_APLLE              (1 << 14)
-#define   SAA7134_MAIN_CTRL_EXOSC              (1 << 13)
-#define   SAA7134_MAIN_CTRL_EVFE1              (1 << 12)
-#define   SAA7134_MAIN_CTRL_EVFE2              (1 << 11)
-#define   SAA7134_MAIN_CTRL_ESFE               (1 << 10)
-#define   SAA7134_MAIN_CTRL_EBADC              (1 << 9)
-#define   SAA7134_MAIN_CTRL_EBDAC              (1 << 8)
+#define   SAA7134_MAIN_CTRL_VPLLE              (1 << 15)
+#define   SAA7134_MAIN_CTRL_APLLE              (1 << 14)
+#define   SAA7134_MAIN_CTRL_EXOSC              (1 << 13)
+#define   SAA7134_MAIN_CTRL_EVFE1              (1 << 12)
+#define   SAA7134_MAIN_CTRL_EVFE2              (1 << 11)
+#define   SAA7134_MAIN_CTRL_ESFE               (1 << 10)
+#define   SAA7134_MAIN_CTRL_EBADC              (1 << 9)
+#define   SAA7134_MAIN_CTRL_EBDAC              (1 << 8)
 #define   SAA7134_MAIN_CTRL_TE6                        (1 << 6)
 #define   SAA7134_MAIN_CTRL_TE5                        (1 << 5)
 #define   SAA7134_MAIN_CTRL_TE4                        (1 << 4)
 
 /* test modes */
 #define SAA7134_SPECIAL_MODE                    0x1d0
+#define SAA7134_PRODUCTION_TEST_MODE            0x1d1
 
 /* audio -- saa7133 + saa7135 only */
 #define SAA7135_DSP_RWSTATE                     0x580
index 463885601ab43041cab0c83a14a98da20f280908..470903e2f5e54ae51587a29f19e1557c3ee58226 100644 (file)
@@ -46,17 +46,11 @@ static int buffer_activate(struct saa7134_dev *dev,
                           struct saa7134_buf *buf,
                           struct saa7134_buf *next)
 {
-       u32 control;
 
        dprintk("buffer_activate [%p]",buf);
        buf->vb.state = STATE_ACTIVE;
        buf->top_seen = 0;
 
-        /* dma: setup channel 5 (= TS) */
-        control = SAA7134_RS_CONTROL_BURST_16 |
-                SAA7134_RS_CONTROL_ME |
-                (buf->pt->dma >> 12);
-
        if (NULL == next)
                next = buf;
        if (V4L2_FIELD_TOP == buf->vb.field) {
@@ -68,8 +62,6 @@ static int buffer_activate(struct saa7134_dev *dev,
                saa_writel(SAA7134_RS_BA1(5),saa7134_buffer_base(next));
                saa_writel(SAA7134_RS_BA2(5),saa7134_buffer_base(buf));
        }
-       saa_writel(SAA7134_RS_PITCH(5),TS_PACKET_SIZE);
-       saa_writel(SAA7134_RS_CONTROL(5),control);
 
        /* start DMA */
        saa7134_set_dmabits(dev);
@@ -84,6 +76,7 @@ static int buffer_prepare(struct videobuf_queue *q, struct videobuf_buffer *vb,
        struct saa7134_dev *dev = q->priv_data;
        struct saa7134_buf *buf = container_of(vb,struct saa7134_buf,vb);
        unsigned int lines, llength, size;
+       u32 control;
        int err;
 
        dprintk("buffer_prepare [%p,%s]\n",buf,v4l2_field_names[field]);
@@ -115,6 +108,18 @@ static int buffer_prepare(struct videobuf_queue *q, struct videobuf_buffer *vb,
                if (err)
                        goto oops;
        }
+
+       /* dma: setup channel 5 (= TS) */
+       control = SAA7134_RS_CONTROL_BURST_16 |
+                 SAA7134_RS_CONTROL_ME |
+                 (buf->pt->dma >> 12);
+
+       saa_writeb(SAA7134_TS_DMA0, ((lines-1)&0xff));
+       saa_writeb(SAA7134_TS_DMA1, (((lines-1)>>8)&0xff));
+       saa_writeb(SAA7134_TS_DMA2, ((((lines-1)>>16)&0x3f) | 0x00)); /* TSNOPIT=0, TSCOLAP=0 */
+       saa_writel(SAA7134_RS_PITCH(5),TS_PACKET_SIZE);
+       saa_writel(SAA7134_RS_CONTROL(5),control);
+
        buf->vb.state = STATE_PREPARED;
        buf->activate = buffer_activate;
        buf->vb.field = field;
@@ -164,11 +169,11 @@ EXPORT_SYMBOL_GPL(saa7134_ts_qops);
 /* ----------------------------------------------------------- */
 /* exported stuff                                              */
 
-static unsigned int tsbufs = 4;
+static unsigned int tsbufs = 8;
 module_param(tsbufs, int, 0444);
 MODULE_PARM_DESC(tsbufs,"number of ts buffers, range 2-32");
 
-static unsigned int ts_nr_packets = 30;
+static unsigned int ts_nr_packets = 64;
 module_param(ts_nr_packets, int, 0444);
 MODULE_PARM_DESC(ts_nr_packets,"size of a ts buffers (in ts packets)");
 
@@ -220,10 +225,10 @@ void saa7134_irq_ts_done(struct saa7134_dev *dev, unsigned long status)
        if (dev->ts_q.curr) {
                field = dev->ts_q.curr->vb.field;
                if (field == V4L2_FIELD_TOP) {
-                       if ((status & 0x100000) != 0x100000)
+                       if ((status & 0x100000) != 0x000000)
                                goto done;
                } else {
-                       if ((status & 0x100000) != 0x000000)
+                       if ((status & 0x100000) != 0x100000)
                                goto done;
                }
                saa7134_buffer_finish(dev,&dev->ts_q,STATE_DONE);
index 61a2d6b50eef29ad67948a5a04a324fcde367554..93268427750dea44b3e8839a9f8c4161935b3485 100644 (file)
@@ -207,6 +207,10 @@ static void tvaudio_setcarrier(struct saa7134_dev *dev,
        saa_writel(SAA7134_CARRIER2_FREQ0 >> 2, tvaudio_carr2reg(secondary));
 }
 
+#define SAA7134_MUTE_MASK 0xbb
+#define SAA7134_MUTE_ANALOG 0x04
+#define SAA7134_MUTE_I2S 0x40
+
 static void mute_input_7134(struct saa7134_dev *dev)
 {
        unsigned int mute;
@@ -241,7 +245,11 @@ static void mute_input_7134(struct saa7134_dev *dev)
 
        if (PCI_DEVICE_ID_PHILIPS_SAA7134 == dev->pci->device)
                /* 7134 mute */
-               saa_writeb(SAA7134_AUDIO_MUTE_CTRL, mute ? 0xbf : 0xbb);
+               saa_writeb(SAA7134_AUDIO_MUTE_CTRL, mute ?
+                                                   SAA7134_MUTE_MASK |
+                                                   SAA7134_MUTE_ANALOG |
+                                                   SAA7134_MUTE_I2S :
+                                                   SAA7134_MUTE_MASK);
 
        /* switch internal audio mux */
        switch (in->amux) {
@@ -753,17 +761,17 @@ static int mute_input_7133(struct saa7134_dev *dev)
 
 
        /* switch gpio-connected external audio mux */
-        if (0 != card(dev).gpiomask) {
-               mask = card(dev).gpiomask;
+       if (0 != card(dev).gpiomask) {
+               mask = card(dev).gpiomask;
 
                if (card(dev).mute.name && dev->ctl_mute)
                        in = &card(dev).mute;
                else
                        in = dev->input;
 
-               saa_andorl(SAA7134_GPIO_GPMODE0 >> 2,   mask, mask);
-               saa_andorl(SAA7134_GPIO_GPSTATUS0 >> 2, mask, in->gpio);
-               saa7134_track_gpio(dev,in->name);
+               saa_andorl(SAA7134_GPIO_GPMODE0 >> 2,   mask, mask);
+               saa_andorl(SAA7134_GPIO_GPSTATUS0 >> 2, mask, in->gpio);
+               saa7134_track_gpio(dev,in->name);
        }
 
        return 0;
@@ -1016,9 +1024,12 @@ int saa7134_tvaudio_do_scan(struct saa7134_dev *dev)
        return 0;
 }
 
+EXPORT_SYMBOL(saa_dsp_writel);
+
 /* ----------------------------------------------------------- */
 /*
  * Local variables:
  * c-basic-offset: 8
  * End:
  */
+
index 35e5e85f669a4056534ddab47d70438045572557..45c852df13ed56c24c2f0332314144a1ef05d3ff 100644 (file)
@@ -30,6 +30,9 @@
 #include "saa7134-reg.h"
 #include "saa7134.h"
 
+/* Include V4L1 specific functions. Should be removed soon */
+#include <linux/videodev.h>
+
 /* ------------------------------------------------------------------ */
 
 static unsigned int video_debug   = 0;
@@ -47,6 +50,43 @@ MODULE_PARM_DESC(noninterlaced,"video input is noninterlaced");
 #define dprintk(fmt, arg...)   if (video_debug) \
        printk(KERN_DEBUG "%s/video: " fmt, dev->name , ## arg)
 
+/* ------------------------------------------------------------------ */
+/* Defines for Video Output Port Register at address 0x191            */
+
+/* Bit 0: VIP code T bit polarity */
+
+#define VP_T_CODE_P_NON_INVERTED       0x00
+#define VP_T_CODE_P_INVERTED           0x01
+
+/* ------------------------------------------------------------------ */
+/* Defines for Video Output Port Register at address 0x195            */
+
+/* Bit 2: Video output clock delay control */
+
+#define VP_CLK_CTRL2_NOT_DELAYED       0x00
+#define VP_CLK_CTRL2_DELAYED           0x04
+
+/* Bit 1: Video output clock invert control */
+
+#define VP_CLK_CTRL1_NON_INVERTED      0x00
+#define VP_CLK_CTRL1_INVERTED          0x02
+
+/* ------------------------------------------------------------------ */
+/* Defines for Video Output Port Register at address 0x196            */
+
+/* Bits 2 to 0: VSYNC pin video vertical sync type */
+
+#define VP_VS_TYPE_MASK                        0x07
+
+#define VP_VS_TYPE_OFF                 0x00
+#define VP_VS_TYPE_V123                        0x01
+#define VP_VS_TYPE_V_ITU               0x02
+#define VP_VS_TYPE_VGATE_L             0x03
+#define VP_VS_TYPE_RESERVED1           0x04
+#define VP_VS_TYPE_RESERVED2           0x05
+#define VP_VS_TYPE_F_ITU               0x06
+#define VP_VS_TYPE_SC_FID              0x07
+
 /* ------------------------------------------------------------------ */
 /* data structs for video                                             */
 
@@ -273,12 +313,12 @@ static struct saa7134_tvnorm tvnorms[] = {
 
                .h_start       = 0,
                .h_stop        = 719,
-               .video_v_start = 23,
-               .video_v_stop  = 262,
-               .vbi_v_start_0 = 10,
-               .vbi_v_stop_0  = 21,
-               .vbi_v_start_1 = 273,
-               .src_timing    = 7,
+               .video_v_start = 23,
+               .video_v_stop  = 262,
+               .vbi_v_start_0 = 10,
+               .vbi_v_stop_0  = 21,
+               .vbi_v_start_1 = 273,
+               .src_timing    = 7,
 
                .sync_control  = 0x18,
                .luma_control  = 0x40,
@@ -622,7 +662,7 @@ static void set_size(struct saa7134_dev *dev, int task,
                prescale = 1;
        xscale = 1024 * dev->crop_current.width / prescale / width;
        yscale = 512 * div * dev->crop_current.height / height;
-               dprintk("prescale=%d xscale=%d yscale=%d\n",prescale,xscale,yscale);
+       dprintk("prescale=%d xscale=%d yscale=%d\n",prescale,xscale,yscale);
        set_h_prescale(dev,task,prescale);
        saa_writeb(SAA7134_H_SCALE_INC1(task),      xscale &  0xff);
        saa_writeb(SAA7134_H_SCALE_INC2(task),      xscale >> 8);
@@ -752,20 +792,20 @@ static int verify_preview(struct saa7134_dev *dev, struct v4l2_window *win)
        maxh  = dev->crop_current.height;
 
        if (V4L2_FIELD_ANY == field) {
-                field = (win->w.height > maxh/2)
-                        ? V4L2_FIELD_INTERLACED
-                        : V4L2_FIELD_TOP;
-        }
-        switch (field) {
-        case V4L2_FIELD_TOP:
-        case V4L2_FIELD_BOTTOM:
-                maxh = maxh / 2;
-                break;
-        case V4L2_FIELD_INTERLACED:
-                break;
-        default:
-                return -EINVAL;
-        }
+               field = (win->w.height > maxh/2)
+                       ? V4L2_FIELD_INTERLACED
+                       : V4L2_FIELD_TOP;
+       }
+       switch (field) {
+       case V4L2_FIELD_TOP:
+       case V4L2_FIELD_BOTTOM:
+               maxh = maxh / 2;
+               break;
+       case V4L2_FIELD_INTERLACED:
+               break;
+       default:
+               return -EINVAL;
+       }
 
        win->field = field;
        if (win->w.width > maxw)
@@ -1306,13 +1346,13 @@ video_poll(struct file *file, struct poll_table_struct *wait)
                        if (res_locked(fh->dev,RESOURCE_VIDEO)) {
                                up(&fh->cap.lock);
                                return POLLERR;
-                        }
-                        if (0 != fh->cap.ops->buf_prepare(&fh->cap,fh->cap.read_buf,fh->cap.field)) {
-                                up(&fh->cap.lock);
-                                return POLLERR;
-                        }
-                        fh->cap.ops->buf_queue(&fh->cap,fh->cap.read_buf);
-                        fh->cap.read_off = 0;
+                       }
+                       if (0 != fh->cap.ops->buf_prepare(&fh->cap,fh->cap.read_buf,fh->cap.field)) {
+                               up(&fh->cap.lock);
+                               return POLLERR;
+                       }
+                       fh->cap.ops->buf_queue(&fh->cap,fh->cap.read_buf);
+                       fh->cap.read_off = 0;
                }
                up(&fh->cap.lock);
                buf = fh->cap.read_buf;
@@ -1666,9 +1706,10 @@ static int video_do_ioctl(struct inode *inode, struct file *file,
        case VIDIOC_QUERYCAP:
        {
                struct v4l2_capability *cap = arg;
+               unsigned int tuner_type = dev->tuner_type;
 
                memset(cap,0,sizeof(*cap));
-                strcpy(cap->driver, "saa7134");
+               strcpy(cap->driver, "saa7134");
                strlcpy(cap->card, saa7134_boards[dev->board].name,
                        sizeof(cap->card));
                sprintf(cap->bus_info,"PCI:%s",pci_name(dev->pci));
@@ -1677,9 +1718,13 @@ static int video_do_ioctl(struct inode *inode, struct file *file,
                        V4L2_CAP_VIDEO_CAPTURE |
                        V4L2_CAP_VIDEO_OVERLAY |
                        V4L2_CAP_VBI_CAPTURE |
-                       V4L2_CAP_TUNER |
                        V4L2_CAP_READWRITE |
-                       V4L2_CAP_STREAMING;
+                       V4L2_CAP_STREAMING |
+                       V4L2_CAP_TUNER;
+
+               if ((tuner_type == TUNER_ABSENT) || (tuner_type == UNSET))
+                       cap->capabilities &= ~V4L2_CAP_TUNER;
+
                return 0;
        }
 
@@ -1793,9 +1838,9 @@ static int video_do_ioctl(struct inode *inode, struct file *file,
                        crop->c.height = b->top - crop->c.top + b->height;
 
                if (crop->c.left < b->left)
-                       crop->c.top = b->left;
+                       crop->c.left = b->left;
                if (crop->c.left > b->left + b->width)
-                       crop->c.top = b->left + b->width;
+                       crop->c.left = b->left + b->width;
                if (crop->c.width > b->left - crop->c.left + b->width)
                        crop->c.width = b->left - crop->c.left + b->width;
 
@@ -1817,6 +1862,7 @@ static int video_do_ioctl(struct inode *inode, struct file *file,
                                break;
                if (NULL != card_in(dev,n).name) {
                        strcpy(t->name, "Television");
+                       t->type = V4L2_TUNER_ANALOG_TV;
                        t->capability = V4L2_TUNER_CAP_NORM |
                                V4L2_TUNER_CAP_STEREO |
                                V4L2_TUNER_CAP_LANG1 |
@@ -1892,26 +1938,26 @@ static int video_do_ioctl(struct inode *inode, struct file *file,
        }
        case VIDIOC_S_AUDIO:
                return 0;
-        case VIDIOC_G_PARM:
-        {
-                struct v4l2_captureparm *parm = arg;
-                memset(parm,0,sizeof(*parm));
-                return 0;
-        }
-
-        case VIDIOC_G_PRIORITY:
-        {
-                enum v4l2_priority *p = arg;
-
-                *p = v4l2_prio_max(&dev->prio);
-                return 0;
-        }
-        case VIDIOC_S_PRIORITY:
-        {
-                enum v4l2_priority *prio = arg;
-
-                return v4l2_prio_change(&dev->prio, &fh->prio, *prio);
-        }
+       case VIDIOC_G_PARM:
+       {
+               struct v4l2_captureparm *parm = arg;
+               memset(parm,0,sizeof(*parm));
+               return 0;
+       }
+
+       case VIDIOC_G_PRIORITY:
+       {
+               enum v4l2_priority *p = arg;
+
+               *p = v4l2_prio_max(&dev->prio);
+               return 0;
+       }
+       case VIDIOC_S_PRIORITY:
+       {
+               enum v4l2_priority *prio = arg;
+
+               return v4l2_prio_change(&dev->prio, &fh->prio, *prio);
+       }
 
        /* --- preview ioctls ---------------------------------------- */
        case VIDIOC_ENUM_FMT:
@@ -2018,7 +2064,7 @@ static int video_do_ioctl(struct inode *inode, struct file *file,
                struct v4l2_format *f = arg;
                return saa7134_try_fmt(dev,fh,f);
        }
-
+#ifdef HAVE_V4L1
        case VIDIOCGMBUF:
        {
                struct video_mbuf *mbuf = arg;
@@ -2043,6 +2089,7 @@ static int video_do_ioctl(struct inode *inode, struct file *file,
                }
                return 0;
        }
+#endif
        case VIDIOC_REQBUFS:
                return videobuf_reqbufs(saa7134_queue(fh),arg);
 
@@ -2060,7 +2107,7 @@ static int video_do_ioctl(struct inode *inode, struct file *file,
        {
                int res = saa7134_resource(fh);
 
-                if (!res_get(dev,fh,res))
+               if (!res_get(dev,fh,res))
                        return -EBUSY;
                return videobuf_streamon(saa7134_queue(fh));
        }
@@ -2102,7 +2149,7 @@ static int radio_do_ioctl(struct inode *inode, struct file *file,
                struct v4l2_capability *cap = arg;
 
                memset(cap,0,sizeof(*cap));
-                strcpy(cap->driver, "saa7134");
+               strcpy(cap->driver, "saa7134");
                strlcpy(cap->card, saa7134_boards[dev->board].name,
                        sizeof(cap->card));
                sprintf(cap->bus_info,"PCI:%s",pci_name(dev->pci));
@@ -2119,6 +2166,7 @@ static int radio_do_ioctl(struct inode *inode, struct file *file,
 
                memset(t,0,sizeof(*t));
                strcpy(t->name, "Radio");
+               t->type = V4L2_TUNER_RADIO;
 
                saa7134_i2c_call_clients(dev, VIDIOC_G_TUNER, t);
 
@@ -2233,7 +2281,7 @@ struct video_device saa7134_video_template =
 {
        .name          = "saa7134-video",
        .type          = VID_TYPE_CAPTURE|VID_TYPE_TUNER|VID_TYPE_OVERLAY|
-                        VID_TYPE_CLIPPING|VID_TYPE_SCALES,
+                        VID_TYPE_CLIPPING|VID_TYPE_SCALES,
        .hardware      = 0,
        .fops          = &video_fops,
        .minor         = -1,
@@ -2280,7 +2328,7 @@ int saa7134_video_init1(struct saa7134_dev *dev)
                dev->tda9887_conf |= TDA9887_AUTOMUTE;
        dev->automute       = 0;
 
-        INIT_LIST_HEAD(&dev->video_q.queue);
+       INIT_LIST_HEAD(&dev->video_q.queue);
        init_timer(&dev->video_q.timeout);
        dev->video_q.timeout.function = saa7134_buffer_timeout;
        dev->video_q.timeout.data     = (unsigned long)(&dev->video_q);
@@ -2289,13 +2337,28 @@ int saa7134_video_init1(struct saa7134_dev *dev)
        if (saa7134_boards[dev->board].video_out) {
                /* enable video output */
                int vo = saa7134_boards[dev->board].video_out;
+               int video_reg;
+               unsigned int vid_port_opts = saa7134_boards[dev->board].vid_port_opts;
                saa_writeb(SAA7134_VIDEO_PORT_CTRL0, video_out[vo][0]);
-               saa_writeb(SAA7134_VIDEO_PORT_CTRL1, video_out[vo][1]);
+               video_reg = video_out[vo][1];
+               if (vid_port_opts & SET_T_CODE_POLARITY_NON_INVERTED)
+                       video_reg &= ~VP_T_CODE_P_INVERTED;
+               saa_writeb(SAA7134_VIDEO_PORT_CTRL1, video_reg);
                saa_writeb(SAA7134_VIDEO_PORT_CTRL2, video_out[vo][2]);
                saa_writeb(SAA7134_VIDEO_PORT_CTRL3, video_out[vo][3]);
                saa_writeb(SAA7134_VIDEO_PORT_CTRL4, video_out[vo][4]);
-               saa_writeb(SAA7134_VIDEO_PORT_CTRL5, video_out[vo][5]);
-               saa_writeb(SAA7134_VIDEO_PORT_CTRL6, video_out[vo][6]);
+               video_reg = video_out[vo][5];
+               if (vid_port_opts & SET_CLOCK_NOT_DELAYED)
+                       video_reg &= ~VP_CLK_CTRL2_DELAYED;
+               if (vid_port_opts & SET_CLOCK_INVERTED)
+                       video_reg |= VP_CLK_CTRL1_INVERTED;
+               saa_writeb(SAA7134_VIDEO_PORT_CTRL5, video_reg);
+               video_reg = video_out[vo][6];
+               if (vid_port_opts & SET_VSYNC_OFF) {
+                       video_reg &= ~VP_VS_TYPE_MASK;
+                       video_reg |= VP_VS_TYPE_OFF;
+               }
+               saa_writeb(SAA7134_VIDEO_PORT_CTRL6, video_reg);
                saa_writeb(SAA7134_VIDEO_PORT_CTRL7, video_out[vo][7]);
                saa_writeb(SAA7134_VIDEO_PORT_CTRL8, video_out[vo][8]);
        }
index 860b89530e2a452c6ab78485dd865b8c47b58058..fb97274716615e18f52a21537c6d865d3e0ad752 100644 (file)
 
 #include <linux/pci.h>
 #include <linux/i2c.h>
-#include <linux/videodev.h>
+#include <linux/videodev2.h>
 #include <linux/kdev_t.h>
 #include <linux/input.h>
+#include <linux/notifier.h>
+#include <linux/delay.h>
 
 #include <asm/io.h>
 
 #include <media/tuner.h>
 #include <media/audiochip.h>
-#include <media/id.h>
 #include <media/ir-common.h>
+#include <media/ir-kbd-i2c.h>
 #include <media/video-buf.h>
 #include <media/video-buf-dvb.h>
 
 #endif
 #define UNSET (-1U)
 
+#include <sound/driver.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+
 /* ----------------------------------------------------------- */
 /* enums                                                       */
 
@@ -187,10 +193,39 @@ struct saa7134_format {
 #define SAA7134_BOARD_FLYTV_DIGIMATRIX 64
 #define SAA7134_BOARD_KWORLD_TERMINATOR 65
 #define SAA7134_BOARD_YUAN_TUN900 66
+#define SAA7134_BOARD_BEHOLD_409FM 67
+#define SAA7134_BOARD_GOTVIEW_7135 68
+#define SAA7134_BOARD_PHILIPS_EUROPA  69
+#define SAA7134_BOARD_VIDEOMATE_DVBT_300 70
+#define SAA7134_BOARD_VIDEOMATE_DVBT_200 71
+#define SAA7134_BOARD_RTD_VFG7350 72
+#define SAA7134_BOARD_RTD_VFG7330 73
+#define SAA7134_BOARD_FLYTVPLATINUM_MINI2 74
+#define SAA7134_BOARD_AVERMEDIA_AVERTVHD_A180 75
+#define SAA7134_BOARD_MONSTERTV_MOBILE 76
+#define SAA7134_BOARD_PINNACLE_PCTV_110i 77
+#define SAA7134_BOARD_ASUSTeK_P7131_DUAL 78
+#define SAA7134_BOARD_SEDNA_PC_TV_CARDBUS     79
+#define SAA7134_BOARD_ASUSTEK_DIGIMATRIX_TV 80
+#define SAA7134_BOARD_PHILIPS_TIGER  81
 
 #define SAA7134_MAXBOARDS 8
 #define SAA7134_INPUT_MAX 8
 
+/* ----------------------------------------------------------- */
+/* Since we support 2 remote types, lets tell them apart       */
+
+#define SAA7134_REMOTE_GPIO  1
+#define SAA7134_REMOTE_I2C   2
+
+/* ----------------------------------------------------------- */
+/* Video Output Port Register Initialization Options           */
+
+#define SET_T_CODE_POLARITY_NON_INVERTED       (1 << 0)
+#define SET_CLOCK_NOT_DELAYED                  (1 << 1)
+#define SET_CLOCK_INVERTED                     (1 << 2)
+#define SET_VSYNC_OFF                          (1 << 3)
+
 struct saa7134_input {
        char                    *name;
        unsigned int            vmux;
@@ -226,6 +261,7 @@ struct saa7134_board {
        /* peripheral I/O */
        enum saa7134_video_out  video_out;
        enum saa7134_mpeg_type  mpeg;
+       unsigned int            vid_port_opts;
 };
 
 #define card_has_radio(dev)   (NULL != saa7134_boards[dev->board].radio.name)
@@ -319,9 +355,9 @@ struct saa7134_fh {
        struct saa7134_pgtable     pt_vbi;
 };
 
-/* oss dsp status */
-struct saa7134_oss {
-        struct semaphore           lock;
+/* dmasound dsp status */
+struct saa7134_dmasound {
+       struct semaphore           lock;
        int                        minor_mixer;
        int                        minor_dsp;
        unsigned int               users_dsp;
@@ -347,6 +383,7 @@ struct saa7134_oss {
        unsigned int               dma_blk;
        unsigned int               read_offset;
        unsigned int               read_count;
+       snd_pcm_substream_t        *substream;
 };
 
 /* IR input */
@@ -358,9 +395,9 @@ struct saa7134_ir {
        u32                        mask_keycode;
        u32                        mask_keydown;
        u32                        mask_keyup;
-        int                        polling;
-        u32                        last_gpio;
-        struct timer_list          timer;
+       int                        polling;
+       u32                        last_gpio;
+       struct timer_list          timer;
 };
 
 /* ts/mpeg status */
@@ -383,8 +420,8 @@ struct saa7134_mpeg_ops {
 /* global device status */
 struct saa7134_dev {
        struct list_head           devlist;
-        struct semaphore           lock;
-               spinlock_t                 slock;
+       struct semaphore           lock;
+       spinlock_t                 slock;
 #ifdef VIDIOC_G_PRIORITY
        struct v4l2_prio_state     prio;
 #endif
@@ -394,7 +431,7 @@ struct saa7134_dev {
        struct video_device        *video_dev;
        struct video_device        *radio_dev;
        struct video_device        *vbi_dev;
-       struct saa7134_oss         oss;
+       struct saa7134_dmasound    dmasound;
 
        /* infrared remote */
        int                        has_remote;
@@ -421,7 +458,7 @@ struct saa7134_dev {
        /* i2c i/o */
        struct i2c_adapter         i2c_adap;
        struct i2c_client          i2c_client;
-       unsigned char              eedata[64];
+       unsigned char              eedata[128];
 
        /* video overlay */
        struct v4l2_framebuffer    ovbuf;
@@ -626,6 +663,7 @@ void saa7134_irq_oss_done(struct saa7134_dev *dev, unsigned long status);
 int  saa7134_input_init1(struct saa7134_dev *dev);
 void saa7134_input_fini(struct saa7134_dev *dev);
 void saa7134_input_irq(struct saa7134_dev *dev);
+void saa7134_set_i2c_ir(struct saa7134_dev *dev, struct IR_i2c *ir);
 
 /*
  * Local variables:
index 255b6088ebf9ba8a86f448a29b96e57f3cce33d8..d32737dd21427d8bfed38d1206fc11b5dd272622 100644 (file)
@@ -50,7 +50,6 @@
 
 #include "bttv.h"
 #include <media/audiochip.h>
-#include <media/id.h>
 
 #ifndef VIDEO_AUDIO_BALANCE
 # define VIDEO_AUDIO_BALANCE 32
@@ -310,9 +309,9 @@ static int tda7432_attach(struct i2c_adapter *adap, int addr, int kind)
        memset(t,0,sizeof *t);
 
        client = &t->c;
-        memcpy(client,&client_template,sizeof(struct i2c_client));
-        client->adapter = adap;
-        client->addr = addr;
+       memcpy(client,&client_template,sizeof(struct i2c_client));
+       client->adapter = adap;
+       client->addr = addr;
        i2c_set_clientdata(client, t);
 
        do_tda7432_init(client);
@@ -472,7 +471,7 @@ static int tda7432_command(struct i2c_client *client,
                }
                }
 
-               t->muted=(va->flags & VIDEO_AUDIO_MUTE);
+               t->muted=(va->flags & VIDEO_AUDIO_MUTE);
                if (t->muted)
                {
                        /* Mute & update balance*/
@@ -503,12 +502,12 @@ static int tda7432_command(struct i2c_client *client,
 
 static struct i2c_driver driver = {
        .owner           = THIS_MODULE,
-        .name            = "i2c tda7432 driver",
+       .name            = "i2c tda7432 driver",
        .id              = I2C_DRIVERID_TDA7432,
-        .flags           = I2C_DF_NOTIFY,
+       .flags           = I2C_DF_NOTIFY,
        .attach_adapter  = tda7432_probe,
-        .detach_client   = tda7432_detach,
-        .command         = tda7432_command,
+       .detach_client   = tda7432_detach,
+       .command         = tda7432_command,
 };
 
 static struct i2c_client client_template =
index c65f0c7680a2606578a4024a65a3ba784a539bb2..b2dfe07e9f9d7abd055df318b4b08e3567152000 100644 (file)
 /*
- *
- * i2c tv tuner chip device driver
- * controls the philips tda8290+75 tuner chip combo.
- */
+
+   i2c tv tuner chip device driver
+   controls the philips tda8290+75 tuner chip combo.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 2 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software
+   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
 #include <linux/i2c.h>
 #include <linux/videodev.h>
 #include <linux/delay.h>
 #include <media/tuner.h>
 
-#define I2C_ADDR_TDA8290        0x4b
-#define I2C_ADDR_TDA8275        0x61
-
 /* ---------------------------------------------------------------------- */
 
-struct freq_entry {
-       u16     freq;
-       u8      value;
+struct tda827x_data {
+       u32 lomax;
+       u8  spd;
+       u8  bs;
+       u8  bp;
+       u8  cp;
+       u8  gc3;
+       u8 div1p5;
 };
 
-static struct freq_entry band_table[] = {
-       { 0x2DF4, 0x1C },
-       { 0x2574, 0x14 },
-       { 0x22B4, 0x0C },
-       { 0x20D4, 0x0B },
-       { 0x1E74, 0x3B },
-       { 0x1C34, 0x33 },
-       { 0x16F4, 0x5B },
-       { 0x1454, 0x53 },
-       { 0x12D4, 0x52 },
-       { 0x1034, 0x4A },
-       { 0x0EE4, 0x7A },
-       { 0x0D34, 0x72 },
-       { 0x0B54, 0x9A },
-       { 0x0914, 0x91 },
-       { 0x07F4, 0x89 },
-       { 0x0774, 0xB9 },
-       { 0x067B, 0xB1 },
-       { 0x0634, 0xD9 },
-       { 0x05A4, 0xD8 },       // FM radio
-       { 0x0494, 0xD0 },
-       { 0x03BC, 0xC8 },
-       { 0x0394, 0xF8 },       // 57250000 Hz
-       { 0x0000, 0xF0 },       // 0
+     /* Note lomax entry is lo / 62500 */
+
+static struct tda827x_data tda827x_analog[] = {
+       { .lomax =   992, .spd = 3, .bs = 2, .bp = 0, .cp = 0, .gc3 = 3, .div1p5 = 1}, /*  62 MHz */
+       { .lomax =  1056, .spd = 3, .bs = 3, .bp = 0, .cp = 0, .gc3 = 3, .div1p5 = 1}, /*  66 MHz */
+       { .lomax =  1216, .spd = 3, .bs = 1, .bp = 0, .cp = 0, .gc3 = 3, .div1p5 = 0}, /*  76 MHz */
+       { .lomax =  1344, .spd = 3, .bs = 2, .bp = 0, .cp = 0, .gc3 = 3, .div1p5 = 0}, /*  84 MHz */
+       { .lomax =  1488, .spd = 3, .bs = 2, .bp = 0, .cp = 0, .gc3 = 1, .div1p5 = 0}, /*  93 MHz */
+       { .lomax =  1568, .spd = 3, .bs = 3, .bp = 0, .cp = 0, .gc3 = 1, .div1p5 = 0}, /*  98 MHz */
+       { .lomax =  1744, .spd = 3, .bs = 3, .bp = 1, .cp = 0, .gc3 = 1, .div1p5 = 0}, /* 109 MHz */
+       { .lomax =  1968, .spd = 2, .bs = 2, .bp = 1, .cp = 0, .gc3 = 1, .div1p5 = 1}, /* 123 MHz */
+       { .lomax =  2128, .spd = 2, .bs = 3, .bp = 1, .cp = 0, .gc3 = 1, .div1p5 = 1}, /* 133 MHz */
+       { .lomax =  2416, .spd = 2, .bs = 1, .bp = 1, .cp = 0, .gc3 = 1, .div1p5 = 0}, /* 151 MHz */
+       { .lomax =  2464, .spd = 2, .bs = 2, .bp = 1, .cp = 0, .gc3 = 1, .div1p5 = 0}, /* 154 MHz */
+       { .lomax =  2896, .spd = 2, .bs = 2, .bp = 1, .cp = 0, .gc3 = 0, .div1p5 = 0}, /* 181 MHz */
+       { .lomax =  2960, .spd = 2, .bs = 2, .bp = 2, .cp = 0, .gc3 = 1, .div1p5 = 0}, /* 185 MHz */
+       { .lomax =  3472, .spd = 2, .bs = 3, .bp = 2, .cp = 0, .gc3 = 1, .div1p5 = 0}, /* 217 MHz */
+       { .lomax =  3904, .spd = 1, .bs = 2, .bp = 2, .cp = 0, .gc3 = 1, .div1p5 = 1}, /* 244 MHz */
+       { .lomax =  4240, .spd = 1, .bs = 3, .bp = 2, .cp = 0, .gc3 = 1, .div1p5 = 1}, /* 265 MHz */
+       { .lomax =  4832, .spd = 1, .bs = 1, .bp = 2, .cp = 0, .gc3 = 1, .div1p5 = 0}, /* 302 MHz */
+       { .lomax =  5184, .spd = 1, .bs = 2, .bp = 2, .cp = 0, .gc3 = 1, .div1p5 = 0}, /* 324 MHz */
+       { .lomax =  5920, .spd = 1, .bs = 2, .bp = 3, .cp = 0, .gc3 = 1, .div1p5 = 0}, /* 370 MHz */
+       { .lomax =  7264, .spd = 1, .bs = 3, .bp = 3, .cp = 0, .gc3 = 1, .div1p5 = 0}, /* 454 MHz */
+       { .lomax =  7888, .spd = 0, .bs = 2, .bp = 3, .cp = 0, .gc3 = 1, .div1p5 = 1}, /* 493 MHz */
+       { .lomax =  8480, .spd = 0, .bs = 3, .bp = 3, .cp = 0, .gc3 = 1, .div1p5 = 1}, /* 530 MHz */
+       { .lomax =  8864, .spd = 0, .bs = 1, .bp = 3, .cp = 0, .gc3 = 1, .div1p5 = 0}, /* 554 MHz */
+       { .lomax =  9664, .spd = 0, .bs = 1, .bp = 4, .cp = 0, .gc3 = 0, .div1p5 = 0}, /* 604 MHz */
+       { .lomax = 11088, .spd = 0, .bs = 2, .bp = 4, .cp = 0, .gc3 = 0, .div1p5 = 0}, /* 696 MHz */
+       { .lomax = 11840, .spd = 0, .bs = 2, .bp = 4, .cp = 1, .gc3 = 0, .div1p5 = 0}, /* 740 MHz */
+       { .lomax = 13120, .spd = 0, .bs = 3, .bp = 4, .cp = 0, .gc3 = 0, .div1p5 = 0}, /* 820 MHz */
+       { .lomax = 13840, .spd = 0, .bs = 3, .bp = 4, .cp = 1, .gc3 = 0, .div1p5 = 0}, /* 865 MHz */
+       { .lomax =     0, .spd = 0, .bs = 0, .bp = 0, .cp = 0, .gc3 = 0, .div1p5 = 0}  /* End      */
 };
 
-static struct freq_entry div_table[] = {
-       { 0x1C34, 3 },
-       { 0x0D34, 2 },
-       { 0x067B, 1 },
-        { 0x0000, 0 },
-};
+static void tda827x_tune(struct i2c_client *c, u16 ifc, unsigned int freq)
+{
+       unsigned char tuner_reg[8];
+       unsigned char reg2[2];
+       u32 N;
+       int i;
+       struct tuner *t = i2c_get_clientdata(c);
+       struct i2c_msg msg = {.addr = t->tda827x_addr, .flags = 0};
 
-static struct freq_entry agc_table[] = {
-       { 0x22B4, 0x8F },
-       { 0x0B54, 0x9F },
-       { 0x09A4, 0x8F },
-       { 0x0554, 0x9F },
-       { 0x0000, 0xBF },
-};
+       if (t->mode == V4L2_TUNER_RADIO)
+               freq = freq / 1000;
 
-static __u8 get_freq_entry( struct freq_entry* table, __u16 freq)
-{
-       while(table->freq && table->freq > freq)
-               table++;
-       return table->value;
-}
+       N = freq + ifc;
+       i = 0;
+       while (tda827x_analog[i].lomax < N) {
+               if(tda827x_analog[i + 1].lomax == 0)
+                       break;
+               i++;
+       }
+
+       N = N << tda827x_analog[i].spd;
+
+       tuner_reg[0] = 0;
+       tuner_reg[1] = (unsigned char)(N>>8);
+       tuner_reg[2] = (unsigned char) N;
+       tuner_reg[3] = 0x40;
+       tuner_reg[4] = 0x52 + (t->tda827x_lpsel << 5);
+       tuner_reg[5] = (tda827x_analog[i].spd   << 6) + (tda827x_analog[i].div1p5 <<5) +
+                      (tda827x_analog[i].bs     <<3) +  tda827x_analog[i].bp;
+       tuner_reg[6] = 0x8f + (tda827x_analog[i].gc3 << 4);
+       tuner_reg[7] = 0x8f;
+
+       msg.buf = tuner_reg;
+       msg.len = 8;
+       i2c_transfer(c->adapter, &msg, 1);
+
+       msg.buf= reg2;
+       msg.len = 2;
+       reg2[0] = 0x80;
+       reg2[1] = 0;
+       i2c_transfer(c->adapter, &msg, 1);
+
+       reg2[0] = 0x60;
+       reg2[1] = 0xbf;
+       i2c_transfer(c->adapter, &msg, 1);
+
+       reg2[0] = 0x30;
+       reg2[1] = tuner_reg[4] + 0x80;
+       i2c_transfer(c->adapter, &msg, 1);
+
+       msleep(1);
+       reg2[0] = 0x30;
+       reg2[1] = tuner_reg[4] + 4;
+       i2c_transfer(c->adapter, &msg, 1);
+
+       msleep(1);
+       reg2[0] = 0x30;
+       reg2[1] = tuner_reg[4];
+       i2c_transfer(c->adapter, &msg, 1);
 
-/* ---------------------------------------------------------------------- */
+       msleep(550);
+       reg2[0] = 0x30;
+       reg2[1] = (tuner_reg[4] & 0xfc) + tda827x_analog[i].cp ;
+       i2c_transfer(c->adapter, &msg, 1);
 
-static unsigned char i2c_enable_bridge[2] =    { 0x21, 0xC0 };
-static unsigned char i2c_disable_bridge[2] =   { 0x21, 0x80 };
-static unsigned char i2c_init_tda8275[14] =    { 0x00, 0x00, 0x00, 0x00,
-                                                 0xfC, 0x04, 0xA3, 0x3F,
-                                                 0x2A, 0x04, 0xFF, 0x00,
-                                                 0x00, 0x40 };
-static unsigned char i2c_set_VS[2] =           { 0x30, 0x6F };
-static unsigned char i2c_set_GP01_CF[2] =      { 0x20, 0x0B };
-static unsigned char i2c_tda8290_reset[2] =    { 0x00, 0x00 };
-static unsigned char i2c_tda8290_standby[2] =  { 0x00, 0x02 };
-static unsigned char i2c_gainset_off[2] =      { 0x28, 0x14 };
-static unsigned char i2c_gainset_on[2] =       { 0x28, 0x54 };
-static unsigned char i2c_agc3_00[2] =          { 0x80, 0x00 };
-static unsigned char i2c_agc2_BF[2] =          { 0x60, 0xBF };
-static unsigned char i2c_cb1_D0[2] =           { 0x30, 0xD0 };
-static unsigned char i2c_cb1_D2[2] =           { 0x30, 0xD2 };
-static unsigned char i2c_cb1_56[2] =           { 0x30, 0x56 };
-static unsigned char i2c_cb1_52[2] =           { 0x30, 0x52 };
-static unsigned char i2c_cb1_50[2] =           { 0x30, 0x50 };
-static unsigned char i2c_agc2_7F[2] =          { 0x60, 0x7F };
-static unsigned char i2c_agc3_08[2] =          { 0x80, 0x08 };
-
-static struct i2c_msg i2c_msg_init[] = {
-       { I2C_ADDR_TDA8275, 0, ARRAY_SIZE(i2c_init_tda8275), i2c_init_tda8275 },
-       { I2C_ADDR_TDA8290, 0, ARRAY_SIZE(i2c_disable_bridge), i2c_disable_bridge },
-       { I2C_ADDR_TDA8290, 0, ARRAY_SIZE(i2c_set_VS), i2c_set_VS },
-       { I2C_ADDR_TDA8290, 0, ARRAY_SIZE(i2c_set_GP01_CF), i2c_set_GP01_CF },
-};
+       reg2[0] = 0x60;
+       reg2[1] = 0x3f;
+       i2c_transfer(c->adapter, &msg, 1);
 
-static struct i2c_msg i2c_msg_prolog[] = {
-//     { I2C_ADDR_TDA8290, 0, ARRAY_SIZE(i2c_easy_mode), i2c_easy_mode },
-       { I2C_ADDR_TDA8290, 0, ARRAY_SIZE(i2c_gainset_off), i2c_gainset_off },
-       { I2C_ADDR_TDA8290, 0, ARRAY_SIZE(i2c_tda8290_reset), i2c_tda8290_reset },
-       { I2C_ADDR_TDA8290, 0, ARRAY_SIZE(i2c_enable_bridge), i2c_enable_bridge },
-};
+       reg2[0] = 0x80;
+       reg2[1] = 0x08;   // Vsync en
+       i2c_transfer(c->adapter, &msg, 1);
+}
 
-static struct i2c_msg i2c_msg_config[] = {
-//     { I2C_ADDR_TDA8275, 0, ARRAY_SIZE(i2c_set_freq), i2c_set_freq },
-       { I2C_ADDR_TDA8275, 0, ARRAY_SIZE(i2c_agc3_00), i2c_agc3_00 },
-       { I2C_ADDR_TDA8275, 0, ARRAY_SIZE(i2c_agc2_BF), i2c_agc2_BF },
-       { I2C_ADDR_TDA8275, 0, ARRAY_SIZE(i2c_cb1_D2), i2c_cb1_D2 },
-       { I2C_ADDR_TDA8275, 0, ARRAY_SIZE(i2c_cb1_56), i2c_cb1_56 },
-       { I2C_ADDR_TDA8275, 0, ARRAY_SIZE(i2c_cb1_52), i2c_cb1_52 },
-};
+static void tda827x_agcf(struct i2c_client *c)
+{
+       struct tuner *t = i2c_get_clientdata(c);
+       unsigned char data[] = {0x80, 0x0c};
+       struct i2c_msg msg = {.addr = t->tda827x_addr, .buf = data,
+                             .flags = 0, .len = 2};
+       i2c_transfer(c->adapter, &msg, 1);
+}
 
-static struct i2c_msg i2c_msg_epilog[] = {
-       { I2C_ADDR_TDA8275, 0, ARRAY_SIZE(i2c_cb1_50), i2c_cb1_50 },
-       { I2C_ADDR_TDA8275, 0, ARRAY_SIZE(i2c_agc2_7F), i2c_agc2_7F },
-       { I2C_ADDR_TDA8275, 0, ARRAY_SIZE(i2c_agc3_08), i2c_agc3_08 },
-       { I2C_ADDR_TDA8290, 0, ARRAY_SIZE(i2c_disable_bridge), i2c_disable_bridge },
-       { I2C_ADDR_TDA8290, 0, ARRAY_SIZE(i2c_gainset_on), i2c_gainset_on },
+/* ---------------------------------------------------------------------- */
+
+struct tda827xa_data {
+       u32 lomax;
+       u8  svco;
+       u8  spd;
+       u8  scr;
+       u8  sbs;
+       u8  gc3;
 };
 
-static struct i2c_msg i2c_msg_standby[] = {
-       { I2C_ADDR_TDA8290, 0, ARRAY_SIZE(i2c_enable_bridge), i2c_enable_bridge },
-       { I2C_ADDR_TDA8275, 0, ARRAY_SIZE(i2c_cb1_D0), i2c_cb1_D0 },
-       { I2C_ADDR_TDA8290, 0, ARRAY_SIZE(i2c_disable_bridge), i2c_disable_bridge },
-       { I2C_ADDR_TDA8290, 0, ARRAY_SIZE(i2c_tda8290_standby), i2c_tda8290_standby },
+static struct tda827xa_data tda827xa_analog[] = {
+       { .lomax =   910, .svco = 3, .spd = 4, .scr = 0, .sbs = 0, .gc3 = 3},  /*  56.875 MHz */
+       { .lomax =  1076, .svco = 0, .spd = 3, .scr = 0, .sbs = 0, .gc3 = 3},  /*  67.25 MHz */
+       { .lomax =  1300, .svco = 1, .spd = 3, .scr = 0, .sbs = 0, .gc3 = 3},  /*  81.25 MHz */
+       { .lomax =  1560, .svco = 2, .spd = 3, .scr = 0, .sbs = 0, .gc3 = 3},  /*  97.5  MHz */
+       { .lomax =  1820, .svco = 3, .spd = 3, .scr = 0, .sbs = 1, .gc3 = 1},  /* 113.75 MHz */
+       { .lomax =  2152, .svco = 0, .spd = 2, .scr = 0, .sbs = 1, .gc3 = 1},  /* 134.5 MHz */
+       { .lomax =  2464, .svco = 1, .spd = 2, .scr = 0, .sbs = 1, .gc3 = 1},  /* 154   MHz */
+       { .lomax =  2600, .svco = 1, .spd = 2, .scr = 0, .sbs = 1, .gc3 = 1},  /* 162.5 MHz */
+       { .lomax =  2928, .svco = 2, .spd = 2, .scr = 0, .sbs = 1, .gc3 = 1},  /* 183   MHz */
+       { .lomax =  3120, .svco = 2, .spd = 2, .scr = 0, .sbs = 2, .gc3 = 1},  /* 195   MHz */
+       { .lomax =  3640, .svco = 3, .spd = 2, .scr = 0, .sbs = 2, .gc3 = 3},  /* 227.5 MHz */
+       { .lomax =  4304, .svco = 0, .spd = 1, .scr = 0, .sbs = 2, .gc3 = 3},  /* 269   MHz */
+       { .lomax =  5200, .svco = 1, .spd = 1, .scr = 0, .sbs = 2, .gc3 = 1},  /* 325   MHz */
+       { .lomax =  6240, .svco = 2, .spd = 1, .scr = 0, .sbs = 3, .gc3 = 3},  /* 390   MHz */
+       { .lomax =  7280, .svco = 3, .spd = 1, .scr = 0, .sbs = 3, .gc3 = 3},  /* 455   MHz */
+       { .lomax =  8320, .svco = 0, .spd = 0, .scr = 0, .sbs = 3, .gc3 = 1},  /* 520   MHz */
+       { .lomax =  8608, .svco = 0, .spd = 0, .scr = 1, .sbs = 3, .gc3 = 1},  /* 538   MHz */
+       { .lomax =  8864, .svco = 1, .spd = 0, .scr = 0, .sbs = 3, .gc3 = 1},  /* 554   MHz */
+       { .lomax =  9920, .svco = 1, .spd = 0, .scr = 0, .sbs = 4, .gc3 = 0},  /* 620   MHz */
+       { .lomax = 10400, .svco = 1, .spd = 0, .scr = 1, .sbs = 4, .gc3 = 0},  /* 650   MHz */
+       { .lomax = 11200, .svco = 2, .spd = 0, .scr = 0, .sbs = 4, .gc3 = 0},  /* 700   MHz */
+       { .lomax = 12480, .svco = 2, .spd = 0, .scr = 1, .sbs = 4, .gc3 = 0},  /* 780   MHz */
+       { .lomax = 13120, .svco = 3, .spd = 0, .scr = 0, .sbs = 4, .gc3 = 0},  /* 820   MHz */
+       { .lomax = 13920, .svco = 3, .spd = 0, .scr = 1, .sbs = 4, .gc3 = 0},  /* 870   MHz */
+       { .lomax = 14576, .svco = 3, .spd = 0, .scr = 2, .sbs = 4, .gc3 = 0},  /* 911   MHz */
+       { .lomax =     0, .svco = 0, .spd = 0, .scr = 0, .sbs = 0, .gc3 = 0}   /* End */
 };
 
-static int tda8290_tune(struct i2c_client *c)
+static void tda827xa_tune(struct i2c_client *c, u16 ifc, unsigned int freq)
 {
+       unsigned char tuner_reg[14];
+       unsigned char reg2[2];
+       u32 N;
+       int i;
        struct tuner *t = i2c_get_clientdata(c);
-       struct i2c_msg easy_mode =
-               { I2C_ADDR_TDA8290, 0, 2, t->i2c_easy_mode };
-       struct i2c_msg set_freq =
-               { I2C_ADDR_TDA8275, 0, 8, t->i2c_set_freq  };
+       struct i2c_msg msg = {.addr = t->tda827x_addr, .flags = 0};
 
-       i2c_transfer(c->adapter, &easy_mode,      1);
-       i2c_transfer(c->adapter, i2c_msg_prolog, ARRAY_SIZE(i2c_msg_prolog));
+       if (t->mode == V4L2_TUNER_RADIO)
+               freq = freq / 1000;
 
-       i2c_transfer(c->adapter, &set_freq,       1);
-       i2c_transfer(c->adapter, i2c_msg_config, ARRAY_SIZE(i2c_msg_config));
+       N = freq + ifc;
+       i = 0;
+       while (tda827xa_analog[i].lomax < N) {
+               if(tda827xa_analog[i + 1].lomax == 0)
+                       break;
+               i++;
+       }
+
+       N = N << tda827xa_analog[i].spd;
+
+       tuner_reg[0] = 0;
+       tuner_reg[1] = (unsigned char)(N>>8);
+       tuner_reg[2] = (unsigned char) N;
+       tuner_reg[3] = 0;
+       tuner_reg[4] = 0x16;
+       tuner_reg[5] = (tda827xa_analog[i].spd << 5) + (tda827xa_analog[i].svco << 3) +
+                       tda827xa_analog[i].sbs;
+       tuner_reg[6] = 0x8b + (tda827xa_analog[i].gc3 << 4);
+       tuner_reg[7] = 0x0c;
+       tuner_reg[8] = 4;
+       tuner_reg[9] = 0x20;
+       tuner_reg[10] = 0xff;
+       tuner_reg[11] = 0xe0;
+       tuner_reg[12] = 0;
+       tuner_reg[13] = 0x39 + (t->tda827x_lpsel << 1);
+
+       msg.buf = tuner_reg;
+       msg.len = 14;
+       i2c_transfer(c->adapter, &msg, 1);
+
+       msg.buf= reg2;
+       msg.len = 2;
+       reg2[0] = 0x60;
+       reg2[1] = 0x3c;
+       i2c_transfer(c->adapter, &msg, 1);
+
+       reg2[0] = 0xa0;
+       reg2[1] = 0xc0;
+       i2c_transfer(c->adapter, &msg, 1);
+
+       msleep(2);
+       reg2[0] = 0x30;
+       reg2[1] = 0x10 + tda827xa_analog[i].scr;
+       i2c_transfer(c->adapter, &msg, 1);
 
        msleep(550);
-       i2c_transfer(c->adapter, i2c_msg_epilog, ARRAY_SIZE(i2c_msg_epilog));
-       return 0;
+       reg2[0] = 0x50;
+       reg2[1] = 0x8f + (tda827xa_analog[i].gc3 << 4);
+       i2c_transfer(c->adapter, &msg, 1);
+
+       reg2[0] = 0x80;
+       reg2[1] = 0x28;
+       i2c_transfer(c->adapter, &msg, 1);
+
+       reg2[0] = 0xb0;
+       reg2[1] = 0x01;
+       i2c_transfer(c->adapter, &msg, 1);
+
+       reg2[0] = 0xc0;
+       reg2[1] = 0x19 + (t->tda827x_lpsel << 1);
+       i2c_transfer(c->adapter, &msg, 1);
 }
 
-static void set_frequency(struct tuner *t, u16 ifc, unsigned int freq)
+static void tda827xa_agcf(struct i2c_client *c)
 {
-       u32 N;
+       struct tuner *t = i2c_get_clientdata(c);
+       unsigned char data[] = {0x80, 0x2c};
+       struct i2c_msg msg = {.addr = t->tda827x_addr, .buf = data,
+                             .flags = 0, .len = 2};
+       i2c_transfer(c->adapter, &msg, 1);
+}
 
-       if (t->mode == V4L2_TUNER_RADIO)
-               freq = freq / 1000;
+/*---------------------------------------------------------------------*/
 
-       N = (((freq<<3)+ifc)&0x3fffc);
-
-       N = N >> get_freq_entry(div_table, freq);
-       t->i2c_set_freq[0] = 0;
-       t->i2c_set_freq[1] = (unsigned char)(N>>8);
-       t->i2c_set_freq[2] = (unsigned char) N;
-       t->i2c_set_freq[3] = 0x40;
-       t->i2c_set_freq[4] = 0x52;
-       t->i2c_set_freq[5] = get_freq_entry(band_table, freq);
-       t->i2c_set_freq[6] = get_freq_entry(agc_table,  freq);
-       t->i2c_set_freq[7] = 0x8f;
+static void tda8290_i2c_bridge(struct i2c_client *c, int close)
+{
+       unsigned char  enable[2] = { 0x21, 0xC0 };
+       unsigned char disable[2] = { 0x21, 0x80 };
+       unsigned char *msg;
+       if(close) {
+               msg = enable;
+               i2c_master_send(c, msg, 2);
+               /* let the bridge stabilize */
+               msleep(20);
+       } else {
+               msg = disable;
+               i2c_master_send(c, msg, 2);
+       }
 }
 
+/*---------------------------------------------------------------------*/
+
+static int tda8290_tune(struct i2c_client *c, u16 ifc, unsigned int freq)
+{
+       struct tuner *t = i2c_get_clientdata(c);
+       unsigned char soft_reset[]  = { 0x00, 0x00 };
+       unsigned char easy_mode[]   = { 0x01, t->tda8290_easy_mode };
+       unsigned char expert_mode[] = { 0x01, 0x80 };
+       unsigned char gainset_off[] = { 0x28, 0x14 };
+       unsigned char if_agc_spd[]  = { 0x0f, 0x88 };
+       unsigned char adc_head_6[]  = { 0x05, 0x04 };
+       unsigned char adc_head_9[]  = { 0x05, 0x02 };
+       unsigned char adc_head_12[] = { 0x05, 0x01 };
+       unsigned char pll_bw_nom[]  = { 0x0d, 0x47 };
+       unsigned char pll_bw_low[]  = { 0x0d, 0x27 };
+       unsigned char gainset_2[]   = { 0x28, 0x64 };
+       unsigned char agc_rst_on[]  = { 0x0e, 0x0b };
+       unsigned char agc_rst_off[] = { 0x0e, 0x09 };
+       unsigned char if_agc_set[]  = { 0x0f, 0x81 };
+       unsigned char addr_adc_sat  = 0x1a;
+       unsigned char addr_agc_stat = 0x1d;
+       unsigned char addr_pll_stat = 0x1b;
+       unsigned char adc_sat, agc_stat,
+                     pll_stat;
+
+       i2c_master_send(c, easy_mode, 2);
+       i2c_master_send(c, soft_reset, 2);
+       msleep(1);
+
+       expert_mode[1] = t->tda8290_easy_mode + 0x80;
+       i2c_master_send(c, expert_mode, 2);
+       i2c_master_send(c, gainset_off, 2);
+       i2c_master_send(c, if_agc_spd, 2);
+       if (t->tda8290_easy_mode & 0x60)
+               i2c_master_send(c, adc_head_9, 2);
+       else
+               i2c_master_send(c, adc_head_6, 2);
+       i2c_master_send(c, pll_bw_nom, 2);
+
+       tda8290_i2c_bridge(c, 1);
+       if (t->tda827x_ver != 0)
+               tda827xa_tune(c, ifc, freq);
+       else
+               tda827x_tune(c, ifc, freq);
+       /* adjust headroom resp. gain */
+       i2c_master_send(c, &addr_adc_sat, 1);
+       i2c_master_recv(c, &adc_sat, 1);
+       i2c_master_send(c, &addr_agc_stat, 1);
+       i2c_master_recv(c, &agc_stat, 1);
+       i2c_master_send(c, &addr_pll_stat, 1);
+       i2c_master_recv(c, &pll_stat, 1);
+       if (pll_stat & 0x80)
+               tuner_dbg("tda8290 is locked, AGC: %d\n", agc_stat);
+       else
+               tuner_dbg("tda8290 not locked, no signal?\n");
+       if ((agc_stat > 115) || (!(pll_stat & 0x80) && (adc_sat < 20))) {
+               tuner_dbg("adjust gain, step 1. Agc: %d, ADC stat: %d, lock: %d\n",
+                          agc_stat, adc_sat, pll_stat & 0x80);
+               i2c_master_send(c, gainset_2, 2);
+               msleep(100);
+               i2c_master_send(c, &addr_agc_stat, 1);
+               i2c_master_recv(c, &agc_stat, 1);
+               i2c_master_send(c, &addr_pll_stat, 1);
+               i2c_master_recv(c, &pll_stat, 1);
+               if ((agc_stat > 115) || !(pll_stat & 0x80)) {
+                       tuner_dbg("adjust gain, step 2. Agc: %d, lock: %d\n",
+                                  agc_stat, pll_stat & 0x80);
+                       if (t->tda827x_ver != 0)
+                               tda827xa_agcf(c);
+                       else
+                               tda827x_agcf(c);
+                       msleep(100);
+                       i2c_master_send(c, &addr_agc_stat, 1);
+                       i2c_master_recv(c, &agc_stat, 1);
+                       i2c_master_send(c, &addr_pll_stat, 1);
+                       i2c_master_recv(c, &pll_stat, 1);
+                       if((agc_stat > 115) || !(pll_stat & 0x80)) {
+                               tuner_dbg("adjust gain, step 3. Agc: %d\n", agc_stat);
+                               i2c_master_send(c, adc_head_12, 2);
+                               i2c_master_send(c, pll_bw_low, 2);
+                               msleep(100);
+                       }
+               }
+       }
+
+       /* l/ l' deadlock? */
+       if(t->tda8290_easy_mode & 0x60) {
+               i2c_master_send(c, &addr_adc_sat, 1);
+               i2c_master_recv(c, &adc_sat, 1);
+               i2c_master_send(c, &addr_pll_stat, 1);
+               i2c_master_recv(c, &pll_stat, 1);
+               if ((adc_sat > 20) || !(pll_stat & 0x80)) {
+                       tuner_dbg("trying to resolve SECAM L deadlock\n");
+                       i2c_master_send(c, agc_rst_on, 2);
+                       msleep(40);
+                       i2c_master_send(c, agc_rst_off, 2);
+               }
+       }
+
+       tda8290_i2c_bridge(c, 0);
+       i2c_master_send(c, if_agc_set, 2);
+       return 0;
+}
+
+
+/*---------------------------------------------------------------------*/
+
 #define V4L2_STD_MN    (V4L2_STD_PAL_M|V4L2_STD_PAL_N|V4L2_STD_PAL_Nc|V4L2_STD_NTSC)
 #define V4L2_STD_B     (V4L2_STD_PAL_B|V4L2_STD_PAL_B1|V4L2_STD_SECAM_B)
 #define V4L2_STD_GH    (V4L2_STD_PAL_G|V4L2_STD_PAL_H|V4L2_STD_SECAM_G|V4L2_STD_SECAM_H)
@@ -174,20 +408,37 @@ static void set_frequency(struct tuner *t, u16 ifc, unsigned int freq)
 
 static void set_audio(struct tuner *t)
 {
-       t->i2c_easy_mode[0] = 0x01;
-
-       if (t->std & V4L2_STD_MN)
-               t->i2c_easy_mode[1] = 0x01;
-       else if (t->std & V4L2_STD_B)
-               t->i2c_easy_mode[1] = 0x02;
-       else if (t->std & V4L2_STD_GH)
-               t->i2c_easy_mode[1] = 0x04;
-       else if (t->std & V4L2_STD_PAL_I)
-               t->i2c_easy_mode[1] = 0x08;
-       else if (t->std & V4L2_STD_DK)
-               t->i2c_easy_mode[1] = 0x10;
-       else if (t->std & V4L2_STD_SECAM_L)
-               t->i2c_easy_mode[1] = 0x20;
+       char* mode;
+
+       t->tda827x_lpsel = 0;
+       mode = "xx";
+       if (t->std & V4L2_STD_MN) {
+               t->sgIF = 92;
+               t->tda8290_easy_mode = 0x01;
+               t->tda827x_lpsel = 1;
+               mode = "MN";
+       } else if (t->std & V4L2_STD_B) {
+               t->sgIF = 108;
+               t->tda8290_easy_mode = 0x02;
+               mode = "B";
+       } else if (t->std & V4L2_STD_GH) {
+               t->sgIF = 124;
+               t->tda8290_easy_mode = 0x04;
+               mode = "GH";
+       } else if (t->std & V4L2_STD_PAL_I) {
+               t->sgIF = 124;
+               t->tda8290_easy_mode = 0x08;
+               mode = "I";
+       } else if (t->std & V4L2_STD_DK) {
+               t->sgIF = 124;
+               t->tda8290_easy_mode = 0x10;
+               mode = "DK";
+       } else if (t->std & V4L2_STD_SECAM_L) {
+               t->sgIF = 124;
+               t->tda8290_easy_mode = 0x20;
+               mode = "L";
+       }
+    tuner_dbg("setting tda8290 to system %s\n", mode);
 }
 
 static void set_tv_freq(struct i2c_client *c, unsigned int freq)
@@ -195,15 +446,13 @@ static void set_tv_freq(struct i2c_client *c, unsigned int freq)
        struct tuner *t = i2c_get_clientdata(c);
 
        set_audio(t);
-       set_frequency(t, 864, freq);
-       tda8290_tune(c);
+       tda8290_tune(c, t->sgIF, freq);
 }
 
 static void set_radio_freq(struct i2c_client *c, unsigned int freq)
 {
-       struct tuner *t = i2c_get_clientdata(c);
-       set_frequency(t, 704, freq);
-       tda8290_tune(c);
+       /* if frequency is 5.5 MHz */
+       tda8290_tune(c, 88, freq);
 }
 
 static int has_signal(struct i2c_client *c)
@@ -216,27 +465,145 @@ static int has_signal(struct i2c_client *c)
        return (afc & 0x80)? 65535:0;
 }
 
+/*---------------------------------------------------------------------*/
+
 static void standby(struct i2c_client *c)
 {
-       i2c_transfer(c->adapter, i2c_msg_standby, ARRAY_SIZE(i2c_msg_standby));
+       struct tuner *t = i2c_get_clientdata(c);
+       unsigned char cb1[] = { 0x30, 0xD0 };
+       unsigned char tda8290_standby[] = { 0x00, 0x02 };
+       struct i2c_msg msg = {.addr = t->tda827x_addr, .flags=0, .buf=cb1, .len = 2};
+
+       tda8290_i2c_bridge(c, 1);
+       if (t->tda827x_ver != 0)
+               cb1[1] = 0x90;
+       i2c_transfer(c->adapter, &msg, 1);
+       tda8290_i2c_bridge(c, 0);
+       i2c_master_send(c, tda8290_standby, 2);
 }
 
-int tda8290_init(struct i2c_client *c)
+
+static void tda8290_init_if(struct i2c_client *c)
+{
+       unsigned char set_VS[] = { 0x30, 0x6F };
+       unsigned char set_GP01_CF[] = { 0x20, 0x0B };
+
+       i2c_master_send(c, set_VS, 2);
+       i2c_master_send(c, set_GP01_CF, 2);
+}
+
+static void tda8290_init_tuner(struct i2c_client *c)
 {
        struct tuner *t = i2c_get_clientdata(c);
+       unsigned char tda8275_init[]  = { 0x00, 0x00, 0x00, 0x40, 0xdC, 0x04, 0xAf,
+                                         0x3F, 0x2A, 0x04, 0xFF, 0x00, 0x00, 0x40 };
+       unsigned char tda8275a_init[] = { 0x00, 0x00, 0x00, 0x00, 0xdC, 0x05, 0x8b,
+                                         0x0c, 0x04, 0x20, 0xFF, 0x00, 0x00, 0x4b };
+       struct i2c_msg msg = {.addr = t->tda827x_addr, .flags=0,
+                             .buf=tda8275_init, .len = 14};
+       if (t->tda827x_ver != 0)
+               msg.buf = tda8275a_init;
+
+       tda8290_i2c_bridge(c, 1);
+       i2c_transfer(c->adapter, &msg, 1);
+       tda8290_i2c_bridge(c, 0);
+}
 
-       strlcpy(c->name, "tda8290+75", sizeof(c->name));
+/*---------------------------------------------------------------------*/
+
+int tda8290_init(struct i2c_client *c)
+{
+       struct tuner *t = i2c_get_clientdata(c);
+       u8 data;
+       int i, ret, tuners_found;
+       u32 tuner_addrs;
+       struct i2c_msg msg = {.flags=I2C_M_RD, .buf=&data, .len = 1};
+
+       tda8290_i2c_bridge(c, 1);
+       /* probe for tuner chip */
+       tuners_found = 0;
+       tuner_addrs = 0;
+       for (i=0x60; i<= 0x63; i++) {
+               msg.addr = i;
+               ret = i2c_transfer(c->adapter, &msg, 1);
+               if (ret == 1) {
+                       tuners_found++;
+                       tuner_addrs = (tuner_addrs << 8) + i;
+               }
+       }
+       /* if there is more than one tuner, we expect the right one is
+          behind the bridge and we choose the highest address that doesn't
+          give a response now
+        */
+       tda8290_i2c_bridge(c, 0);
+       if(tuners_found > 1)
+               for (i = 0; i < tuners_found; i++) {
+                       msg.addr = tuner_addrs  & 0xff;
+                       ret = i2c_transfer(c->adapter, &msg, 1);
+                       if(ret == 1)
+                               tuner_addrs = tuner_addrs >> 8;
+                       else
+                               break;
+               }
+       if (tuner_addrs == 0) {
+               tuner_addrs = 0x61;
+               tuner_info ("could not clearly identify tuner address, defaulting to %x\n",
+                            tuner_addrs);
+       } else {
+               tuner_addrs = tuner_addrs & 0xff;
+               tuner_info ("setting tuner address to %x\n", tuner_addrs);
+       }
+       t->tda827x_addr = tuner_addrs;
+       msg.addr = tuner_addrs;
+
+       tda8290_i2c_bridge(c, 1);
+       ret = i2c_transfer(c->adapter, &msg, 1);
+       if( ret != 1)
+               tuner_warn ("TDA827x access failed!\n");
+       if ((data & 0x3c) == 0) {
+               strlcpy(c->name, "tda8290+75", sizeof(c->name));
+               t->tda827x_ver = 0;
+       } else {
+               strlcpy(c->name, "tda8290+75a", sizeof(c->name));
+               t->tda827x_ver = 2;
+       }
        tuner_info("tuner: type set to %s\n", c->name);
+
        t->tv_freq    = set_tv_freq;
        t->radio_freq = set_radio_freq;
        t->has_signal = has_signal;
        t->standby = standby;
+       t->tda827x_lpsel = 0;
 
-       i2c_master_send(c, i2c_enable_bridge, ARRAY_SIZE(i2c_enable_bridge));
-       i2c_transfer(c->adapter, i2c_msg_init, ARRAY_SIZE(i2c_msg_init));
+       tda8290_init_tuner(c);
+       tda8290_init_if(c);
        return 0;
 }
 
+int tda8290_probe(struct i2c_client *c)
+{
+       unsigned char soft_reset[]  = { 0x00, 0x00 };
+       unsigned char easy_mode_b[] = { 0x01, 0x02 };
+       unsigned char easy_mode_g[] = { 0x01, 0x04 };
+       unsigned char addr_dto_lsb = 0x07;
+       unsigned char data;
+
+       i2c_master_send(c, easy_mode_b, 2);
+       i2c_master_send(c, soft_reset, 2);
+       i2c_master_send(c, &addr_dto_lsb, 1);
+       i2c_master_recv(c, &data, 1);
+       if (data == 0) {
+               i2c_master_send(c, easy_mode_g, 2);
+               i2c_master_send(c, soft_reset, 2);
+               i2c_master_send(c, &addr_dto_lsb, 1);
+               i2c_master_recv(c, &data, 1);
+               if (data == 0x7b) {
+                       return 0;
+               }
+       }
+       return -1;
+}
+
 /*
  * Overrides for Emacs so that we follow Linus's tabbing style.
  * ---------------------------------------------------------------------------
index 7e3dcdb262b0ef0c65e18a7c693da652b3da37bc..a5e37dc91f39054e1bdfff22350583540157d2de 100644 (file)
@@ -32,7 +32,6 @@
 
 #include "bttv.h"
 #include <media/audiochip.h>
-#include <media/id.h>
 
 static int debug; /* insmod parameter */
 module_param(debug, int, S_IRUGO | S_IWUSR);
@@ -126,20 +125,20 @@ static int tda9875_write(struct i2c_client *client, int subaddr, unsigned char v
 
 static int i2c_read_register(struct i2c_adapter *adap, int addr, int reg)
 {
-        unsigned char write[1];
-        unsigned char read[1];
-        struct i2c_msg msgs[2] = {
-                { addr, 0,        1, write },
-                { addr, I2C_M_RD, 1, read  }
-        };
-        write[0] = reg;
-
-        if (2 != i2c_transfer(adap,msgs,2)) {
-                printk(KERN_WARNING "tda9875: I/O error (read2)\n");
-                return -1;
-        }
-        dprintk("tda9875: chip_read2: reg%d=0x%x\n",reg,read[0]);
-        return read[0];
+       unsigned char write[1];
+       unsigned char read[1];
+       struct i2c_msg msgs[2] = {
+               { addr, 0,        1, write },
+               { addr, I2C_M_RD, 1, read  }
+       };
+       write[0] = reg;
+
+       if (2 != i2c_transfer(adap,msgs,2)) {
+               printk(KERN_WARNING "tda9875: I/O error (read2)\n");
+               return -1;
+       }
+       dprintk("tda9875: chip_read2: reg%d=0x%x\n",reg,read[0]);
+       return read[0];
 }
 
 static void tda9875_set(struct i2c_client *client)
@@ -184,7 +183,7 @@ static void do_tda9875_init(struct i2c_client *client)
        tda9875_write(client, TDA9875_DACOS, 0x02 ); /* sig DAC i/o(in:nicam)*/
        tda9875_write(client, TDA9875_ADCIS, 0x6f ); /* sig ADC input(in:mono)*/
        tda9875_write(client, TDA9875_LOSR, 0x00 );  /* line out (in:mono)*/
-       tda9875_write(client, TDA9875_AER, 0x00 );   /*06 Effect (AVL+PSEUDO) */
+       tda9875_write(client, TDA9875_AER, 0x00 );   /*06 Effect (AVL+PSEUDO) */
        tda9875_write(client, TDA9875_MCS, 0x44 );   /* Main ch select (DAC) */
        tda9875_write(client, TDA9875_MVL, 0x03 );   /* Vol Main left 10dB */
        tda9875_write(client, TDA9875_MVR, 0x03 );   /* Vol Main right 10dB*/
@@ -200,7 +199,7 @@ static void do_tda9875_init(struct i2c_client *client)
 
        t->mode=AUDIO_UNMUTE;
        t->lvol=t->rvol =0;     /* 0dB */
-       t->bass=0;                      /* 0dB */
+       t->bass=0;                      /* 0dB */
        t->treble=0;            /* 0dB */
        tda9875_set(client);
 
@@ -239,9 +238,9 @@ static int tda9875_attach(struct i2c_adapter *adap, int addr, int kind)
        memset(t,0,sizeof *t);
 
        client = &t->c;
-        memcpy(client,&client_template,sizeof(struct i2c_client));
-        client->adapter = adap;
-        client->addr = addr;
+       memcpy(client,&client_template,sizeof(struct i2c_client));
+       client->adapter = adap;
+       client->addr = addr;
        i2c_set_clientdata(client, t);
 
        if(!tda9875_checkit(adap,addr)) {
@@ -287,7 +286,7 @@ static int tda9875_command(struct i2c_client *client,
        dprintk("In tda9875_command...\n");
 
        switch (cmd) {
-        /* --- v4l ioctls --- */
+       /* --- v4l ioctls --- */
        /* take care: bttv does userspace copying, we'll get a
           kernel pointer here... */
        case VIDIOCGAUDIO:
@@ -355,7 +354,7 @@ static int tda9875_command(struct i2c_client *client,
 //printk("tda9875 bal:%04x vol:%04x bass:%04x treble:%04x\n",va->balance,va->volume,va->bass,va->treble);
 
 
-                tda9875_set(client);
+               tda9875_set(client);
 
                break;
 
@@ -374,18 +373,18 @@ static int tda9875_command(struct i2c_client *client,
 
 static struct i2c_driver driver = {
        .owner          = THIS_MODULE,
-        .name           = "i2c tda9875 driver",
-        .id             = I2C_DRIVERID_TDA9875,
-        .flags          = I2C_DF_NOTIFY,
+       .name           = "i2c tda9875 driver",
+       .id             = I2C_DRIVERID_TDA9875,
+       .flags          = I2C_DF_NOTIFY,
        .attach_adapter = tda9875_probe,
-        .detach_client  = tda9875_detach,
-        .command        = tda9875_command,
+       .detach_client  = tda9875_detach,
+       .command        = tda9875_command,
 };
 
 static struct i2c_client client_template =
 {
-        .name      = "tda9875",
-        .driver    = &driver,
+       .name      = "tda9875",
+       .driver    = &driver,
 };
 
 static int __init tda9875_init(void)
index 94053f149ddf57f1bbfd16f39cd6dca6abab77cf..4249127c0a1d67c3b144f63f31888caa0609ed05 100644 (file)
@@ -11,7 +11,6 @@
 
 #include <media/audiochip.h>
 #include <media/tuner.h>
-#include <media/id.h>
 
 /* Chips:
    TDA9885 (PAL, NTSC)
@@ -44,8 +43,13 @@ MODULE_LICENSE("GPL");
 /* ---------------------------------------------------------------------- */
 
 #define UNSET       (-1U)
-#define PREFIX      "tda9885/6/7: "
-#define dprintk     if (debug) printk
+#define tda9887_info(fmt, arg...) do {\
+       printk(KERN_INFO "%s %d-%04x: " fmt, t->client.name, \
+                       i2c_adapter_id(t->client.adapter), t->client.addr , ##arg); } while (0)
+#define tda9887_dbg(fmt, arg...) do {\
+       if (debug) \
+               printk(KERN_INFO "%s %d-%04x: " fmt, t->client.name, \
+                       i2c_adapter_id(t->client.adapter), t->client.addr , ##arg); } while (0)
 
 struct tda9887 {
        struct i2c_client  client;
@@ -55,6 +59,7 @@ struct tda9887 {
        unsigned int       pinnacle_id;
        unsigned int       using_v4l2;
        unsigned int       radio_mode;
+       unsigned char      data[4];
 };
 
 struct tvnorm {
@@ -180,7 +185,8 @@ static struct tvnorm tvnorms[] = {
                .name  = "SECAM-L",
                .b     = ( cPositiveAmTV  |
                           cQSS           ),
-               .e     = ( cAudioIF_6_5   |
+               .e     = ( cGating_36     |
+                          cAudioIF_6_5   |
                           cVideoIF_38_90 ),
        },{
                .std   = V4L2_STD_SECAM_DK,
@@ -236,7 +242,7 @@ static struct tvnorm radio_mono = {
 
 /* ---------------------------------------------------------------------- */
 
-static void dump_read_message(unsigned char *buf)
+static void dump_read_message(struct tda9887 *t, unsigned char *buf)
 {
        static char *afc[16] = {
                "- 12.5 kHz",
@@ -256,15 +262,15 @@ static void dump_read_message(unsigned char *buf)
                "+ 37.5 kHz",
                "+ 12.5 kHz",
        };
-       printk(PREFIX "read: 0x%2x\n", buf[0]);
-       printk("  after power on : %s\n", (buf[0] & 0x01) ? "yes" : "no");
-       printk("  afc            : %s\n", afc[(buf[0] >> 1) & 0x0f]);
-       printk("  fmif level     : %s\n", (buf[0] & 0x20) ? "high" : "low");
-       printk("  afc window     : %s\n", (buf[0] & 0x40) ? "in" : "out");
-       printk("  vfi level      : %s\n", (buf[0] & 0x80) ? "high" : "low");
+       tda9887_info("read: 0x%2x\n", buf[0]);
+       tda9887_info("  after power on : %s\n", (buf[0] & 0x01) ? "yes" : "no");
+       tda9887_info("  afc            : %s\n", afc[(buf[0] >> 1) & 0x0f]);
+       tda9887_info("  fmif level     : %s\n", (buf[0] & 0x20) ? "high" : "low");
+       tda9887_info("  afc window     : %s\n", (buf[0] & 0x40) ? "in" : "out");
+       tda9887_info("  vfi level      : %s\n", (buf[0] & 0x80) ? "high" : "low");
 }
 
-static void dump_write_message(unsigned char *buf)
+static void dump_write_message(struct tda9887 *t, unsigned char *buf)
 {
        static char *sound[4] = {
                "AM/TV",
@@ -304,58 +310,58 @@ static void dump_write_message(unsigned char *buf)
                "44 MHz",
        };
 
-       printk(PREFIX "write: byte B 0x%02x\n",buf[1]);
-       printk("  B0   video mode      : %s\n",
+       tda9887_info("write: byte B 0x%02x\n",buf[1]);
+       tda9887_info("  B0   video mode      : %s\n",
               (buf[1] & 0x01) ? "video trap" : "sound trap");
-       printk("  B1   auto mute fm    : %s\n",
+       tda9887_info("  B1   auto mute fm    : %s\n",
               (buf[1] & 0x02) ? "yes" : "no");
-       printk("  B2   carrier mode    : %s\n",
+       tda9887_info("  B2   carrier mode    : %s\n",
               (buf[1] & 0x04) ? "QSS" : "Intercarrier");
-       printk("  B3-4 tv sound/radio  : %s\n",
+       tda9887_info("  B3-4 tv sound/radio  : %s\n",
               sound[(buf[1] & 0x18) >> 3]);
-       printk("  B5   force mute audio: %s\n",
+       tda9887_info("  B5   force mute audio: %s\n",
               (buf[1] & 0x20) ? "yes" : "no");
-       printk("  B6   output port 1   : %s\n",
+       tda9887_info("  B6   output port 1   : %s\n",
               (buf[1] & 0x40) ? "high (inactive)" : "low (active)");
-       printk("  B7   output port 2   : %s\n",
+       tda9887_info("  B7   output port 2   : %s\n",
               (buf[1] & 0x80) ? "high (inactive)" : "low (active)");
 
-       printk(PREFIX "write: byte C 0x%02x\n",buf[2]);
-       printk("  C0-4 top adjustment  : %s dB\n", adjust[buf[2] & 0x1f]);
-       printk("  C5-6 de-emphasis     : %s\n", deemph[(buf[2] & 0x60) >> 5]);
-       printk("  C7   audio gain      : %s\n",
+       tda9887_info("write: byte C 0x%02x\n",buf[2]);
+       tda9887_info("  C0-4 top adjustment  : %s dB\n", adjust[buf[2] & 0x1f]);
+       tda9887_info("  C5-6 de-emphasis     : %s\n", deemph[(buf[2] & 0x60) >> 5]);
+       tda9887_info("  C7   audio gain      : %s\n",
               (buf[2] & 0x80) ? "-6" : "0");
 
-       printk(PREFIX "write: byte E 0x%02x\n",buf[3]);
-       printk("  E0-1 sound carrier   : %s\n",
+       tda9887_info("write: byte E 0x%02x\n",buf[3]);
+       tda9887_info("  E0-1 sound carrier   : %s\n",
               carrier[(buf[3] & 0x03)]);
-       printk("  E6   l pll ganting   : %s\n",
+       tda9887_info("  E6   l pll gating   : %s\n",
               (buf[3] & 0x40) ? "36" : "13");
 
        if (buf[1] & 0x08) {
                /* radio */
-               printk("  E2-4 video if        : %s\n",
+               tda9887_info("  E2-4 video if        : %s\n",
                       rif[(buf[3] & 0x0c) >> 2]);
-               printk("  E7   vif agc output  : %s\n",
+               tda9887_info("  E7   vif agc output  : %s\n",
                       (buf[3] & 0x80)
                       ? ((buf[3] & 0x10) ? "fm-agc radio" : "sif-agc radio")
                       : "fm radio carrier afc");
        } else {
                /* video */
-               printk("  E2-4 video if        : %s\n",
+               tda9887_info("  E2-4 video if        : %s\n",
                       vif[(buf[3] & 0x1c) >> 2]);
-               printk("  E5   tuner gain      : %s\n",
+               tda9887_info("  E5   tuner gain      : %s\n",
                       (buf[3] & 0x80)
                       ? ((buf[3] & 0x20) ? "external" : "normal")
                       : ((buf[3] & 0x20) ? "minimum"  : "normal"));
-               printk("  E7   vif agc output  : %s\n",
+               tda9887_info("  E7   vif agc output  : %s\n",
                       (buf[3] & 0x80)
                       ? ((buf[3] & 0x20)
                          ? "pin3 port, pin22 vif agc out"
                          : "pin22 port, pin3 vif acg ext in")
                       : "pin3+pin22 port");
        }
-       printk("--\n");
+       tda9887_info("--\n");
 }
 
 /* ---------------------------------------------------------------------- */
@@ -379,11 +385,11 @@ static int tda9887_set_tvnorm(struct tda9887 *t, char *buf)
                }
        }
        if (NULL == norm) {
-               dprintk(PREFIX "Unsupported tvnorm entry - audio muted\n");
+               tda9887_dbg("Unsupported tvnorm entry - audio muted\n");
                return -1;
        }
 
-       dprintk(PREFIX "configure for: %s\n",norm->name);
+       tda9887_dbg("configure for: %s\n",norm->name);
        buf[1] = norm->b;
        buf[2] = norm->c;
        buf[3] = norm->e;
@@ -458,6 +464,8 @@ static int tda9887_set_config(struct tda9887 *t, char *buf)
                        break;
                }
        }
+       if ((t->config & TDA9887_INTERCARRIER_NTSC) && (t->std & V4L2_STD_NTSC))
+               buf[1] &= ~cQSS;
        return 0;
 }
 
@@ -475,11 +483,11 @@ static int tda9887_set_pinnacle(struct tda9887 *t, char *buf)
                }
        }
        if (t->std & V4L2_STD_525_60) {
-                if ((5 == t->pinnacle_id) || (6 == t->pinnacle_id)) {
+               if ((5 == t->pinnacle_id) || (6 == t->pinnacle_id)) {
                        bCarrierMode = cIntercarrier;
                } else {
                        bCarrierMode = cQSS;
-                }
+               }
        }
 
        if (bCarrierMode != UNSET) {
@@ -505,26 +513,26 @@ static int tda9887_fixup_std(struct tda9887 *t)
                case 'B':
                case 'g':
                case 'G':
-                       dprintk(PREFIX "insmod fixup: PAL => PAL-BG\n");
+                       tda9887_dbg("insmod fixup: PAL => PAL-BG\n");
                        t->std = V4L2_STD_PAL_BG;
                        break;
                case 'i':
                case 'I':
-                       dprintk(PREFIX "insmod fixup: PAL => PAL-I\n");
+                       tda9887_dbg("insmod fixup: PAL => PAL-I\n");
                        t->std = V4L2_STD_PAL_I;
                        break;
                case 'd':
                case 'D':
                case 'k':
                case 'K':
-                       dprintk(PREFIX "insmod fixup: PAL => PAL-DK\n");
+                       tda9887_dbg("insmod fixup: PAL => PAL-DK\n");
                        t->std = V4L2_STD_PAL_DK;
                        break;
                case '-':
                        /* default parameter, do nothing */
                        break;
                default:
-                       printk(PREFIX "pal= argument not recognised\n");
+                       tda9887_info("pal= argument not recognised\n");
                        break;
                }
        }
@@ -534,19 +542,19 @@ static int tda9887_fixup_std(struct tda9887 *t)
                case 'D':
                case 'k':
                case 'K':
-                       dprintk(PREFIX "insmod fixup: SECAM => SECAM-DK\n");
+                       tda9887_dbg("insmod fixup: SECAM => SECAM-DK\n");
                        t->std = V4L2_STD_SECAM_DK;
                        break;
                case 'l':
                case 'L':
-                       dprintk(PREFIX "insmod fixup: SECAM => SECAM-L\n");
+                       tda9887_dbg("insmod fixup: SECAM => SECAM-L\n");
                        t->std = V4L2_STD_SECAM_L;
                        break;
                case '-':
                        /* default parameter, do nothing */
                        break;
                default:
-                       printk(PREFIX "secam= argument not recognised\n");
+                       tda9887_info("secam= argument not recognised\n");
                        break;
                }
        }
@@ -559,41 +567,40 @@ static int tda9887_status(struct tda9887 *t)
        int rc;
 
        memset(buf,0,sizeof(buf));
-        if (1 != (rc = i2c_master_recv(&t->client,buf,1)))
-                printk(PREFIX "i2c i/o error: rc == %d (should be 1)\n",rc);
-       dump_read_message(buf);
+       if (1 != (rc = i2c_master_recv(&t->client,buf,1)))
+               tda9887_info("i2c i/o error: rc == %d (should be 1)\n",rc);
+       dump_read_message(t, buf);
        return 0;
 }
 
 static int tda9887_configure(struct tda9887 *t)
 {
-       unsigned char buf[4];
        int rc;
 
-       memset(buf,0,sizeof(buf));
-       tda9887_set_tvnorm(t,buf);
+       memset(t->data,0,sizeof(t->data));
+       tda9887_set_tvnorm(t,t->data);
 
-       buf[1] |= cOutputPort1Inactive;
-       buf[1] |= cOutputPort2Inactive;
+       t->data[1] |= cOutputPort1Inactive;
+       t->data[1] |= cOutputPort2Inactive;
 
        if (UNSET != t->pinnacle_id) {
-               tda9887_set_pinnacle(t,buf);
+               tda9887_set_pinnacle(t,t->data);
        }
-       tda9887_set_config(t,buf);
-       tda9887_set_insmod(t,buf);
+       tda9887_set_config(t,t->data);
+       tda9887_set_insmod(t,t->data);
 
        if (t->mode == T_STANDBY) {
-               buf[1] |= cForcedMuteAudioON;
+               t->data[1] |= cForcedMuteAudioON;
        }
 
 
-       dprintk(PREFIX "writing: b=0x%02x c=0x%02x e=0x%02x\n",
-               buf[1],buf[2],buf[3]);
+       tda9887_dbg("writing: b=0x%02x c=0x%02x e=0x%02x\n",
+               t->data[1],t->data[2],t->data[3]);
        if (debug > 1)
-               dump_write_message(buf);
+               dump_write_message(t, t->data);
 
-        if (4 != (rc = i2c_master_send(&t->client,buf,4)))
-                printk(PREFIX "i2c i/o error: rc == %d (should be 4)\n",rc);
+       if (4 != (rc = i2c_master_send(&t->client,t->data,4)))
+               tda9887_info("i2c i/o error: rc == %d (should be 4)\n",rc);
 
        if (debug > 2) {
                msleep_interruptible(1000);
@@ -608,13 +615,11 @@ static int tda9887_attach(struct i2c_adapter *adap, int addr, int kind)
 {
        struct tda9887 *t;
 
-        client_template.adapter = adap;
-        client_template.addr    = addr;
-
-        printk(PREFIX "chip found @ 0x%x\n", addr<<1);
+       client_template.adapter = adap;
+       client_template.addr    = addr;
 
-        if (NULL == (t = kmalloc(sizeof(*t), GFP_KERNEL)))
-                return -ENOMEM;
+       if (NULL == (t = kmalloc(sizeof(*t), GFP_KERNEL)))
+               return -ENOMEM;
        memset(t,0,sizeof(*t));
 
        t->client      = client_template;
@@ -622,6 +627,8 @@ static int tda9887_attach(struct i2c_adapter *adap, int addr, int kind)
        t->pinnacle_id = UNSET;
        t->radio_mode = V4L2_TUNER_MODE_STEREO;
 
+       tda9887_info("chip found @ 0x%x (%s)\n", addr<<1, adap->name);
+
        i2c_set_clientdata(&t->client, t);
        i2c_attach_client(&t->client);
 
@@ -655,18 +662,18 @@ static int tda9887_detach(struct i2c_client *client)
 }
 
 #define SWITCH_V4L2    if (!t->using_v4l2 && debug) \
-                         printk(PREFIX "switching to v4l2\n"); \
-                         t->using_v4l2 = 1;
+                         tda9887_info("switching to v4l2\n"); \
+                         t->using_v4l2 = 1;
 #define CHECK_V4L2     if (t->using_v4l2) { if (debug) \
-                         printk(PREFIX "ignore v4l1 call\n"); \
-                         return 0; }
+                         tda9887_info("ignore v4l1 call\n"); \
+                         return 0; }
 
 static int
 tda9887_command(struct i2c_client *client, unsigned int cmd, void *arg)
 {
        struct tda9887 *t = i2c_get_clientdata(client);
 
-        switch (cmd) {
+       switch (cmd) {
 
        /* --- configuration --- */
        case AUDC_SET_RADIO:
@@ -777,6 +784,11 @@ tda9887_command(struct i2c_client *client, unsigned int cmd, void *arg)
                }
                break;
        }
+       case VIDIOC_LOG_STATUS:
+       {
+               tda9887_info("Data bytes: b=%02x c=%02x e=%02x\n", t->data[1], t->data[2], t->data[3]);
+               break;
+       }
        default:
                /* nothing */
                break;
@@ -786,7 +798,10 @@ tda9887_command(struct i2c_client *client, unsigned int cmd, void *arg)
 
 static int tda9887_suspend(struct device * dev, pm_message_t state)
 {
-       dprintk("tda9887: suspend\n");
+       struct i2c_client *c = container_of(dev, struct i2c_client, dev);
+       struct tda9887 *t = i2c_get_clientdata(c);
+
+       tda9887_dbg("suspend\n");
        return 0;
 }
 
@@ -795,7 +810,7 @@ static int tda9887_resume(struct device * dev)
        struct i2c_client *c = container_of(dev, struct i2c_client, dev);
        struct tda9887 *t = i2c_get_clientdata(c);
 
-       dprintk("tda9887: resume\n");
+       tda9887_dbg("resume\n");
        tda9887_configure(t);
        return 0;
 }
index 38bf50943798cee2cfd83c8db523c1c560242bb9..a9375ef05de121b5986060fc6c464f97d0d53e3f 100644 (file)
 #define TEA5767_RESERVED_MASK  0xff
 
 enum tea5767_xtal_freq {
-        TEA5767_LOW_LO_32768    = 0,
-        TEA5767_HIGH_LO_32768   = 1,
-        TEA5767_LOW_LO_13MHz    = 2,
-        TEA5767_HIGH_LO_13MHz   = 3,
+       TEA5767_LOW_LO_32768    = 0,
+       TEA5767_HIGH_LO_32768   = 1,
+       TEA5767_LOW_LO_13MHz    = 2,
+       TEA5767_HIGH_LO_13MHz   = 3,
 };
 
 
index ad85bef1c3d5d20bcd256704ea868352fd3fca1f..73c4041c35d78811f1fdd25585c6187c5ffa32b3 100644 (file)
@@ -28,7 +28,7 @@
 
 /* standard i2c insmod options */
 static unsigned short normal_i2c[] = {
-       0x4b,                   /* tda8290 */
+       0x42, 0x43, 0x4a, 0x4b,                 /* tda8290 */
        0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67,
        0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f,
        I2C_CLIENT_END
@@ -189,6 +189,13 @@ static void set_type(struct i2c_client *c, unsigned int type,
                i2c_master_send(c, buffer, 4);
                default_tuner_init(c);
                break;
+       case TUNER_PHILIPS_TD1316:
+               buffer[0] = 0x0b;
+               buffer[1] = 0xdc;
+               buffer[2] = 0x86;
+               buffer[3] = 0xa4;
+               i2c_master_send(c,buffer,4);
+               default_tuner_init(c);
        default:
                default_tuner_init(c);
                break;
@@ -215,9 +222,9 @@ static void set_addr(struct i2c_client *c, struct tuner_setup *tun_setup)
 {
        struct tuner *t = i2c_get_clientdata(c);
 
-       if ((tun_setup->addr == ADDR_UNSET &&
+       if ( t->type == UNSET && ((tun_setup->addr == ADDR_UNSET &&
                (t->mode_mask & tun_setup->mode_mask)) ||
-               tun_setup->addr == c->addr) {
+               tun_setup->addr == c->addr)) {
                        set_type(c, tun_setup->type, tun_setup->mode_mask);
        }
 }
@@ -341,23 +348,33 @@ static int tuner_attach(struct i2c_adapter *adap, int addr, int kind)
        t->audmode = V4L2_TUNER_MODE_STEREO;
        t->mode_mask = T_UNINITIALIZED;
 
-
-       tuner_info("chip found @ 0x%x (%s)\n", addr << 1, adap->name);
-
        if (show_i2c) {
                unsigned char buffer[16];
                int i,rc;
 
                memset(buffer, 0, sizeof(buffer));
                rc = i2c_master_recv(&t->i2c, buffer, sizeof(buffer));
-               printk("tuner-%04x I2C RECV = ",addr);
+               tuner_info("I2C RECV = ");
                for (i=0;i<rc;i++)
                        printk("%02x ",buffer[i]);
                printk("\n");
        }
        /* TEA5767 autodetection code - only for addr = 0xc0 */
        if (!no_autodetect) {
-               if (addr == 0x60) {
+               switch (addr) {
+               case 0x42:
+               case 0x43:
+               case 0x4a:
+               case 0x4b:
+                       /* If chip is not tda8290, don't register.
+                          since it can be tda9887*/
+                       if (tda8290_probe(&t->i2c) != 0) {
+                               tuner_dbg("chip at addr %x is not a tda8290\n", addr);
+                               kfree(t);
+                               return 0;
+                       }
+                       break;
+               case 0x60:
                        if (tea5767_autodetection(&t->i2c) != EINVAL) {
                                t->type = TUNER_TEA5767;
                                t->mode_mask = T_RADIO;
@@ -365,10 +382,9 @@ static int tuner_attach(struct i2c_adapter *adap, int addr, int kind)
                                t->freq = 87.5 * 16; /* Sets freq to FM range */
                                default_mode_mask &= ~T_RADIO;
 
-                               i2c_attach_client (&t->i2c);
-                               set_type(&t->i2c,t->type, t->mode_mask);
-                               return 0;
+                               goto register_client;
                        }
+                       break;
                }
        }
 
@@ -381,6 +397,8 @@ static int tuner_attach(struct i2c_adapter *adap, int addr, int kind)
        }
 
        /* Should be just before return */
+register_client:
+       tuner_info("chip found @ 0x%x (%s)\n", addr << 1, adap->name);
        i2c_attach_client (&t->i2c);
        set_type (&t->i2c,t->type, t->mode_mask);
        return 0;
@@ -425,23 +443,23 @@ static int tuner_detach(struct i2c_client *client)
 
 static inline int set_mode(struct i2c_client *client, struct tuner *t, int mode, char *cmd)
 {
-       if (mode == t->mode)
-               return 0;
-
-       t->mode = mode;
-
-       if (check_mode(t, cmd) == EINVAL) {
-               t->mode = T_STANDBY;
-               if (t->standby)
-                       t->standby (client);
-               return EINVAL;
-       }
-       return 0;
+       if (mode == t->mode)
+               return 0;
+
+       t->mode = mode;
+
+       if (check_mode(t, cmd) == EINVAL) {
+               t->mode = T_STANDBY;
+               if (t->standby)
+                       t->standby (client);
+               return EINVAL;
+       }
+       return 0;
 }
 
 #define switch_v4l2()  if (!t->using_v4l2) \
-                           tuner_dbg("switching to v4l2\n"); \
-                       t->using_v4l2 = 1;
+                           tuner_dbg("switching to v4l2\n"); \
+                       t->using_v4l2 = 1;
 
 static inline int check_v4l2(struct tuner *t)
 {
@@ -479,8 +497,6 @@ static int tuner_command(struct i2c_client *client, unsigned int cmd, void *arg)
                        break;
                }
        case AUDC_CONFIG_PINNACLE:
-               if (check_mode(t, "AUDC_CONFIG_PINNACLE") == EINVAL)
-                       return 0;
                switch (*iarg) {
                case 2:
                        tuner_dbg("pinnacle pal\n");
@@ -616,7 +632,7 @@ static int tuner_command(struct i2c_client *client, unsigned int cmd, void *arg)
                        switch_v4l2();
                        if (V4L2_TUNER_RADIO == f->type &&
                            V4L2_TUNER_RADIO != t->mode) {
-                               if (set_mode (client, t, f->type, "VIDIOC_S_FREQUENCY")
+                               if (set_mode (client, t, f->type, "VIDIOC_S_FREQUENCY")
                                            == EINVAL)
                                        return 0;
                        }
@@ -688,7 +704,7 @@ static int tuner_command(struct i2c_client *client, unsigned int cmd, void *arg)
                        break;
                }
        default:
-               tuner_dbg("Unimplemented IOCTL 0x%08x(dir=%d,tp=0x%02x,nr=%d,sz=%d)\n",
+               tuner_dbg("Unimplemented IOCTL 0x%08x(dir=%d,tp='%c',nr=%d,sz=%d)\n",
                                         cmd, _IOC_DIR(cmd), _IOC_TYPE(cmd),
                                        _IOC_NR(cmd), _IOC_SIZE(cmd));
                break;
index 8edd73abe1d8cb356c639ac904fb870ed2473b4e..d832205818f21ef94b0c0d85e4e2e016a938a5db 100644 (file)
@@ -102,7 +102,7 @@ struct tunertype
  */
 static struct tunertype tuners[] = {
        /* 0-9 */
-        { "Temic PAL (4002 FH5)", TEMIC, PAL,
+       { "Temic PAL (4002 FH5)", TEMIC, PAL,
          16*140.25,16*463.25,0x02,0x04,0x01,0x8e,623},
        { "Philips PAL_I (FI1246 and compatibles)", Philips, PAL_I,
          16*140.25,16*463.25,0xa0,0x90,0x30,0x8e,623},
@@ -118,41 +118,41 @@ static struct tunertype tuners[] = {
          16*157.25,16*463.25,0x02,0x04,0x01,0x8e,732},
        { "Temic PAL_I (4062 FY5)", TEMIC, PAL_I,
          16*170.00,16*450.00,0x02,0x04,0x01,0x8e,623},
-       { "Temic NTSC (4036 FY5)", TEMIC, NTSC,
+       { "Temic NTSC (4036 FY5)", TEMIC, NTSC,
          16*157.25,16*463.25,0xa0,0x90,0x30,0x8e,732},
-        { "Alps HSBH1", TEMIC, NTSC,
+       { "Alps HSBH1", TEMIC, NTSC,
          16*137.25,16*385.25,0x01,0x02,0x08,0x8e,732},
 
        /* 10-19 */
-        { "Alps TSBE1", TEMIC, PAL,
+       { "Alps TSBE1", TEMIC, PAL,
          16*137.25,16*385.25,0x01,0x02,0x08,0x8e,732},
-        { "Alps TSBB5", Alps, PAL_I, /* tested (UK UHF) with Modulartech MM205 */
+       { "Alps TSBB5", Alps, PAL_I, /* tested (UK UHF) with Modulartech MM205 */
          16*133.25,16*351.25,0x01,0x02,0x08,0x8e,632},
-        { "Alps TSBE5", Alps, PAL, /* untested - data sheet guess. Only IF differs. */
+       { "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. */
+       { "Alps TSBC5", Alps, PAL, /* untested - data sheet guess. Only IF differs. */
          16*133.25,16*351.25,0x01,0x02,0x08,0x8e,608},
        { "Temic PAL_BG (4006FH5)", TEMIC, PAL,
          16*170.00,16*450.00,0xa0,0x90,0x30,0x8e,623},
-       { "Alps TSCH6", Alps, NTSC,
-         16*137.25,16*385.25,0x14,0x12,0x11,0x8e,732},
-       { "Temic PAL_DK (4016 FY5)", TEMIC, PAL,
-         16*168.25,16*456.25,0xa0,0x90,0x30,0x8e,623},
-       { "Philips NTSC_M (MK2)", Philips, NTSC,
-         16*160.00,16*454.00,0xa0,0x90,0x30,0x8e,732},
-        { "Temic PAL_I (4066 FY5)", TEMIC, PAL_I,
-          16*169.00, 16*454.00, 0xa0,0x90,0x30,0x8e,623},
-        { "Temic PAL* auto (4006 FN5)", TEMIC, PAL,
-          16*169.00, 16*454.00, 0xa0,0x90,0x30,0x8e,623},
+       { "Alps TSCH6", Alps, NTSC,
+         16*137.25,16*385.25,0x14,0x12,0x11,0x8e,732},
+       { "Temic PAL_DK (4016 FY5)", TEMIC, PAL,
+         16*168.25,16*456.25,0xa0,0x90,0x30,0x8e,623},
+       { "Philips NTSC_M (MK2)", Philips, NTSC,
+         16*160.00,16*454.00,0xa0,0x90,0x30,0x8e,732},
+       { "Temic PAL_I (4066 FY5)", TEMIC, PAL_I,
+         16*169.00, 16*454.00, 0xa0,0x90,0x30,0x8e,623},
+       { "Temic PAL* auto (4006 FN5)", TEMIC, PAL,
+         16*169.00, 16*454.00, 0xa0,0x90,0x30,0x8e,623},
 
        /* 20-29 */
-        { "Temic PAL_BG (4009 FR5) or PAL_I (4069 FR5)", TEMIC, PAL,
-          16*141.00, 16*464.00, 0xa0,0x90,0x30,0x8e,623},
-        { "Temic NTSC (4039 FR5)", TEMIC, NTSC,
-          16*158.00, 16*453.00, 0xa0,0x90,0x30,0x8e,732},
-        { "Temic PAL/SECAM multi (4046 FM5)", TEMIC, PAL,
-          16*169.00, 16*454.00, 0xa0,0x90,0x30,0x8e,623},
-        { "Philips PAL_DK (FI1256 and compatibles)", Philips, PAL,
+       { "Temic PAL_BG (4009 FR5) or PAL_I (4069 FR5)", TEMIC, PAL,
+         16*141.00, 16*464.00, 0xa0,0x90,0x30,0x8e,623},
+       { "Temic NTSC (4039 FR5)", TEMIC, NTSC,
+         16*158.00, 16*453.00, 0xa0,0x90,0x30,0x8e,732},
+       { "Temic PAL/SECAM multi (4046 FM5)", TEMIC, PAL,
+         16*169.00, 16*454.00, 0xa0,0x90,0x30,0x8e,623},
+       { "Philips PAL_DK (FI1256 and compatibles)", Philips, PAL,
          16*170.00,16*450.00,0xa0,0x90,0x30,0x8e,623},
        { "Philips PAL/SECAM multi (FQ1216ME)", Philips, PAL,
          16*170.00,16*450.00,0xa0,0x90,0x30,0x8e,623},
@@ -173,21 +173,21 @@ static struct tunertype tuners[] = {
        { "SHARP NTSC_JP (2U5JF5540)", SHARP, NTSC, /* 940=16*58.75 NTSC@Japan */
          16*137.25,16*317.25,0x01,0x02,0x08,0x8e,940 },
        { "Samsung PAL TCPM9091PD27", Samsung, PAL, /* from sourceforge v3tv */
-          16*169,16*464,0xA0,0x90,0x30,0x8e,623},
+         16*169,16*464,0xA0,0x90,0x30,0x8e,623},
        { "MT20xx universal", Microtune, PAL|NTSC,
          /* see mt20xx.c for details */ },
        { "Temic PAL_BG (4106 FH5)", TEMIC, PAL,
-          16*141.00, 16*464.00, 0xa0,0x90,0x30,0x8e,623},
+         16*141.00, 16*464.00, 0xa0,0x90,0x30,0x8e,623},
        { "Temic PAL_DK/SECAM_L (4012 FY5)", TEMIC, PAL,
-          16*140.25, 16*463.25, 0x02,0x04,0x01,0x8e,623},
+         16*140.25, 16*463.25, 0x02,0x04,0x01,0x8e,623},
        { "Temic NTSC (4136 FY5)", TEMIC, NTSC,
-          16*158.00, 16*453.00, 0xa0,0x90,0x30,0x8e,732},
-        { "LG PAL (newer TAPC series)", LGINNOTEK, PAL,
-          16*170.00, 16*450.00, 0x01,0x02,0x08,0x8e,623},
+         16*158.00, 16*453.00, 0xa0,0x90,0x30,0x8e,732},
+       { "LG PAL (newer TAPC series)", LGINNOTEK, PAL,
+         16*170.00, 16*450.00, 0x01,0x02,0x08,0x8e,623},
        { "Philips PAL/SECAM multi (FM1216ME MK3)", Philips, PAL,
-         16*160.00,16*442.00,0x01,0x02,0x04,0x8e,623 },
+         16*158.00,16*442.00,0x01,0x02,0x04,0x8e,623 },
        { "LG NTSC (newer TAPC series)", LGINNOTEK, NTSC,
-          16*170.00, 16*450.00, 0x01,0x02,0x08,0x8e,732},
+         16*170.00, 16*450.00, 0x01,0x02,0x08,0x8e,732},
 
        /* 40-49 */
        { "HITACHI V7-J180AT", HITACHI, NTSC,
@@ -196,24 +196,24 @@ static struct tunertype tuners[] = {
          16*140.25,16*463.25,0x01,0xc2,0xcf,0x8e,623},
        { "Philips 1236D ATSC/NTSC daul in", Philips, ATSC,
          16*157.25,16*454.00,0xa0,0x90,0x30,0x8e,732},
-        { "Philips NTSC MK3 (FM1236MK3 or FM1236/F)", Philips, NTSC,
-          16*160.00,16*442.00,0x01,0x02,0x04,0x8e,732},
-        { "Philips 4 in 1 (ATI TV Wonder Pro/Conexant)", Philips, NTSC,
-          16*160.00,16*442.00,0x01,0x02,0x04,0x8e,732},
+       { "Philips NTSC MK3 (FM1236MK3 or FM1236/F)", Philips, NTSC,
+         16*160.00,16*442.00,0x01,0x02,0x04,0x8e,732},
+       { "Philips 4 in 1 (ATI TV Wonder Pro/Conexant)", Philips, NTSC,
+         16*160.00,16*442.00,0x01,0x02,0x04,0x8e,732},
        { "Microtune 4049 FM5", Microtune, PAL,
          16*141.00,16*464.00,0xa0,0x90,0x30,0x8e,623},
        { "Panasonic VP27s/ENGE4324D", Panasonic, NTSC,
          16*160.00,16*454.00,0x01,0x02,0x08,0xce,940},
-        { "LG NTSC (TAPE series)", LGINNOTEK, NTSC,
-          16*160.00,16*442.00,0x01,0x02,0x04,0x8e,732 },
-        { "Tenna TNF 8831 BGFF)", Philips, PAL,
-          16*161.25,16*463.25,0xa0,0x90,0x30,0x8e,623},
+       { "LG NTSC (TAPE series)", LGINNOTEK, NTSC,
+         16*160.00,16*442.00,0x01,0x02,0x04,0x8e,732 },
+       { "Tenna TNF 8831 BGFF)", Philips, PAL,
+         16*161.25,16*463.25,0xa0,0x90,0x30,0x8e,623},
        { "Microtune 4042 FI5 ATSC/NTSC dual in", Microtune, NTSC,
          16*162.00,16*457.00,0xa2,0x94,0x31,0x8e,732},
 
        /* 50-59 */
-        { "TCL 2002N", TCL, NTSC,
-          16*172.00,16*448.00,0x01,0x02,0x08,0x8e,732},
+       { "TCL 2002N", TCL, NTSC,
+         16*172.00,16*448.00,0x01,0x02,0x08,0x8e,732},
        { "Philips PAL/SECAM_D (FM 1256 I-H3)", Philips, PAL,
          16*160.00,16*442.00,0x01,0x02,0x04,0x8e,623 },
        { "Thomson DDT 7610 (ATSC/NTSC)", THOMSON, ATSC,
@@ -222,8 +222,8 @@ static struct tunertype tuners[] = {
          16*160.00,16*454.00,0x41,0x42,0x04,0x8e,940}, /* UHF band untested */
        { "tda8290+75", Philips, PAL|NTSC,
          /* see tda8290.c for details */ },
-       { "LG PAL (TAPE series)", LGINNOTEK, PAL,
-          16*170.00, 16*450.00, 0x01,0x02,0x08,0xce,623},
+       { "TCL 2002MB", TCL, PAL,
+         16*170.00, 16*450.00, 0x01,0x02,0x08,0xce,623},
        { "Philips PAL/SECAM multi (FQ1216AME MK4)", Philips, PAL,
          16*160.00,16*442.00,0x01,0x02,0x04,0xce,623 },
        { "Philips FQ1236A MK4", Philips, NTSC,
@@ -233,21 +233,25 @@ static struct tunertype tuners[] = {
        { "Ymec TVision TVF-5533MF", Philips, NTSC,
          16*160.00,16*454.00,0x01,0x02,0x04,0x8e,732},
 
-       /* 60-66 */
+       /* 60-68 */
        { "Thomson DDT 7611 (ATSC/NTSC)", THOMSON, ATSC,
          16*157.25,16*454.00,0x39,0x3a,0x3c,0x8e,732},
        { "Tena TNF9533-D/IF/TNF9533-B/DF", Philips, PAL,
-          16*160.25,16*464.25,0x01,0x02,0x04,0x8e,623},
+         16*160.25,16*464.25,0x01,0x02,0x04,0x8e,623},
        { "Philips TEA5767HN FM Radio", Philips, RADIO,
-          /* see tea5767.c for details */},
+         /* see tea5767.c for details */},
        { "Philips FMD1216ME MK3 Hybrid Tuner", Philips, PAL,
          16*160.00,16*442.00,0x51,0x52,0x54,0x86,623 },
        { "LG TDVS-H062F/TUA6034", LGINNOTEK, ATSC,
          16*160.00,16*455.00,0x01,0x02,0x04,0x8e,732},
        { "Ymec TVF66T5-B/DFF", Philips, PAL,
-          16*160.25,16*464.25,0x01,0x02,0x08,0x8e,623},
-       { "LG NTSC (TALN mini series)", LGINNOTEK, NTSC,
+         16*160.25,16*464.25,0x01,0x02,0x08,0x8e,623},
+       { "LG NTSC (TALN mini series)", LGINNOTEK, NTSC,
          16*137.25,16*373.25,0x01,0x02,0x08,0x8e,732 },
+       { "Philips TD1316 Hybrid Tuner", Philips, PAL,
+         16*160.00,16*442.00,0xa1,0xa2,0xa4,0xc8,623 },
+       { "Philips TUV1236D ATSC/NTSC dual in", Philips, ATSC,
+         16*157.25,16*454.00,0x01,0x02,0x04,0xce,732 },
 };
 
 unsigned const int tuner_count = ARRAY_SIZE(tuners);
@@ -277,7 +281,7 @@ static int tuner_stereo(struct i2c_client *c)
        status = tuner_getstatus (c);
 
        switch (t->type) {
-               case TUNER_PHILIPS_FM1216ME_MK3:
+               case TUNER_PHILIPS_FM1216ME_MK3:
                case TUNER_PHILIPS_FM1236_MK3:
                case TUNER_PHILIPS_FM1256_IH3:
                        stereo = ((status & TUNER_SIGNAL) == TUNER_STEREO_MK3);
@@ -295,10 +299,10 @@ static int tuner_stereo(struct i2c_client *c)
 static void default_set_tv_freq(struct i2c_client *c, unsigned int freq)
 {
        struct tuner *t = i2c_get_clientdata(c);
-       u8 config;
+       u8 config, tuneraddr;
        u16 div;
        struct tunertype *tun;
-        unsigned char buffer[4];
+       unsigned char buffer[4];
        int rc;
 
        tun = &tuners[t->type];
@@ -373,6 +377,31 @@ static void default_set_tv_freq(struct i2c_client *c, unsigned int freq)
                /* Set the charge pump for fast tuning */
                tun->config |= TUNER_CHARGE_PUMP;
                break;
+
+       case TUNER_PHILIPS_TUV1236D:
+               /* 0x40 -> ATSC antenna input 1 */
+               /* 0x48 -> ATSC antenna input 2 */
+               /* 0x00 -> NTSC antenna input 1 */
+               /* 0x08 -> NTSC antenna input 2 */
+               buffer[0] = 0x14;
+               buffer[1] = 0x00;
+               buffer[2] = 0x17;
+               buffer[3] = 0x00;
+               config &= ~0x40;
+               if (t->std & V4L2_STD_ATSC) {
+                       config |= 0x40;
+                       buffer[1] = 0x04;
+               }
+               /* set to the correct mode (analog or digital) */
+               tuneraddr = c->addr;
+               c->addr = 0x0a;
+               if (2 != (rc = i2c_master_send(c,&buffer[0],2)))
+                       tuner_warn("i2c i/o error: rc == %d (should be 2)\n",rc);
+               if (2 != (rc = i2c_master_send(c,&buffer[2],2)))
+                       tuner_warn("i2c i/o error: rc == %d (should be 2)\n",rc);
+               c->addr = tuneraddr;
+               /* FIXME: input */
+               break;
        }
 
        /*
@@ -404,7 +433,7 @@ static void default_set_tv_freq(struct i2c_client *c, unsigned int freq)
        tuner_dbg("tv 0x%02x 0x%02x 0x%02x 0x%02x\n",
                  buffer[0],buffer[1],buffer[2],buffer[3]);
 
-        if (4 != (rc = i2c_master_send(c,buffer,4)))
+       if (4 != (rc = i2c_master_send(c,buffer,4)))
                tuner_warn("i2c i/o error: rc == %d (should be 4)\n",rc);
 
        if (t->type == TUNER_MICROTUNE_4042FI5) {
@@ -443,7 +472,7 @@ static void default_set_radio_freq(struct i2c_client *c, unsigned int freq)
 {
        struct tunertype *tun;
        struct tuner *t = i2c_get_clientdata(c);
-        unsigned char buffer[4];
+       unsigned char buffer[4];
        unsigned div;
        int rc;
 
@@ -476,13 +505,13 @@ static void default_set_radio_freq(struct i2c_client *c, unsigned int freq)
                buffer[3] = 0xa4;
                break;
        }
-        buffer[0] = (div>>8) & 0x7f;
-        buffer[1] = div      & 0xff;
+       buffer[0] = (div>>8) & 0x7f;
+       buffer[1] = div      & 0xff;
 
        tuner_dbg("radio 0x%02x 0x%02x 0x%02x 0x%02x\n",
               buffer[0],buffer[1],buffer[2],buffer[3]);
 
-        if (4 != (rc = i2c_master_send(c,buffer,4)))
+       if (4 != (rc = i2c_master_send(c,buffer,4)))
                tuner_warn("i2c i/o error: rc == %d (should be 4)\n",rc);
 }
 
index 1c31ef52f8639450ecae09b635937a9f43bfbd7f..c31bf28b73fe707bb4154639545cc24731a3aa15 100644 (file)
@@ -31,7 +31,6 @@
 #include <linux/smp_lock.h>
 
 #include <media/audiochip.h>
-#include <media/id.h>
 
 #include "tvaudio.h"
 
@@ -458,8 +457,8 @@ static void tda9840_setmode(struct CHIPSTATE *chip, int mode)
 #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 */
+                             * 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) */
 
@@ -1028,7 +1027,7 @@ static int tda9874a_initialize(struct CHIPSTATE *chip)
 #define TEA6300_TR         0x03  /* treble */
 #define TEA6300_FA         0x04  /* fader control */
 #define TEA6300_S          0x05  /* switch register */
-                                 /* values for those registers: */
+                                /* 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 */
@@ -1042,7 +1041,7 @@ static int tda9874a_initialize(struct CHIPSTATE *chip)
 #define TEA6320_BA         0x05  /* bass (0-4) */
 #define TEA6320_TR         0x06  /* treble (0-4) */
 #define TEA6320_S          0x07  /* switch register */
-                                 /* values for those registers: */
+                                /* values for those registers: */
 #define TEA6320_S_SA       0x07  /* stereo A input */
 #define TEA6320_S_SB       0x06  /* stereo B */
 #define TEA6320_S_SC       0x05  /* stereo C */
@@ -1082,7 +1081,7 @@ static int tea6320_initialize(struct CHIPSTATE * chip)
 #define TDA8425_BA         0x02  /* bass */
 #define TDA8425_TR         0x03  /* treble */
 #define TDA8425_S1         0x08  /* switch functions */
-                                 /* values for those registers: */
+                                /* values for those registers: */
 #define TDA8425_S1_OFF     0xEE  /* audio off (mute on) */
 #define TDA8425_S1_CH1     0xCE  /* audio channel 1 (mute off) - "linear stereo" mode */
 #define TDA8425_S1_CH2     0xCF  /* audio channel 2 (mute off) - "linear stereo" mode */
@@ -1148,7 +1147,7 @@ static void tda8425_setmode(struct CHIPSTATE *chip, int mode)
 
 /* bit definition of the RESET register, I2C data. */
 #define PIC16C54_MISC_RESET_REMOTE_CTL 0x01 /* bit 0, Reset to receive the key */
-                                            /*        code of remote controller */
+                                           /*        code of remote controller */
 #define PIC16C54_MISC_MTS_MAIN         0x02 /* bit 1 */
 #define PIC16C54_MISC_MTS_SAP          0x04 /* bit 2 */
 #define PIC16C54_MISC_MTS_BOTH         0x08 /* bit 3 */
@@ -1281,7 +1280,7 @@ static struct CHIPDESC chiplist[] = {
                .setmode    = tda9840_setmode,
                .checkmode  = generic_checkmode,
 
-               .init       = { 2, { TDA9840_TEST, TDA9840_TEST_INT1SN
+               .init       = { 2, { TDA9840_TEST, TDA9840_TEST_INT1SN
                                /* ,TDA9840_SW, TDA9840_MONO */} }
        },
        {
@@ -1438,7 +1437,7 @@ static struct CHIPDESC chiplist[] = {
        },
        {
                .name       = "pic16c54 (PV951)",
-               .id         = I2C_DRIVERID_PIC16C54_PV951,
+               .id         = I2C_DRIVERID_PIC16C54_PV9,
                .insmodopt  = &pic16c54,
                .addr_lo    = I2C_PIC16C54 >> 1,
                .addr_hi    = I2C_PIC16C54>> 1,
@@ -1467,7 +1466,7 @@ static struct CHIPDESC chiplist[] = {
                .setmode    = ta8874z_setmode,
                .checkmode  = generic_checkmode,
 
-               .init       = {2, { TA8874Z_MONO_SET, TA8874Z_SEPARATION_DEFAULT}},
+               .init       = {2, { TA8874Z_MONO_SET, TA8874Z_SEPARATION_DEFAULT}},
        },
        { .name = NULL } /* EOF */
 };
@@ -1486,8 +1485,8 @@ static int chip_attach(struct i2c_adapter *adap, int addr, int kind)
                return -ENOMEM;
        memset(chip,0,sizeof(*chip));
        memcpy(&chip->c,&client_template,sizeof(struct i2c_client));
-        chip->c.adapter = adap;
-        chip->c.addr = addr;
+       chip->c.adapter = adap;
+       chip->c.addr = addr;
        i2c_set_clientdata(&chip->c, chip);
 
        /* find description for the chip */
index 5344d5592199356a5f0601991134e2d455c870a7..72e8741e8b595e2d4817b056ff1c87c21ab7c158 100644 (file)
@@ -6,12 +6,12 @@
  * which are:
 
     Copyright (C) 1996,97,98 Ralph  Metzler (rjkm@thp.uni-koeln.de)
-                           & Marcus Metzler (mocm@thp.uni-koeln.de)
+                          & Marcus Metzler (mocm@thp.uni-koeln.de)
     (c) 1999-2001 Gerd Knorr <kraxel@goldbach.in-berlin.de>
 
  * Adjustments to fit a more general model and all bugs:
 
-       Copyright (C) 2003 John Klar <linpvr at projectplasma.com>
+       Copyright (C) 2003 John Klar <linpvr at projectplasma.com>
 
  * 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
@@ -40,6 +40,7 @@
 
 #include <media/tuner.h>
 #include <media/tveeprom.h>
+#include <media/audiochip.h>
 
 MODULE_DESCRIPTION("i2c Hauppauge eeprom decoder driver");
 MODULE_AUTHOR("John Klar");
@@ -53,14 +54,14 @@ MODULE_PARM_DESC(debug, "Debug level (0-1)");
 
 #define tveeprom_info(fmt, arg...) do {\
        printk(KERN_INFO "tveeprom %d-%04x: " fmt, \
-                        c->adapter->nr, c->addr , ##arg); } while (0)
+                       c->adapter->nr, c->addr , ##arg); } while (0)
 #define tveeprom_warn(fmt, arg...) do {\
        printk(KERN_WARNING "tveeprom %d-%04x: " fmt, \
-                        c->adapter->nr, c->addr , ##arg); } while (0)
+                       c->adapter->nr, c->addr , ##arg); } while (0)
 #define tveeprom_dbg(fmt, arg...) do {\
        if (debug) \
-                printk(KERN_INFO "tveeprom %d-%04x: " fmt, \
-                        c->adapter->nr, c->addr , ##arg); } while (0)
+               printk(KERN_INFO "tveeprom %d-%04x: " fmt, \
+                       c->adapter->nr, c->addr , ##arg); } while (0)
 
 
 /* ----------------------------------------------------------------------- */
@@ -134,8 +135,8 @@ hauppauge_tuner[] =
        { TUNER_TEMIC_4039FR5_NTSC, "Temic 4039FR5" },
        { TUNER_PHILIPS_FQ1216ME,   "Philips FQ1216 ME" },
        { TUNER_TEMIC_4066FY5_PAL_I, "Temic 4066FY5" },
-        { TUNER_PHILIPS_NTSC,        "Philips TD1536" },
-        { TUNER_PHILIPS_NTSC,        "Philips TD1536D" },
+       { TUNER_PHILIPS_NTSC,        "Philips TD1536" },
+       { TUNER_PHILIPS_NTSC,        "Philips TD1536D" },
        { TUNER_PHILIPS_NTSC,  "Philips FMR1236" }, /* mono radio */
        { TUNER_ABSENT,        "Philips FI1256MP" },
        /* 40-49 */
@@ -189,7 +190,7 @@ hauppauge_tuner[] =
        { TUNER_LG_PAL_NEW_TAPC, "TCL 2002MB 3"},
        { TUNER_LG_PAL_NEW_TAPC, "TCL 2002MI 3"},
        { TUNER_TCL_2002N,     "TCL 2002N 6A"},
-       { TUNER_ABSENT,        "Philips FQ1236 MK3"},
+       { TUNER_PHILIPS_FM1236_MK3, "Philips FQ1236 MK3"},
        { TUNER_ABSENT,        "Samsung TCPN 2121P30A"},
        { TUNER_ABSENT,        "Samsung TCPE 4121P30A"},
        { TUNER_PHILIPS_FM1216ME_MK3, "TCL MFPE05 2"},
@@ -200,95 +201,137 @@ hauppauge_tuner[] =
        { TUNER_ABSENT,        "Philips FQ1286A MK4"},
        { TUNER_ABSENT,        "Philips FQ1216ME MK5"},
        { TUNER_ABSENT,        "Philips FQ1236 MK5"},
-       { TUNER_ABSENT,        "Unspecified"},
-       { TUNER_LG_PAL_TAPE,   "LG PAL (TAPE Series)"},
-        { TUNER_ABSENT,        "Unspecified"},
-        { TUNER_TCL_2002N,     "TCL 2002N 5H"},
-       /* 100-103 */
-       { TUNER_ABSENT,        "Unspecified"},
-        { TUNER_TEA5767,       "Philips TEA5767HN FM Radio"},
-        { TUNER_ABSENT,        "Unspecified"},
-        { TUNER_PHILIPS_FM1236_MK3, "TCL MFNM05 4"},
+       { TUNER_ABSENT,        "Samsung TCPG_6121P30A"},
+       { TUNER_TCL_2002MB,    "TCL 2002MB_3H"},
+       { TUNER_ABSENT,        "TCL 2002MI_3H"},
+       { TUNER_TCL_2002N,     "TCL 2002N 5H"},
+       /* 100-109 */
+       { TUNER_ABSENT,        "Philips FMD1216ME"},
+       { TUNER_TEA5767,       "Philips TEA5768HL FM Radio"},
+       { TUNER_ABSENT,        "Panasonic ENV57H12D5"},
+       { TUNER_ABSENT,        "TCL MFNM05-4"},
+       { TUNER_ABSENT,        "TCL MNM05-4"},
+       { TUNER_PHILIPS_FM1216ME_MK3, "TCL MPE05-2"},
+       { TUNER_ABSENT,        "TCL MQNM05-4"},
+       { TUNER_ABSENT,        "LG TAPC-W701D"},
+       { TUNER_ABSENT,        "TCL 9886P-WM"},
+       { TUNER_ABSENT,        "TCL 1676NM-WM"},
 };
 
-/* This list is supplied by Hauppauge. Thanks! */
-static const char *audioIC[] = {
-        /* 0-4 */
-        "None", "TEA6300", "TEA6320", "TDA9850", "MSP3400C",
-        /* 5-9 */
-        "MSP3410D", "MSP3415", "MSP3430", "MSP3438", "CS5331",
-        /* 10-14 */
-        "MSP3435", "MSP3440", "MSP3445", "MSP3411", "MSP3416",
-        /* 15-19 */
-        "MSP3425", "MSP3451", "MSP3418", "Type 0x12", "OKI7716",
-        /* 20-24 */
-        "MSP4410", "MSP4420", "MSP4440", "MSP4450", "MSP4408",
-        /* 25-29 */
-        "MSP4418", "MSP4428", "MSP4448", "MSP4458", "Type 0x1d",
-        /* 30-34 */
-        "CX880", "CX881", "CX883", "CX882", "CX25840",
-        /* 35-38 */
-        "CX25841", "CX25842", "CX25843", "CX23418",
+static struct HAUPPAUGE_AUDIOIC
+{
+       enum audiochip  id;
+       char *name;
+}
+audioIC[] =
+{
+       /* 0-4 */
+       {AUDIO_CHIP_NONE,     "None"},
+       {AUDIO_CHIP_TEA6300,  "TEA6300"},
+       {AUDIO_CHIP_TEA6300,  "TEA6320"},
+       {AUDIO_CHIP_TDA985X,  "TDA9850"},
+       {AUDIO_CHIP_MSP34XX,  "MSP3400C"},
+       /* 5-9 */
+       {AUDIO_CHIP_MSP34XX,  "MSP3410D"},
+       {AUDIO_CHIP_MSP34XX,  "MSP3415"},
+       {AUDIO_CHIP_MSP34XX,  "MSP3430"},
+       {AUDIO_CHIP_UNKNOWN,  "MSP3438"},
+       {AUDIO_CHIP_UNKNOWN,  "CS5331"},
+       /* 10-14 */
+       {AUDIO_CHIP_MSP34XX,  "MSP3435"},
+       {AUDIO_CHIP_MSP34XX,  "MSP3440"},
+       {AUDIO_CHIP_MSP34XX,  "MSP3445"},
+       {AUDIO_CHIP_UNKNOWN,  "MSP3411"},
+       {AUDIO_CHIP_UNKNOWN,  "MSP3416"},
+       /* 15-19 */
+       {AUDIO_CHIP_MSP34XX,  "MSP3425"},
+       {AUDIO_CHIP_UNKNOWN,  "MSP3451"},
+       {AUDIO_CHIP_UNKNOWN,  "MSP3418"},
+       {AUDIO_CHIP_UNKNOWN,  "Type 0x12"},
+       {AUDIO_CHIP_UNKNOWN,  "OKI7716"},
+       /* 20-24 */
+       {AUDIO_CHIP_UNKNOWN,  "MSP4410"},
+       {AUDIO_CHIP_UNKNOWN,  "MSP4420"},
+       {AUDIO_CHIP_UNKNOWN,  "MSP4440"},
+       {AUDIO_CHIP_UNKNOWN,  "MSP4450"},
+       {AUDIO_CHIP_UNKNOWN,  "MSP4408"},
+       /* 25-29 */
+       {AUDIO_CHIP_UNKNOWN,  "MSP4418"},
+       {AUDIO_CHIP_UNKNOWN,  "MSP4428"},
+       {AUDIO_CHIP_UNKNOWN,  "MSP4448"},
+       {AUDIO_CHIP_UNKNOWN,  "MSP4458"},
+       {AUDIO_CHIP_UNKNOWN,  "Type 0x1d"},
+       /* 30-34 */
+       {AUDIO_CHIP_INTERNAL, "CX880"},
+       {AUDIO_CHIP_INTERNAL, "CX881"},
+       {AUDIO_CHIP_INTERNAL, "CX883"},
+       {AUDIO_CHIP_INTERNAL, "CX882"},
+       {AUDIO_CHIP_INTERNAL, "CX25840"},
+       /* 35-38 */
+       {AUDIO_CHIP_INTERNAL, "CX25841"},
+       {AUDIO_CHIP_INTERNAL, "CX25842"},
+       {AUDIO_CHIP_INTERNAL, "CX25843"},
+       {AUDIO_CHIP_INTERNAL, "CX23418"},
 };
 
 /* This list is supplied by Hauppauge. Thanks! */
 static const char *decoderIC[] = {
-        /* 0-4 */
-        "None", "BT815", "BT817", "BT819", "BT815A",
-        /* 5-9 */
-        "BT817A", "BT819A", "BT827", "BT829", "BT848",
-        /* 10-14 */
-        "BT848A", "BT849A", "BT829A", "BT827A", "BT878",
-        /* 15-19 */
-        "BT879", "BT880", "VPX3226E", "SAA7114", "SAA7115",
-        /* 20-24 */
-        "CX880", "CX881", "CX883", "SAA7111", "SAA7113",
-        /* 25-29 */
-        "CX882", "TVP5150A", "CX25840", "CX25841", "CX25842",
-        /* 30-31 */
-        "CX25843", "CX23418",
+       /* 0-4 */
+       "None", "BT815", "BT817", "BT819", "BT815A",
+       /* 5-9 */
+       "BT817A", "BT819A", "BT827", "BT829", "BT848",
+       /* 10-14 */
+       "BT848A", "BT849A", "BT829A", "BT827A", "BT878",
+       /* 15-19 */
+       "BT879", "BT880", "VPX3226E", "SAA7114", "SAA7115",
+       /* 20-24 */
+       "CX880", "CX881", "CX883", "SAA7111", "SAA7113",
+       /* 25-29 */
+       "CX882", "TVP5150A", "CX25840", "CX25841", "CX25842",
+       /* 30-31 */
+       "CX25843", "CX23418",
 };
 
 static int hasRadioTuner(int tunerType)
 {
-        switch (tunerType) {
-                case 18: //PNPEnv_TUNER_FR1236_MK2:
-                case 23: //PNPEnv_TUNER_FM1236:
-                case 38: //PNPEnv_TUNER_FMR1236:
-                case 16: //PNPEnv_TUNER_FR1216_MK2:
-                case 19: //PNPEnv_TUNER_FR1246_MK2:
-                case 21: //PNPEnv_TUNER_FM1216:
-                case 24: //PNPEnv_TUNER_FM1246:
-                case 17: //PNPEnv_TUNER_FR1216MF_MK2:
-                case 22: //PNPEnv_TUNER_FM1216MF:
-                case 20: //PNPEnv_TUNER_FR1256_MK2:
-                case 25: //PNPEnv_TUNER_FM1256:
-                case 33: //PNPEnv_TUNER_4039FR5:
-                case 42: //PNPEnv_TUNER_4009FR5:
-                case 52: //PNPEnv_TUNER_4049FM5:
-                case 54: //PNPEnv_TUNER_4049FM5_AltI2C:
-                case 44: //PNPEnv_TUNER_4009FN5:
-                case 31: //PNPEnv_TUNER_TCPB9085P:
-                case 30: //PNPEnv_TUNER_TCPN9085D:
-                case 46: //PNPEnv_TUNER_TP18NSR01F:
-                case 47: //PNPEnv_TUNER_TP18PSB01D:
-                case 49: //PNPEnv_TUNER_TAPC_I001D:
-                case 60: //PNPEnv_TUNER_TAPE_S001D_MK3:
-                case 57: //PNPEnv_TUNER_FM1216ME_MK3:
-                case 59: //PNPEnv_TUNER_FM1216MP_MK3:
-                case 58: //PNPEnv_TUNER_FM1236_MK3:
-                case 68: //PNPEnv_TUNER_TAPE_H001F_MK3:
-                case 61: //PNPEnv_TUNER_TAPE_M001D_MK3:
-                case 78: //PNPEnv_TUNER_TDA8275C1_8290_FM:
-                case 89: //PNPEnv_TUNER_TCL_MFPE05_2:
-                case 92: //PNPEnv_TUNER_PHILIPS_FQ1236A_MK4:
-                    return 1;
-        }
-        return 0;
+       switch (tunerType) {
+               case 18: //PNPEnv_TUNER_FR1236_MK2:
+               case 23: //PNPEnv_TUNER_FM1236:
+               case 38: //PNPEnv_TUNER_FMR1236:
+               case 16: //PNPEnv_TUNER_FR1216_MK2:
+               case 19: //PNPEnv_TUNER_FR1246_MK2:
+               case 21: //PNPEnv_TUNER_FM1216:
+               case 24: //PNPEnv_TUNER_FM1246:
+               case 17: //PNPEnv_TUNER_FR1216MF_MK2:
+               case 22: //PNPEnv_TUNER_FM1216MF:
+               case 20: //PNPEnv_TUNER_FR1256_MK2:
+               case 25: //PNPEnv_TUNER_FM1256:
+               case 33: //PNPEnv_TUNER_4039FR5:
+               case 42: //PNPEnv_TUNER_4009FR5:
+               case 52: //PNPEnv_TUNER_4049FM5:
+               case 54: //PNPEnv_TUNER_4049FM5_AltI2C:
+               case 44: //PNPEnv_TUNER_4009FN5:
+               case 31: //PNPEnv_TUNER_TCPB9085P:
+               case 30: //PNPEnv_TUNER_TCPN9085D:
+               case 46: //PNPEnv_TUNER_TP18NSR01F:
+               case 47: //PNPEnv_TUNER_TP18PSB01D:
+               case 49: //PNPEnv_TUNER_TAPC_I001D:
+               case 60: //PNPEnv_TUNER_TAPE_S001D_MK3:
+               case 57: //PNPEnv_TUNER_FM1216ME_MK3:
+               case 59: //PNPEnv_TUNER_FM1216MP_MK3:
+               case 58: //PNPEnv_TUNER_FM1236_MK3:
+               case 68: //PNPEnv_TUNER_TAPE_H001F_MK3:
+               case 61: //PNPEnv_TUNER_TAPE_M001D_MK3:
+               case 78: //PNPEnv_TUNER_TDA8275C1_8290_FM:
+               case 89: //PNPEnv_TUNER_TCL_MFPE05_2:
+               case 92: //PNPEnv_TUNER_PHILIPS_FQ1236A_MK4:
+               return 1;
+       }
+       return 0;
 }
 
 void tveeprom_hauppauge_analog(struct i2c_client *c, struct tveeprom *tvee,
-                                unsigned char *eeprom_data)
+                               unsigned char *eeprom_data)
 {
        /* ----------------------------------------------
        ** The hauppauge eeprom format is tagged
@@ -312,19 +355,27 @@ void tveeprom_hauppauge_analog(struct i2c_client *c, struct tveeprom *tvee,
        ** # of inputs/outputs ???
        */
 
-       int i, j, len, done, beenhere, tag;
+       int i, j, len, done, beenhere, tag,start;
 
-        int tuner1 = 0, t_format1 = 0;
+       int tuner1 = 0, t_format1 = 0, audioic=-1;
        char *t_name1 = NULL;
-        const char *t_fmt_name1[8] = { " none", "", "", "", "", "", "", "" };
+       const char *t_fmt_name1[8] = { " none", "", "", "", "", "", "", "" };
 
-        int tuner2 = 0, t_format2 = 0;
+       int tuner2 = 0, t_format2 = 0;
        char *t_name2 = NULL;
-        const char *t_fmt_name2[8] = { " none", "", "", "", "", "", "", "" };
+       const char *t_fmt_name2[8] = { " none", "", "", "", "", "", "", "" };
 
-        memset(tvee, 0, sizeof(*tvee));
+       memset(tvee, 0, sizeof(*tvee));
        done = len = beenhere = 0;
-       for (i = 0; !done && i < 256; i += len) {
+
+       /* Hack for processing eeprom for em28xx */
+       if ((eeprom_data[0]==0x1a)&&(eeprom_data[1]==0xeb)&&
+                               (eeprom_data[2]==0x67)&&(eeprom_data[3]==0x95))
+               start=0xa0;
+       else
+               start=0;
+
+       for (i = start; !done && i < 256; i += len) {
                if (eeprom_data[i] == 0x84) {
                        len = eeprom_data[i + 1] + (eeprom_data[i + 2] << 8);
                        i += 3;
@@ -338,28 +389,28 @@ void tveeprom_hauppauge_analog(struct i2c_client *c, struct tveeprom *tvee,
                        ++i;
                } else {
                        tveeprom_warn("Encountered bad packet header [%02x]. "
-                                  "Corrupt or not a Hauppauge eeprom.\n", eeprom_data[i]);
+                               "Corrupt or not a Hauppauge eeprom.\n", eeprom_data[i]);
                        return;
                }
 
-                if (debug) {
-                        tveeprom_info("Tag [%02x] + %d bytes:", eeprom_data[i], len - 1);
-                        for(j = 1; j < len; j++) {
-                                printk(" %02x", eeprom_data[i + j]);
-                        }
-                        printk("\n");
-                }
+               if (debug) {
+                       tveeprom_info("Tag [%02x] + %d bytes:", eeprom_data[i], len - 1);
+                       for(j = 1; j < len; j++) {
+                               printk(" %02x", eeprom_data[i + j]);
+                       }
+                       printk("\n");
+               }
 
                /* process by tag */
                tag = eeprom_data[i];
                switch (tag) {
                case 0x00:
-                        /* tag: 'Comprehensive' */
+                       /* tag: 'Comprehensive' */
                        tuner1 = eeprom_data[i+6];
                        t_format1 = eeprom_data[i+5];
                        tvee->has_radio = eeprom_data[i+len-1];
-                        /* old style tag, don't know how to detect
-                           IR presence, mark as unknown. */
+                       /* old style tag, don't know how to detect
+                       IR presence, mark as unknown. */
                        tvee->has_ir = 2;
                        tvee->model =
                                eeprom_data[i+8] +
@@ -370,7 +421,7 @@ void tveeprom_hauppauge_analog(struct i2c_client *c, struct tveeprom *tvee,
                        break;
 
                case 0x01:
-                        /* tag: 'SerialID' */
+                       /* tag: 'SerialID' */
                        tvee->serial_number =
                                eeprom_data[i+6] +
                                (eeprom_data[i+7] << 8) +
@@ -378,17 +429,21 @@ void tveeprom_hauppauge_analog(struct i2c_client *c, struct tveeprom *tvee,
                        break;
 
                case 0x02:
-                        /* tag 'AudioInfo'
-                           Note mask with 0x7F, high bit used on some older models
-                           to indicate 4052 mux was removed in favor of using MSP
-                           inputs directly. */
-                       tvee->audio_processor = eeprom_data[i+2] & 0x7f;
+                       /* tag 'AudioInfo'
+                       Note mask with 0x7F, high bit used on some older models
+                       to indicate 4052 mux was removed in favor of using MSP
+                       inputs directly. */
+                       audioic = eeprom_data[i+2] & 0x7f;
+                       if (audioic < sizeof(audioIC)/sizeof(*audioIC))
+                               tvee->audio_processor = audioIC[audioic].id;
+                       else
+                               tvee->audio_processor = AUDIO_CHIP_UNKNOWN;
                        break;
 
-                /* case 0x03: tag 'EEInfo' */
+               /* case 0x03: tag 'EEInfo' */
 
                case 0x04:
-                        /* tag 'SerialID2' */
+                       /* tag 'SerialID2' */
                        tvee->serial_number =
                                eeprom_data[i+5] +
                                (eeprom_data[i+6] << 8) +
@@ -396,15 +451,20 @@ void tveeprom_hauppauge_analog(struct i2c_client *c, struct tveeprom *tvee,
                        break;
 
                case 0x05:
-                        /* tag 'Audio2'
-                           Note mask with 0x7F, high bit used on some older models
-                           to indicate 4052 mux was removed in favor of using MSP
-                           inputs directly. */
-                       tvee->audio_processor = eeprom_data[i+1] & 0x7f;
+                       /* tag 'Audio2'
+                       Note mask with 0x7F, high bit used on some older models
+                       to indicate 4052 mux was removed in favor of using MSP
+                       inputs directly. */
+                       audioic = eeprom_data[i+1] & 0x7f;
+                       if (audioic < sizeof(audioIC)/sizeof(*audioIC))
+                               tvee->audio_processor = audioIC[audioic].id;
+                       else
+                               tvee->audio_processor = AUDIO_CHIP_UNKNOWN;
+
                        break;
 
                case 0x06:
-                        /* tag 'ModelRev' */
+                       /* tag 'ModelRev' */
                        tvee->model =
                                eeprom_data[i+1] +
                                (eeprom_data[i+2] << 8);
@@ -414,55 +474,55 @@ void tveeprom_hauppauge_analog(struct i2c_client *c, struct tveeprom *tvee,
                        break;
 
                case 0x07:
-                        /* tag 'Details': according to Hauppauge not interesting
-                           on any PCI-era or later boards. */
+                       /* tag 'Details': according to Hauppauge not interesting
+                       on any PCI-era or later boards. */
                        break;
 
-                /* there is no tag 0x08 defined */
+               /* there is no tag 0x08 defined */
 
                case 0x09:
-                        /* tag 'Video' */
+                       /* tag 'Video' */
                        tvee->decoder_processor = eeprom_data[i + 1];
                        break;
 
                case 0x0a:
-                        /* tag 'Tuner' */
+                       /* tag 'Tuner' */
                        if (beenhere == 0) {
                                tuner1 = eeprom_data[i+2];
                                t_format1 = eeprom_data[i+1];
                                beenhere = 1;
                        } else {
-                                /* a second (radio) tuner may be present */
+                               /* a second (radio) tuner may be present */
                                tuner2 = eeprom_data[i+2];
                                t_format2 = eeprom_data[i+1];
-                                if (t_format2 == 0) {  /* not a TV tuner? */
-                                        tvee->has_radio = 1; /* must be radio */
-                                }
-                        }
+                               if (t_format2 == 0) {  /* not a TV tuner? */
+                                       tvee->has_radio = 1; /* must be radio */
+                               }
+                       }
                        break;
 
-                case 0x0b:
-                        /* tag 'Inputs': according to Hauppauge this is specific
-                           to each driver family, so no good assumptions can be
-                           made. */
-                        break;
+               case 0x0b:
+                       /* tag 'Inputs': according to Hauppauge this is specific
+                       to each driver family, so no good assumptions can be
+                       made. */
+                       break;
 
-                /* case 0x0c: tag 'Balun' */
-                /* case 0x0d: tag 'Teletext' */
+               /* case 0x0c: tag 'Balun' */
+               /* case 0x0d: tag 'Teletext' */
 
                case 0x0e:
-                        /* tag: 'Radio' */
+                       /* tag: 'Radio' */
                        tvee->has_radio = eeprom_data[i+1];
                        break;
 
-                case 0x0f:
-                        /* tag 'IRInfo' */
-                        tvee->has_ir = eeprom_data[i+1];
-                        break;
+               case 0x0f:
+                       /* tag 'IRInfo' */
+                       tvee->has_ir = eeprom_data[i+1];
+                       break;
 
-                /* case 0x10: tag 'VBIInfo' */
-                /* case 0x11: tag 'QCInfo' */
-                /* case 0x12: tag 'InfoBits' */
+               /* case 0x10: tag 'VBIInfo' */
+               /* case 0x11: tag 'QCInfo' */
+               /* case 0x12: tag 'InfoBits' */
 
                default:
                        tveeprom_dbg("Not sure what to do with tag [%02x]\n", tag);
@@ -483,11 +543,11 @@ void tveeprom_hauppauge_analog(struct i2c_client *c, struct tveeprom *tvee,
                tvee->rev_str[4] = 0;
        }
 
-        if (hasRadioTuner(tuner1) && !tvee->has_radio) {
-           tveeprom_info("The eeprom says no radio is present, but the tuner type\n");
-           tveeprom_info("indicates otherwise. I will assume that radio is present.\n");
-            tvee->has_radio = 1;
-        }
+       if (hasRadioTuner(tuner1) && !tvee->has_radio) {
+               tveeprom_info("The eeprom says no radio is present, but the tuner type\n");
+               tveeprom_info("indicates otherwise. I will assume that radio is present.\n");
+               tvee->has_radio = 1;
+       }
 
        if (tuner1 < sizeof(hauppauge_tuner)/sizeof(struct HAUPPAUGE_TUNER)) {
                tvee->tuner_type = hauppauge_tuner[tuner1].id;
@@ -510,45 +570,53 @@ void tveeprom_hauppauge_analog(struct i2c_client *c, struct tveeprom *tvee,
                        tvee->tuner_formats |= hauppauge_tuner_fmt[i].id;
                        t_fmt_name1[j++] = hauppauge_tuner_fmt[i].name;
                }
-                if (t_format2 & (1 << i)) {
-                        tvee->tuner2_formats |= hauppauge_tuner_fmt[i].id;
-                        t_fmt_name2[j++] = hauppauge_tuner_fmt[i].name;
-                }
+               if (t_format2 & (1 << i)) {
+                       tvee->tuner2_formats |= hauppauge_tuner_fmt[i].id;
+                       t_fmt_name2[j++] = hauppauge_tuner_fmt[i].name;
+               }
        }
 
        tveeprom_info("Hauppauge model %d, rev %s, serial# %d\n",
-                  tvee->model, tvee->rev_str, tvee->serial_number);
+               tvee->model, tvee->rev_str, tvee->serial_number);
        tveeprom_info("tuner model is %s (idx %d, type %d)\n",
-                  t_name1, tuner1, tvee->tuner_type);
+               t_name1, tuner1, tvee->tuner_type);
        tveeprom_info("TV standards%s%s%s%s%s%s%s%s (eeprom 0x%02x)\n",
-                  t_fmt_name1[0], t_fmt_name1[1], t_fmt_name1[2], t_fmt_name1[3],
-                  t_fmt_name1[4], t_fmt_name1[5], t_fmt_name1[6], t_fmt_name1[7],
-                   t_format1);
-        if (tuner2) {
-                tveeprom_info("second tuner model is %s (idx %d, type %d)\n",
-                           t_name2, tuner2, tvee->tuner2_type);
-        }
-        if (t_format2) {
-                tveeprom_info("TV standards%s%s%s%s%s%s%s%s (eeprom 0x%02x)\n",
-                           t_fmt_name2[0], t_fmt_name2[1], t_fmt_name2[2], t_fmt_name2[3],
-                           t_fmt_name2[4], t_fmt_name2[5], t_fmt_name2[6], t_fmt_name2[7],
-                           t_format2);
-        }
-       tveeprom_info("audio processor is %s (idx %d)\n",
-                  STRM(audioIC, tvee->audio_processor),
-                  tvee->audio_processor);
-        if (tvee->decoder_processor) {
-                tveeprom_info("decoder processor is %s (idx %d)\n",
-                           STRM(decoderIC, tvee->decoder_processor),
-                           tvee->decoder_processor);
-        }
-        if (tvee->has_ir == 2)
-                tveeprom_info("has %sradio\n",
-                                tvee->has_radio ? "" : "no ");
-        else
-                tveeprom_info("has %sradio, has %sIR remote\n",
-                                tvee->has_radio ? "" : "no ",
-                                tvee->has_ir ? "" : "no ");
+               t_fmt_name1[0], t_fmt_name1[1], t_fmt_name1[2], t_fmt_name1[3],
+               t_fmt_name1[4], t_fmt_name1[5], t_fmt_name1[6], t_fmt_name1[7],
+               t_format1);
+       if (tuner2) {
+               tveeprom_info("second tuner model is %s (idx %d, type %d)\n",
+                                       t_name2, tuner2, tvee->tuner2_type);
+       }
+       if (t_format2) {
+               tveeprom_info("TV standards%s%s%s%s%s%s%s%s (eeprom 0x%02x)\n",
+                       t_fmt_name2[0], t_fmt_name2[1], t_fmt_name2[2], t_fmt_name2[3],
+                       t_fmt_name2[4], t_fmt_name2[5], t_fmt_name2[6], t_fmt_name2[7],
+                       t_format2);
+       }
+       if (audioic<0) {
+               tveeprom_info("audio processor is unknown (no idx)\n");
+               tvee->audio_processor=AUDIO_CHIP_UNKNOWN;
+       } else {
+               if (audioic < sizeof(audioIC)/sizeof(*audioIC))
+                       tveeprom_info("audio processor is %s (idx %d)\n",
+                                       audioIC[audioic].name,audioic);
+               else
+                       tveeprom_info("audio processor is unknown (idx %d)\n",
+                                                               audioic);
+       }
+       if (tvee->decoder_processor) {
+               tveeprom_info("decoder processor is %s (idx %d)\n",
+                       STRM(decoderIC, tvee->decoder_processor),
+                       tvee->decoder_processor);
+       }
+       if (tvee->has_ir == 2)
+               tveeprom_info("has %sradio\n",
+                               tvee->has_radio ? "" : "no ");
+       else
+               tveeprom_info("has %sradio, has %sIR remote\n",
+                               tvee->has_radio ? "" : "no ",
+                               tvee->has_ir ? "" : "no ");
 }
 EXPORT_SYMBOL(tveeprom_hauppauge_analog);
 
@@ -569,18 +637,18 @@ int tveeprom_read(struct i2c_client *c, unsigned char *eedata, int len)
                tveeprom_warn("i2c eeprom read error (err=%d)\n", err);
                return -1;
        }
-        if (debug) {
-                int i;
-
-                tveeprom_info("full 256-byte eeprom dump:\n");
-                for (i = 0; i < len; i++) {
-                        if (0 == (i % 16))
-                                tveeprom_info("%02x:", i);
-                        printk(" %02x", eedata[i]);
-                        if (15 == (i % 16))
-                                printk("\n");
-                }
-        }
+       if (debug) {
+               int i;
+
+               tveeprom_info("full 256-byte eeprom dump:\n");
+               for (i = 0; i < len; i++) {
+                       if (0 == (i % 16))
+                               tveeprom_info("%02x:", i);
+                       printk(" %02x", eedata[i]);
+                       if (15 == (i % 16))
+                               printk("\n");
+               }
+       }
        return 0;
 }
 EXPORT_SYMBOL(tveeprom_read);
@@ -590,10 +658,6 @@ EXPORT_SYMBOL(tveeprom_read);
 /* run, just call the exported tveeprom_* directly, there is no point in   */
 /* using the indirect way via i2c_driver->command()                        */
 
-#ifndef I2C_DRIVERID_TVEEPROM
-# define I2C_DRIVERID_TVEEPROM I2C_DRIVERID_EXP2
-#endif
-
 static unsigned short normal_i2c[] = {
        0xa0 >> 1,
        I2C_CLIENT_END,
index d86e08ebddfc253506389050d3ef468dcbf3d532..8318bd1aad000450713fd30bf8200a222516b12f 100644 (file)
@@ -79,7 +79,7 @@ static int tvmixer_ioctl(struct inode *inode, struct file *file, unsigned int cm
 {
        struct video_audio va;
        int left,right,ret,val = 0;
-        struct TVMIXER *mix = file->private_data;
+       struct TVMIXER *mix = file->private_data;
        struct i2c_client *client = mix->dev;
        void __user *argp = (void __user *)arg;
        int __user *p = argp;
@@ -87,25 +87,25 @@ static int tvmixer_ioctl(struct inode *inode, struct file *file, unsigned int cm
        if (NULL == client)
                return -ENODEV;
 
-        if (cmd == SOUND_MIXER_INFO) {
-                mixer_info info;
-                strlcpy(info.id, "tv card", sizeof(info.id));
-                strlcpy(info.name, client->name, sizeof(info.name));
-                info.modify_counter = 42 /* FIXME */;
-                if (copy_to_user(argp, &info, sizeof(info)))
-                        return -EFAULT;
-                return 0;
-        }
-        if (cmd == SOUND_OLD_MIXER_INFO) {
-                _old_mixer_info info;
-                strlcpy(info.id, "tv card", sizeof(info.id));
-                strlcpy(info.name, client->name, sizeof(info.name));
-                if (copy_to_user(argp, &info, sizeof(info)))
-                        return -EFAULT;
-                return 0;
-        }
-        if (cmd == OSS_GETVERSION)
-                return put_user(SOUND_VERSION, p);
+       if (cmd == SOUND_MIXER_INFO) {
+               mixer_info info;
+               strlcpy(info.id, "tv card", sizeof(info.id));
+               strlcpy(info.name, client->name, sizeof(info.name));
+               info.modify_counter = 42 /* FIXME */;
+               if (copy_to_user(argp, &info, sizeof(info)))
+                       return -EFAULT;
+               return 0;
+       }
+       if (cmd == SOUND_OLD_MIXER_INFO) {
+               _old_mixer_info info;
+               strlcpy(info.id, "tv card", sizeof(info.id));
+               strlcpy(info.name, client->name, sizeof(info.name));
+               if (copy_to_user(argp, &info, sizeof(info)))
+                       return -EFAULT;
+               return 0;
+       }
+       if (cmd == OSS_GETVERSION)
+               return put_user(SOUND_VERSION, p);
 
        if (_SIOC_DIR(cmd) & _SIOC_WRITE)
                if (get_user(val, p))
@@ -181,8 +181,8 @@ static int tvmixer_ioctl(struct inode *inode, struct file *file, unsigned int cm
 
 static int tvmixer_open(struct inode *inode, struct file *file)
 {
-        int i, minor = iminor(inode);
-        struct TVMIXER *mix = NULL;
+       int i, minor = iminor(inode);
+       struct TVMIXER *mix = NULL;
        struct i2c_client *client = NULL;
 
        for (i = 0; i < DEV_MAX; i++) {
@@ -204,7 +204,7 @@ static int tvmixer_open(struct inode *inode, struct file *file)
 #endif
        if (client->adapter->owner)
                try_module_get(client->adapter->owner);
-        return 0;
+       return 0;
 }
 
 static int tvmixer_release(struct inode *inode, struct file *file)
@@ -231,15 +231,15 @@ static struct i2c_driver driver = {
        .owner           = THIS_MODULE,
 #endif
        .name            = "tv card mixer driver",
-        .id              = I2C_DRIVERID_TVMIXER,
+       .id              = I2C_DRIVERID_TVMIXER,
 #ifdef I2C_DF_DUMMY
        .flags           = I2C_DF_DUMMY,
 #else
        .flags           = I2C_DF_NOTIFY,
-        .detach_adapter  = tvmixer_adapters,
+       .detach_adapter  = tvmixer_adapters,
 #endif
-        .attach_adapter  = tvmixer_adapters,
-        .detach_client   = tvmixer_clients,
+       .attach_adapter  = tvmixer_adapters,
+       .detach_client   = tvmixer_clients,
 };
 
 static struct file_operations tvmixer_fops = {
diff --git a/drivers/media/video/tvp5150.c b/drivers/media/video/tvp5150.c
new file mode 100644 (file)
index 0000000..81e6d44
--- /dev/null
@@ -0,0 +1,829 @@
+/*
+ * tvp5150 - Texas Instruments TVP5150A(M) video decoder driver
+ *
+ * Copyright (c) 2005 Mauro Carvalho Chehab (mchehab@brturbo.com.br)
+ * This code is placed under the terms of the GNU General Public License
+ */
+
+#include <linux/i2c.h>
+#include <linux/videodev.h>
+#include <linux/delay.h>
+#include <linux/video_decoder.h>
+
+#include "tvp5150_reg.h"
+
+MODULE_DESCRIPTION("Texas Instruments TVP5150A video decoder driver"); /* standard i2c insmod options */
+MODULE_AUTHOR("Mauro Carvalho Chehab");
+MODULE_LICENSE("GPL");
+
+static unsigned short normal_i2c[] = {
+       0xb8 >> 1,
+       0xba >> 1,
+       I2C_CLIENT_END
+};
+
+I2C_CLIENT_INSMOD;
+
+static int debug = 0;
+module_param(debug, int, 0);
+MODULE_PARM_DESC(debug, "Debug level (0-1)");
+
+#define dprintk(num, format, args...) \
+       do { \
+               if (debug >= num) \
+                       printk(format , ##args); \
+       } while (0)
+
+/* supported controls */
+static struct v4l2_queryctrl tvp5150_qctrl[] = {
+       {
+        .id = V4L2_CID_BRIGHTNESS,
+        .type = V4L2_CTRL_TYPE_INTEGER,
+        .name = "Brightness",
+        .minimum = 0,
+        .maximum = 255,
+        .step = 1,
+        .default_value = 0,
+        .flags = 0,
+        }, {
+            .id = V4L2_CID_CONTRAST,
+            .type = V4L2_CTRL_TYPE_INTEGER,
+            .name = "Contrast",
+            .minimum = 0,
+            .maximum = 255,
+            .step = 0x1,
+            .default_value = 0x10,
+            .flags = 0,
+            }, {
+                .id = V4L2_CID_SATURATION,
+                .type = V4L2_CTRL_TYPE_INTEGER,
+                .name = "Saturation",
+                .minimum = 0,
+                .maximum = 255,
+                .step = 0x1,
+                .default_value = 0x10,
+                .flags = 0,
+                }, {
+                    .id = V4L2_CID_HUE,
+                    .type = V4L2_CTRL_TYPE_INTEGER,
+                    .name = "Hue",
+                    .minimum = -128,
+                    .maximum = 127,
+                    .step = 0x1,
+                    .default_value = 0x10,
+                    .flags = 0,
+                    }
+};
+
+struct tvp5150 {
+       struct i2c_client *client;
+
+       int norm;
+       int input;
+       int enable;
+       int bright;
+       int contrast;
+       int hue;
+       int sat;
+};
+
+static inline int tvp5150_read(struct i2c_client *c, unsigned char addr)
+{
+       unsigned char buffer[1];
+       int rc;
+
+       buffer[0] = addr;
+       if (1 != (rc = i2c_master_send(c, buffer, 1)))
+               dprintk(0, "i2c i/o error: rc == %d (should be 1)\n", rc);
+
+       msleep(10);
+
+       if (1 != (rc = i2c_master_recv(c, buffer, 1)))
+               dprintk(0, "i2c i/o error: rc == %d (should be 1)\n", rc);
+
+       return (buffer[0]);
+}
+
+static inline void tvp5150_write(struct i2c_client *c, unsigned char addr,
+                                unsigned char value)
+{
+       unsigned char buffer[2];
+       int rc;
+/*     struct tvp5150 *core = i2c_get_clientdata(c); */
+
+       buffer[0] = addr;
+       buffer[1] = value;
+       dprintk(1, "tvp5150: writing 0x%02x 0x%02x\n", buffer[0], buffer[1]);
+       if (2 != (rc = i2c_master_send(c, buffer, 2)))
+               dprintk(0, "i2c i/o error: rc == %d (should be 2)\n", rc);
+}
+
+static void dump_reg(struct i2c_client *c)
+{
+       printk("tvp5150: Video input source selection #1 = 0x%02x\n",
+              tvp5150_read(c, TVP5150_VD_IN_SRC_SEL_1));
+       printk("tvp5150: Analog channel controls = 0x%02x\n",
+              tvp5150_read(c, TVP5150_ANAL_CHL_CTL));
+       printk("tvp5150: Operation mode controls = 0x%02x\n",
+              tvp5150_read(c, TVP5150_OP_MODE_CTL));
+       printk("tvp5150: Miscellaneous controls = 0x%02x\n",
+              tvp5150_read(c, TVP5150_MISC_CTL));
+       printk("tvp5150: Autoswitch mask: TVP5150A / TVP5150AM = 0x%02x\n",
+              tvp5150_read(c, TVP5150_AUTOSW_MSK));
+       printk("tvp5150: Color killer threshold control = 0x%02x\n",
+              tvp5150_read(c, TVP5150_COLOR_KIL_THSH_CTL));
+       printk("tvp5150: Luminance processing control #1 = 0x%02x\n",
+              tvp5150_read(c, TVP5150_LUMA_PROC_CTL_1));
+       printk("tvp5150: Luminance processing control #2 = 0x%02x\n",
+              tvp5150_read(c, TVP5150_LUMA_PROC_CTL_2));
+       printk("tvp5150: Brightness control = 0x%02x\n",
+              tvp5150_read(c, TVP5150_BRIGHT_CTL));
+       printk("tvp5150: Color saturation control = 0x%02x\n",
+              tvp5150_read(c, TVP5150_SATURATION_CTL));
+       printk("tvp5150: Hue control = 0x%02x\n",
+              tvp5150_read(c, TVP5150_HUE_CTL));
+       printk("tvp5150: Contrast control = 0x%02x\n",
+              tvp5150_read(c, TVP5150_CONTRAST_CTL));
+       printk("tvp5150: Outputs and data rates select = 0x%02x\n",
+              tvp5150_read(c, TVP5150_DATA_RATE_SEL));
+       printk("tvp5150: Luminance processing control #3 = 0x%02x\n",
+              tvp5150_read(c, TVP5150_LUMA_PROC_CTL_3));
+       printk("tvp5150: Configuration shared pins = 0x%02x\n",
+              tvp5150_read(c, TVP5150_CONF_SHARED_PIN));
+       printk("tvp5150: Active video cropping start MSB = 0x%02x\n",
+              tvp5150_read(c, TVP5150_ACT_VD_CROP_ST_MSB));
+       printk("tvp5150: Active video cropping start LSB = 0x%02x\n",
+              tvp5150_read(c, TVP5150_ACT_VD_CROP_ST_LSB));
+       printk("tvp5150: Active video cropping stop MSB = 0x%02x\n",
+              tvp5150_read(c, TVP5150_ACT_VD_CROP_STP_MSB));
+       printk("tvp5150: Active video cropping stop LSB = 0x%02x\n",
+              tvp5150_read(c, TVP5150_ACT_VD_CROP_STP_LSB));
+       printk("tvp5150: Genlock/RTC = 0x%02x\n",
+              tvp5150_read(c, TVP5150_GENLOCK));
+       printk("tvp5150: Horizontal sync start = 0x%02x\n",
+              tvp5150_read(c, TVP5150_HORIZ_SYNC_START));
+       printk("tvp5150: Vertical blanking start = 0x%02x\n",
+              tvp5150_read(c, TVP5150_VERT_BLANKING_START));
+       printk("tvp5150: Vertical blanking stop = 0x%02x\n",
+              tvp5150_read(c, TVP5150_VERT_BLANKING_STOP));
+       printk("tvp5150: Chrominance processing control #1 = 0x%02x\n",
+              tvp5150_read(c, TVP5150_CHROMA_PROC_CTL_1));
+       printk("tvp5150: Chrominance processing control #2 = 0x%02x\n",
+              tvp5150_read(c, TVP5150_CHROMA_PROC_CTL_2));
+       printk("tvp5150: Interrupt reset register B = 0x%02x\n",
+              tvp5150_read(c, TVP5150_INT_RESET_REG_B));
+       printk("tvp5150: Interrupt enable register B = 0x%02x\n",
+              tvp5150_read(c, TVP5150_INT_ENABLE_REG_B));
+       printk("tvp5150: Interrupt configuration register B = 0x%02x\n",
+              tvp5150_read(c, TVP5150_INTT_CONFIG_REG_B));
+       printk("tvp5150: Video standard = 0x%02x\n",
+              tvp5150_read(c, TVP5150_VIDEO_STD));
+       printk("tvp5150: Cb gain factor = 0x%02x\n",
+              tvp5150_read(c, TVP5150_CB_GAIN_FACT));
+       printk("tvp5150: Cr gain factor = 0x%02x\n",
+              tvp5150_read(c, TVP5150_CR_GAIN_FACTOR));
+       printk("tvp5150: Macrovision on counter = 0x%02x\n",
+              tvp5150_read(c, TVP5150_MACROVISION_ON_CTR));
+       printk("tvp5150: Macrovision off counter = 0x%02x\n",
+              tvp5150_read(c, TVP5150_MACROVISION_OFF_CTR));
+       printk("tvp5150: revision select (TVP5150AM1 only) = 0x%02x\n",
+              tvp5150_read(c, TVP5150_REV_SELECT));
+       printk("tvp5150: MSB of device ID = 0x%02x\n",
+              tvp5150_read(c, TVP5150_MSB_DEV_ID));
+       printk("tvp5150: LSB of device ID = 0x%02x\n",
+              tvp5150_read(c, TVP5150_LSB_DEV_ID));
+       printk("tvp5150: ROM major version = 0x%02x\n",
+              tvp5150_read(c, TVP5150_ROM_MAJOR_VER));
+       printk("tvp5150: ROM minor version = 0x%02x\n",
+              tvp5150_read(c, TVP5150_ROM_MINOR_VER));
+       printk("tvp5150: Vertical line count MSB = 0x%02x\n",
+              tvp5150_read(c, TVP5150_VERT_LN_COUNT_MSB));
+       printk("tvp5150: Vertical line count LSB = 0x%02x\n",
+              tvp5150_read(c, TVP5150_VERT_LN_COUNT_LSB));
+       printk("tvp5150: Interrupt status register B = 0x%02x\n",
+              tvp5150_read(c, TVP5150_INT_STATUS_REG_B));
+       printk("tvp5150: Interrupt active register B = 0x%02x\n",
+              tvp5150_read(c, TVP5150_INT_ACTIVE_REG_B));
+       printk("tvp5150: Status register #1 = 0x%02x\n",
+              tvp5150_read(c, TVP5150_STATUS_REG_1));
+       printk("tvp5150: Status register #2 = 0x%02x\n",
+              tvp5150_read(c, TVP5150_STATUS_REG_2));
+       printk("tvp5150: Status register #3 = 0x%02x\n",
+              tvp5150_read(c, TVP5150_STATUS_REG_3));
+       printk("tvp5150: Status register #4 = 0x%02x\n",
+              tvp5150_read(c, TVP5150_STATUS_REG_4));
+       printk("tvp5150: Status register #5 = 0x%02x\n",
+              tvp5150_read(c, TVP5150_STATUS_REG_5));
+       printk("tvp5150: Closed caption data registers = 0x%02x\n",
+              tvp5150_read(c, TVP5150_CC_DATA_REG1));
+       printk("tvp5150: Closed caption data registers = 0x%02x\n",
+              tvp5150_read(c, TVP5150_CC_DATA_REG2));
+       printk("tvp5150: Closed caption data registers = 0x%02x\n",
+              tvp5150_read(c, TVP5150_CC_DATA_REG3));
+       printk("tvp5150: Closed caption data registers = 0x%02x\n",
+              tvp5150_read(c, TVP5150_CC_DATA_REG4));
+       printk("tvp5150: WSS data registers = 0x%02x\n",
+              tvp5150_read(c, TVP5150_WSS_DATA_REG1));
+       printk("tvp5150: WSS data registers = 0x%02x\n",
+              tvp5150_read(c, TVP5150_WSS_DATA_REG2));
+       printk("tvp5150: WSS data registers = 0x%02x\n",
+              tvp5150_read(c, TVP5150_WSS_DATA_REG3));
+       printk("tvp5150: WSS data registers = 0x%02x\n",
+              tvp5150_read(c, TVP5150_WSS_DATA_REG4));
+       printk("tvp5150: WSS data registers = 0x%02x\n",
+              tvp5150_read(c, TVP5150_WSS_DATA_REG5));
+       printk("tvp5150: WSS data registers = 0x%02x\n",
+              tvp5150_read(c, TVP5150_WSS_DATA_REG6));
+       printk("tvp5150: VPS data registers = 0x%02x\n",
+              tvp5150_read(c, TVP5150_VPS_DATA_REG1));
+       printk("tvp5150: VPS data registers = 0x%02x\n",
+              tvp5150_read(c, TVP5150_VPS_DATA_REG2));
+       printk("tvp5150: VPS data registers = 0x%02x\n",
+              tvp5150_read(c, TVP5150_VPS_DATA_REG3));
+       printk("tvp5150: VPS data registers = 0x%02x\n",
+              tvp5150_read(c, TVP5150_VPS_DATA_REG4));
+       printk("tvp5150: VPS data registers = 0x%02x\n",
+              tvp5150_read(c, TVP5150_VPS_DATA_REG5));
+       printk("tvp5150: VPS data registers = 0x%02x\n",
+              tvp5150_read(c, TVP5150_VPS_DATA_REG6));
+       printk("tvp5150: VPS data registers = 0x%02x\n",
+              tvp5150_read(c, TVP5150_VPS_DATA_REG7));
+       printk("tvp5150: VPS data registers = 0x%02x\n",
+              tvp5150_read(c, TVP5150_VPS_DATA_REG8));
+       printk("tvp5150: VPS data registers = 0x%02x\n",
+              tvp5150_read(c, TVP5150_VPS_DATA_REG9));
+       printk("tvp5150: VPS data registers = 0x%02x\n",
+              tvp5150_read(c, TVP5150_VPS_DATA_REG10));
+       printk("tvp5150: VPS data registers = 0x%02x\n",
+              tvp5150_read(c, TVP5150_VPS_DATA_REG11));
+       printk("tvp5150: VPS data registers = 0x%02x\n",
+              tvp5150_read(c, TVP5150_VPS_DATA_REG12));
+       printk("tvp5150: VPS data registers = 0x%02x\n",
+              tvp5150_read(c, TVP5150_VPS_DATA_REG13));
+       printk("tvp5150: VITC data registers = 0x%02x\n",
+              tvp5150_read(c, TVP5150_VITC_DATA_REG1));
+       printk("tvp5150: VITC data registers = 0x%02x\n",
+              tvp5150_read(c, TVP5150_VITC_DATA_REG2));
+       printk("tvp5150: VITC data registers = 0x%02x\n",
+              tvp5150_read(c, TVP5150_VITC_DATA_REG3));
+       printk("tvp5150: VITC data registers = 0x%02x\n",
+              tvp5150_read(c, TVP5150_VITC_DATA_REG4));
+       printk("tvp5150: VITC data registers = 0x%02x\n",
+              tvp5150_read(c, TVP5150_VITC_DATA_REG5));
+       printk("tvp5150: VITC data registers = 0x%02x\n",
+              tvp5150_read(c, TVP5150_VITC_DATA_REG6));
+       printk("tvp5150: VITC data registers = 0x%02x\n",
+              tvp5150_read(c, TVP5150_VITC_DATA_REG7));
+       printk("tvp5150: VITC data registers = 0x%02x\n",
+              tvp5150_read(c, TVP5150_VITC_DATA_REG8));
+       printk("tvp5150: VITC data registers = 0x%02x\n",
+              tvp5150_read(c, TVP5150_VITC_DATA_REG9));
+       printk("tvp5150: VBI FIFO read data = 0x%02x\n",
+              tvp5150_read(c, TVP5150_VBI_FIFO_READ_DATA));
+       printk("tvp5150: Teletext filter 1 = 0x%02x\n",
+              tvp5150_read(c, TVP5150_TELETEXT_FIL_1_1));
+       printk("tvp5150: Teletext filter 1 = 0x%02x\n",
+              tvp5150_read(c, TVP5150_TELETEXT_FIL_1_2));
+       printk("tvp5150: Teletext filter 1 = 0x%02x\n",
+              tvp5150_read(c, TVP5150_TELETEXT_FIL_1_3));
+       printk("tvp5150: Teletext filter 1 = 0x%02x\n",
+              tvp5150_read(c, TVP5150_TELETEXT_FIL_1_4));
+       printk("tvp5150: Teletext filter 1 = 0x%02x\n",
+              tvp5150_read(c, TVP5150_TELETEXT_FIL_1_5));
+       printk("tvp5150: Teletext filter 2 = 0x%02x\n",
+              tvp5150_read(c, TVP5150_TELETEXT_FIL_2_1));
+       printk("tvp5150: Teletext filter 2 = 0x%02x\n",
+              tvp5150_read(c, TVP5150_TELETEXT_FIL_2_2));
+       printk("tvp5150: Teletext filter 2 = 0x%02x\n",
+              tvp5150_read(c, TVP5150_TELETEXT_FIL_2_3));
+       printk("tvp5150: Teletext filter 2 = 0x%02x\n",
+              tvp5150_read(c, TVP5150_TELETEXT_FIL_2_4));
+       printk("tvp5150: Teletext filter 2 = 0x%02x\n",
+              tvp5150_read(c, TVP5150_TELETEXT_FIL_2_5));
+       printk("tvp5150: Teletext filter enable = 0x%02x\n",
+              tvp5150_read(c, TVP5150_TELETEXT_FIL_ENA));
+       printk("tvp5150: Interrupt status register A = 0x%02x\n",
+              tvp5150_read(c, TVP5150_INT_STATUS_REG_A));
+       printk("tvp5150: Interrupt enable register A = 0x%02x\n",
+              tvp5150_read(c, TVP5150_INT_ENABLE_REG_A));
+       printk("tvp5150: Interrupt configuration = 0x%02x\n",
+              tvp5150_read(c, TVP5150_INT_CONF));
+       printk("tvp5150: VDP configuration RAM data = 0x%02x\n",
+              tvp5150_read(c, TVP5150_VDP_CONF_RAM_DATA));
+       printk("tvp5150: Configuration RAM address low byte = 0x%02x\n",
+              tvp5150_read(c, TVP5150_CONF_RAM_ADDR_LOW));
+       printk("tvp5150: Configuration RAM address high byte = 0x%02x\n",
+              tvp5150_read(c, TVP5150_CONF_RAM_ADDR_HIGH));
+       printk("tvp5150: VDP status register = 0x%02x\n",
+              tvp5150_read(c, TVP5150_VDP_STATUS_REG));
+       printk("tvp5150: FIFO word count = 0x%02x\n",
+              tvp5150_read(c, TVP5150_FIFO_WORD_COUNT));
+       printk("tvp5150: FIFO interrupt threshold = 0x%02x\n",
+              tvp5150_read(c, TVP5150_FIFO_INT_THRESHOLD));
+       printk("tvp5150: FIFO reset = 0x%02x\n",
+              tvp5150_read(c, TVP5150_FIFO_RESET));
+       printk("tvp5150: Line number interrupt = 0x%02x\n",
+              tvp5150_read(c, TVP5150_LINE_NUMBER_INT));
+       printk("tvp5150: Pixel alignment register low byte = 0x%02x\n",
+              tvp5150_read(c, TVP5150_PIX_ALIGN_REG_LOW));
+       printk("tvp5150: Pixel alignment register high byte = 0x%02x\n",
+              tvp5150_read(c, TVP5150_PIX_ALIGN_REG_HIGH));
+       printk("tvp5150: FIFO output control = 0x%02x\n",
+              tvp5150_read(c, TVP5150_FIFO_OUT_CTRL));
+       printk("tvp5150: Full field enable 1 = 0x%02x\n",
+              tvp5150_read(c, TVP5150_FULL_FIELD_ENA_1));
+       printk("tvp5150: Full field enable 2 = 0x%02x\n",
+              tvp5150_read(c, TVP5150_FULL_FIELD_ENA_2));
+       printk("tvp5150: Line mode registers = 0x%02x\n",
+              tvp5150_read(c, TVP5150_LINE_MODE_REG_1));
+       printk("tvp5150: Line mode registers = 0x%02x\n",
+              tvp5150_read(c, TVP5150_LINE_MODE_REG_2));
+       printk("tvp5150: Line mode registers = 0x%02x\n",
+              tvp5150_read(c, TVP5150_LINE_MODE_REG_3));
+       printk("tvp5150: Line mode registers = 0x%02x\n",
+              tvp5150_read(c, TVP5150_LINE_MODE_REG_4));
+       printk("tvp5150: Line mode registers = 0x%02x\n",
+              tvp5150_read(c, TVP5150_LINE_MODE_REG_5));
+       printk("tvp5150: Line mode registers = 0x%02x\n",
+              tvp5150_read(c, TVP5150_LINE_MODE_REG_6));
+       printk("tvp5150: Line mode registers = 0x%02x\n",
+              tvp5150_read(c, TVP5150_LINE_MODE_REG_7));
+       printk("tvp5150: Line mode registers = 0x%02x\n",
+              tvp5150_read(c, TVP5150_LINE_MODE_REG_8));
+       printk("tvp5150: Line mode registers = 0x%02x\n",
+              tvp5150_read(c, TVP5150_LINE_MODE_REG_9));
+       printk("tvp5150: Line mode registers = 0x%02x\n",
+              tvp5150_read(c, TVP5150_LINE_MODE_REG_10));
+       printk("tvp5150: Line mode registers = 0x%02x\n",
+              tvp5150_read(c, TVP5150_LINE_MODE_REG_11));
+       printk("tvp5150: Line mode registers = 0x%02x\n",
+              tvp5150_read(c, TVP5150_LINE_MODE_REG_12));
+       printk("tvp5150: Line mode registers = 0x%02x\n",
+              tvp5150_read(c, TVP5150_LINE_MODE_REG_13));
+       printk("tvp5150: Line mode registers = 0x%02x\n",
+              tvp5150_read(c, TVP5150_LINE_MODE_REG_14));
+       printk("tvp5150: Line mode registers = 0x%02x\n",
+              tvp5150_read(c, TVP5150_LINE_MODE_REG_15));
+       printk("tvp5150: Line mode registers = 0x%02x\n",
+              tvp5150_read(c, TVP5150_LINE_MODE_REG_16));
+       printk("tvp5150: Line mode registers = 0x%02x\n",
+              tvp5150_read(c, TVP5150_LINE_MODE_REG_17));
+       printk("tvp5150: Line mode registers = 0x%02x\n",
+              tvp5150_read(c, TVP5150_LINE_MODE_REG_18));
+       printk("tvp5150: Line mode registers = 0x%02x\n",
+              tvp5150_read(c, TVP5150_LINE_MODE_REG_19));
+       printk("tvp5150: Line mode registers = 0x%02x\n",
+              tvp5150_read(c, TVP5150_LINE_MODE_REG_20));
+       printk("tvp5150: Line mode registers = 0x%02x\n",
+              tvp5150_read(c, TVP5150_LINE_MODE_REG_21));
+       printk("tvp5150: Line mode registers = 0x%02x\n",
+              tvp5150_read(c, TVP5150_LINE_MODE_REG_22));
+       printk("tvp5150: Line mode registers = 0x%02x\n",
+              tvp5150_read(c, TVP5150_LINE_MODE_REG_23));
+       printk("tvp5150: Line mode registers = 0x%02x\n",
+              tvp5150_read(c, TVP5150_LINE_MODE_REG_24));
+       printk("tvp5150: Line mode registers = 0x%02x\n",
+              tvp5150_read(c, TVP5150_LINE_MODE_REG_25));
+       printk("tvp5150: Line mode registers = 0x%02x\n",
+              tvp5150_read(c, TVP5150_LINE_MODE_REG_27));
+       printk("tvp5150: Line mode registers = 0x%02x\n",
+              tvp5150_read(c, TVP5150_LINE_MODE_REG_28));
+       printk("tvp5150: Line mode registers = 0x%02x\n",
+              tvp5150_read(c, TVP5150_LINE_MODE_REG_29));
+       printk("tvp5150: Line mode registers = 0x%02x\n",
+              tvp5150_read(c, TVP5150_LINE_MODE_REG_30));
+       printk("tvp5150: Line mode registers = 0x%02x\n",
+              tvp5150_read(c, TVP5150_LINE_MODE_REG_31));
+       printk("tvp5150: Line mode registers = 0x%02x\n",
+              tvp5150_read(c, TVP5150_LINE_MODE_REG_32));
+       printk("tvp5150: Line mode registers = 0x%02x\n",
+              tvp5150_read(c, TVP5150_LINE_MODE_REG_33));
+       printk("tvp5150: Line mode registers = 0x%02x\n",
+              tvp5150_read(c, TVP5150_LINE_MODE_REG_34));
+       printk("tvp5150: Line mode registers = 0x%02x\n",
+              tvp5150_read(c, TVP5150_LINE_MODE_REG_35));
+       printk("tvp5150: Line mode registers = 0x%02x\n",
+              tvp5150_read(c, TVP5150_LINE_MODE_REG_36));
+       printk("tvp5150: Line mode registers = 0x%02x\n",
+              tvp5150_read(c, TVP5150_LINE_MODE_REG_37));
+       printk("tvp5150: Line mode registers = 0x%02x\n",
+              tvp5150_read(c, TVP5150_LINE_MODE_REG_38));
+       printk("tvp5150: Line mode registers = 0x%02x\n",
+              tvp5150_read(c, TVP5150_LINE_MODE_REG_39));
+       printk("tvp5150: Line mode registers = 0x%02x\n",
+              tvp5150_read(c, TVP5150_LINE_MODE_REG_40));
+       printk("tvp5150: Line mode registers = 0x%02x\n",
+              tvp5150_read(c, TVP5150_LINE_MODE_REG_41));
+       printk("tvp5150: Line mode registers = 0x%02x\n",
+              tvp5150_read(c, TVP5150_LINE_MODE_REG_42));
+       printk("tvp5150: Line mode registers = 0x%02x\n",
+              tvp5150_read(c, TVP5150_LINE_MODE_REG_43));
+       printk("tvp5150: Line mode registers = 0x%02x\n",
+              tvp5150_read(c, TVP5150_LINE_MODE_REG_44));
+       printk("tvp5150: Full field mode register = 0x%02x\n",
+              tvp5150_read(c, TVP5150_FULL_FIELD_MODE_REG));
+}
+
+/****************************************************************************
+                       Basic functions
+ ****************************************************************************/
+enum tvp5150_input {
+       TVP5150_ANALOG_CH0 = 0,
+       TVP5150_SVIDEO = 1,
+       TVP5150_ANALOG_CH1 = 2,
+       TVP5150_BLACK_SCREEN = 8
+};
+
+static inline void tvp5150_selmux(struct i2c_client *c,
+                                 enum tvp5150_input input)
+{
+       struct tvp5150 *decoder = i2c_get_clientdata(c);
+
+       if (!decoder->enable)
+               input |= TVP5150_BLACK_SCREEN;
+
+       tvp5150_write(c, TVP5150_VD_IN_SRC_SEL_1, input);
+};
+
+static inline void tvp5150_reset(struct i2c_client *c)
+{
+       struct tvp5150 *decoder = i2c_get_clientdata(c);
+
+       tvp5150_write(c, TVP5150_CONF_SHARED_PIN, 2);
+
+       /* Automatic offset and AGC enabled */
+       tvp5150_write(c, TVP5150_ANAL_CHL_CTL, 0x15);
+
+       /* Normal Operation */
+//      tvp5150_write(c, TVP5150_OP_MODE_CTL, 0x00);
+
+       /* Activate YCrCb output 0x9 or 0xd ? */
+       tvp5150_write(c, TVP5150_MISC_CTL, 0x6f);
+
+       /* Activates video std autodetection for all standards */
+       tvp5150_write(c, TVP5150_AUTOSW_MSK, 0x0);
+
+       /* Default format: 0x47, 4:2:2: 0x40 */
+       tvp5150_write(c, TVP5150_DATA_RATE_SEL, 0x47);
+
+       tvp5150_selmux(c, decoder->input);
+
+       tvp5150_write(c, TVP5150_CHROMA_PROC_CTL_1, 0x0c);
+       tvp5150_write(c, TVP5150_CHROMA_PROC_CTL_2, 0x54);
+
+       tvp5150_write(c, 0x27, 0x20);   /* ?????????? */
+
+       tvp5150_write(c, TVP5150_VIDEO_STD, 0x0);       /* Auto switch */
+
+       tvp5150_write(c, TVP5150_BRIGHT_CTL, decoder->bright >> 8);
+       tvp5150_write(c, TVP5150_CONTRAST_CTL, decoder->contrast >> 8);
+       tvp5150_write(c, TVP5150_SATURATION_CTL, decoder->contrast >> 8);
+       tvp5150_write(c, TVP5150_HUE_CTL, (decoder->hue - 32768) >> 8);
+};
+
+static int tvp5150_get_ctrl(struct i2c_client *c, struct v4l2_control *ctrl)
+{
+/*     struct tvp5150 *decoder = i2c_get_clientdata(c); */
+
+       switch (ctrl->id) {
+       case V4L2_CID_BRIGHTNESS:
+               ctrl->value = tvp5150_read(c, TVP5150_BRIGHT_CTL);
+               return 0;
+       case V4L2_CID_CONTRAST:
+               ctrl->value = tvp5150_read(c, TVP5150_CONTRAST_CTL);
+               return 0;
+       case V4L2_CID_SATURATION:
+               ctrl->value = tvp5150_read(c, TVP5150_SATURATION_CTL);
+               return 0;
+       case V4L2_CID_HUE:
+               ctrl->value = tvp5150_read(c, TVP5150_HUE_CTL);
+               return 0;
+       default:
+               return -EINVAL;
+       }
+}
+
+static int tvp5150_set_ctrl(struct i2c_client *c, struct v4l2_control *ctrl)
+{
+/*     struct tvp5150 *decoder = i2c_get_clientdata(c); */
+
+       switch (ctrl->id) {
+       case V4L2_CID_BRIGHTNESS:
+               tvp5150_write(c, TVP5150_BRIGHT_CTL, ctrl->value);
+               return 0;
+       case V4L2_CID_CONTRAST:
+               tvp5150_write(c, TVP5150_CONTRAST_CTL, ctrl->value);
+               return 0;
+       case V4L2_CID_SATURATION:
+               tvp5150_write(c, TVP5150_SATURATION_CTL, ctrl->value);
+               return 0;
+       case V4L2_CID_HUE:
+               tvp5150_write(c, TVP5150_HUE_CTL, ctrl->value);
+               return 0;
+       default:
+               return -EINVAL;
+       }
+}
+
+/****************************************************************************
+                       I2C Command
+ ****************************************************************************/
+static int tvp5150_command(struct i2c_client *client,
+                          unsigned int cmd, void *arg)
+{
+       struct tvp5150 *decoder = i2c_get_clientdata(client);
+
+       switch (cmd) {
+
+       case 0:
+       case DECODER_INIT:
+               tvp5150_reset(client);
+               break;
+
+       case DECODER_DUMP:
+               dump_reg(client);
+               break;
+
+       case DECODER_GET_CAPABILITIES:
+               {
+                       struct video_decoder_capability *cap = arg;
+
+                       cap->flags = VIDEO_DECODER_PAL |
+                           VIDEO_DECODER_NTSC |
+                           VIDEO_DECODER_SECAM |
+                           VIDEO_DECODER_AUTO | VIDEO_DECODER_CCIR;
+                       cap->inputs = 3;
+                       cap->outputs = 1;
+                       break;
+               }
+       case DECODER_GET_STATUS:
+               {
+                       break;
+               }
+
+       case DECODER_SET_GPIO:
+               break;
+
+       case DECODER_SET_VBI_BYPASS:
+               break;
+
+       case DECODER_SET_NORM:
+               {
+                       int *iarg = arg;
+
+                       switch (*iarg) {
+
+                       case VIDEO_MODE_NTSC:
+                               break;
+
+                       case VIDEO_MODE_PAL:
+                               break;
+
+                       case VIDEO_MODE_SECAM:
+                               break;
+
+                       case VIDEO_MODE_AUTO:
+                               break;
+
+                       default:
+                               return -EINVAL;
+
+                       }
+                       decoder->norm = *iarg;
+                       break;
+               }
+       case DECODER_SET_INPUT:
+               {
+                       int *iarg = arg;
+                       if (*iarg < 0 || *iarg > 3) {
+                               return -EINVAL;
+                       }
+
+                       decoder->input = *iarg;
+                       tvp5150_selmux(client, decoder->input);
+
+                       break;
+               }
+       case DECODER_SET_OUTPUT:
+               {
+                       int *iarg = arg;
+
+                       /* not much choice of outputs */
+                       if (*iarg != 0) {
+                               return -EINVAL;
+                       }
+                       break;
+               }
+       case DECODER_ENABLE_OUTPUT:
+               {
+                       int *iarg = arg;
+
+                       decoder->enable = (*iarg != 0);
+
+                       tvp5150_selmux(client, decoder->input);
+
+                       break;
+               }
+       case VIDIOC_QUERYCTRL:
+               {
+                       struct v4l2_queryctrl *qc = arg;
+                       u8 i, n;
+
+                       dprintk(1, KERN_DEBUG "VIDIOC_QUERYCTRL");
+
+                       n = sizeof(tvp5150_qctrl) / sizeof(tvp5150_qctrl[0]);
+                       for (i = 0; i < n; i++)
+                               if (qc->id && qc->id == tvp5150_qctrl[i].id) {
+                                       memcpy(qc, &(tvp5150_qctrl[i]),
+                                              sizeof(*qc));
+                                       return 0;
+                               }
+
+                       return -EINVAL;
+               }
+       case VIDIOC_G_CTRL:
+               {
+                       struct v4l2_control *ctrl = arg;
+                       dprintk(1, KERN_DEBUG "VIDIOC_G_CTRL");
+
+                       return tvp5150_get_ctrl(client, ctrl);
+               }
+       case VIDIOC_S_CTRL_OLD: /* ??? */
+       case VIDIOC_S_CTRL:
+               {
+                       struct v4l2_control *ctrl = arg;
+                       u8 i, n;
+                       dprintk(1, KERN_DEBUG "VIDIOC_S_CTRL");
+                       n = sizeof(tvp5150_qctrl) / sizeof(tvp5150_qctrl[0]);
+                       for (i = 0; i < n; i++)
+                               if (ctrl->id == tvp5150_qctrl[i].id) {
+                                       if (ctrl->value <
+                                           tvp5150_qctrl[i].minimum
+                                           || ctrl->value >
+                                           tvp5150_qctrl[i].maximum)
+                                               return -ERANGE;
+                                       dprintk(1,
+                                               KERN_DEBUG
+                                               "VIDIOC_S_CTRL: id=%d, value=%d",
+                                               ctrl->id, ctrl->value);
+                                       return tvp5150_set_ctrl(client, ctrl);
+                               }
+                       return -EINVAL;
+               }
+
+       case DECODER_SET_PICTURE:
+               {
+                       struct video_picture *pic = arg;
+                       if (decoder->bright != pic->brightness) {
+                               /* We want 0 to 255 we get 0-65535 */
+                               decoder->bright = pic->brightness;
+                               tvp5150_write(client, TVP5150_BRIGHT_CTL,
+                                             decoder->bright >> 8);
+                       }
+                       if (decoder->contrast != pic->contrast) {
+                               /* We want 0 to 255 we get 0-65535 */
+                               decoder->contrast = pic->contrast;
+                               tvp5150_write(client, TVP5150_CONTRAST_CTL,
+                                             decoder->contrast >> 8);
+                       }
+                       if (decoder->sat != pic->colour) {
+                               /* We want 0 to 255 we get 0-65535 */
+                               decoder->sat = pic->colour;
+                               tvp5150_write(client, TVP5150_SATURATION_CTL,
+                                             decoder->contrast >> 8);
+                       }
+                       if (decoder->hue != pic->hue) {
+                               /* We want -128 to 127 we get 0-65535 */
+                               decoder->hue = pic->hue;
+                               tvp5150_write(client, TVP5150_HUE_CTL,
+                                             (decoder->hue - 32768) >> 8);
+                       }
+                       break;
+               }
+       default:
+               return -EINVAL;
+       }
+
+       return 0;
+}
+
+/****************************************************************************
+                       I2C Client & Driver
+ ****************************************************************************/
+static struct i2c_driver driver;
+
+static struct i2c_client client_template = {
+       .name = "(unset)",
+       .flags = I2C_CLIENT_ALLOW_USE,
+       .driver = &driver,
+};
+
+static int tvp5150_detect_client(struct i2c_adapter *adapter,
+                                int address, int kind)
+{
+       struct i2c_client *client;
+       struct tvp5150 *core;
+       int rv;
+
+       dprintk(1,
+               KERN_INFO
+               "tvp5150.c: detecting tvp5150 client on address 0x%x\n",
+               address << 1);
+
+       client_template.adapter = adapter;
+       client_template.addr = address;
+
+       /* Check if the adapter supports the needed features */
+       if (!i2c_check_functionality
+           (adapter,
+            I2C_FUNC_SMBUS_READ_BYTE | I2C_FUNC_SMBUS_WRITE_BYTE_DATA))
+               return 0;
+
+       client = kmalloc(sizeof(struct i2c_client), GFP_KERNEL);
+       if (client == 0)
+               return -ENOMEM;
+       memcpy(client, &client_template, sizeof(struct i2c_client));
+
+       core = kmalloc(sizeof(struct tvp5150), GFP_KERNEL);
+       if (core == 0) {
+               kfree(client);
+               return -ENOMEM;
+       }
+       memset(core, 0, sizeof(struct tvp5150));
+       i2c_set_clientdata(client, core);
+
+       rv = i2c_attach_client(client);
+
+       core->norm = VIDEO_MODE_AUTO;
+       core->input = 2;
+       core->enable = 1;
+       core->bright = 32768;
+       core->contrast = 32768;
+       core->hue = 32768;
+       core->sat = 32768;
+
+       if (rv) {
+               kfree(client);
+               kfree(core);
+               return rv;
+       }
+
+       if (debug > 1)
+               dump_reg(client);
+
+       return 0;
+}
+
+static int tvp5150_attach_adapter(struct i2c_adapter *adapter)
+{
+       dprintk(1,
+               KERN_INFO
+               "tvp5150.c: starting probe for adapter %s (0x%x)\n",
+               adapter->name, adapter->id);
+       return i2c_probe(adapter, &addr_data, &tvp5150_detect_client);
+}
+
+static int tvp5150_detach_client(struct i2c_client *client)
+{
+       struct tvp5150 *decoder = i2c_get_clientdata(client);
+       int err;
+
+       err = i2c_detach_client(client);
+       if (err) {
+               return err;
+       }
+
+       kfree(decoder);
+       kfree(client);
+
+       return 0;
+}
+
+/* ----------------------------------------------------------------------- */
+
+static struct i2c_driver driver = {
+       .owner = THIS_MODULE,
+       .name = "tvp5150",
+
+       /* FIXME */
+       .id = I2C_DRIVERID_SAA7110,
+       .flags = I2C_DF_NOTIFY,
+
+       .attach_adapter = tvp5150_attach_adapter,
+       .detach_client = tvp5150_detach_client,
+
+       .command = tvp5150_command,
+};
+
+static int __init tvp5150_init(void)
+{
+       return i2c_add_driver(&driver);
+}
+
+static void __exit tvp5150_exit(void)
+{
+       i2c_del_driver(&driver);
+}
+
+module_init(tvp5150_init);
+module_exit(tvp5150_exit);
diff --git a/drivers/media/video/tvp5150_reg.h b/drivers/media/video/tvp5150_reg.h
new file mode 100644 (file)
index 0000000..cd45c1d
--- /dev/null
@@ -0,0 +1,173 @@
+#define TVP5150_VD_IN_SRC_SEL_1      0x00 /* Video input source selection #1 */
+#define TVP5150_ANAL_CHL_CTL         0x01 /* Analog channel controls */
+#define TVP5150_OP_MODE_CTL          0x02 /* Operation mode controls */
+#define TVP5150_MISC_CTL             0x03 /* Miscellaneous controls */
+#define TVP5150_AUTOSW_MSK           0x04 /* Autoswitch mask: TVP5150A / TVP5150AM */
+
+/* Reserved 05h */
+
+#define TVP5150_COLOR_KIL_THSH_CTL   0x06 /* Color killer threshold control */
+#define TVP5150_LUMA_PROC_CTL_1      0x07 /* Luminance processing control #1 */
+#define TVP5150_LUMA_PROC_CTL_2      0x08 /* Luminance processing control #2 */
+#define TVP5150_BRIGHT_CTL           0x09 /* Brightness control */
+#define TVP5150_SATURATION_CTL       0x0a /* Color saturation control */
+#define TVP5150_HUE_CTL              0x0b /* Hue control */
+#define TVP5150_CONTRAST_CTL         0x0c /* Contrast control */
+#define TVP5150_DATA_RATE_SEL        0x0d /* Outputs and data rates select */
+#define TVP5150_LUMA_PROC_CTL_3      0x0e /* Luminance processing control #3 */
+#define TVP5150_CONF_SHARED_PIN      0x0f /* Configuration shared pins */
+
+/* Reserved 10h */
+
+#define TVP5150_ACT_VD_CROP_ST_MSB   0x11 /* Active video cropping start MSB */
+#define TVP5150_ACT_VD_CROP_ST_LSB   0x12 /* Active video cropping start LSB */
+#define TVP5150_ACT_VD_CROP_STP_MSB  0x13 /* Active video cropping stop MSB */
+#define TVP5150_ACT_VD_CROP_STP_LSB  0x14 /* Active video cropping stop LSB */
+#define TVP5150_GENLOCK              0x15 /* Genlock/RTC */
+#define TVP5150_HORIZ_SYNC_START     0x16 /* Horizontal sync start */
+
+/* Reserved 17h */
+
+#define TVP5150_VERT_BLANKING_START 0x18 /* Vertical blanking start */
+#define TVP5150_VERT_BLANKING_STOP  0x19 /* Vertical blanking stop */
+#define TVP5150_CHROMA_PROC_CTL_1   0x1a /* Chrominance processing control #1 */
+#define TVP5150_CHROMA_PROC_CTL_2   0x1b /* Chrominance processing control #2 */
+#define TVP5150_INT_RESET_REG_B     0x1c /* Interrupt reset register B */
+#define TVP5150_INT_ENABLE_REG_B    0x1d /* Interrupt enable register B */
+#define TVP5150_INTT_CONFIG_REG_B   0x1e /* Interrupt configuration register B */
+
+/* Reserved 1Fh-27h */
+
+#define TVP5150_VIDEO_STD           0x28 /* Video standard */
+
+/* Reserved 29h-2bh */
+
+#define TVP5150_CB_GAIN_FACT        0x2c /* Cb gain factor */
+#define TVP5150_CR_GAIN_FACTOR      0x2d /* Cr gain factor */
+#define TVP5150_MACROVISION_ON_CTR  0x2e /* Macrovision on counter */
+#define TVP5150_MACROVISION_OFF_CTR 0x2f /* Macrovision off counter */
+#define TVP5150_REV_SELECT          0x30 /* revision select (TVP5150AM1 only) */
+
+/* Reserved    31h-7Fh */
+
+#define TVP5150_MSB_DEV_ID          0x80 /* MSB of device ID */
+#define TVP5150_LSB_DEV_ID          0x81 /* LSB of device ID */
+#define TVP5150_ROM_MAJOR_VER       0x82 /* ROM major version */
+#define TVP5150_ROM_MINOR_VER       0x83 /* ROM minor version */
+#define TVP5150_VERT_LN_COUNT_MSB   0x84 /* Vertical line count MSB */
+#define TVP5150_VERT_LN_COUNT_LSB   0x85 /* Vertical line count LSB */
+#define TVP5150_INT_STATUS_REG_B    0x86 /* Interrupt status register B */
+#define TVP5150_INT_ACTIVE_REG_B    0x87 /* Interrupt active register B */
+#define TVP5150_STATUS_REG_1        0x88 /* Status register #1 */
+#define TVP5150_STATUS_REG_2        0x89 /* Status register #2 */
+#define TVP5150_STATUS_REG_3        0x8a /* Status register #3 */
+#define TVP5150_STATUS_REG_4        0x8b /* Status register #4 */
+#define TVP5150_STATUS_REG_5        0x8c /* Status register #5 */
+/* Reserved    8Dh-8Fh */
+#define TVP5150_CC_DATA_REG1        0x90 /* Closed caption data registers */
+#define TVP5150_CC_DATA_REG2        0x91 /* Closed caption data registers */
+#define TVP5150_CC_DATA_REG3        0x92 /* Closed caption data registers */
+#define TVP5150_CC_DATA_REG4        0x93 /* Closed caption data registers */
+#define TVP5150_WSS_DATA_REG1       0X94 /* WSS data registers */
+#define TVP5150_WSS_DATA_REG2       0X95 /* WSS data registers */
+#define TVP5150_WSS_DATA_REG3       0X96 /* WSS data registers */
+#define TVP5150_WSS_DATA_REG4       0X97 /* WSS data registers */
+#define TVP5150_WSS_DATA_REG5       0X98 /* WSS data registers */
+#define TVP5150_WSS_DATA_REG6       0X99 /* WSS data registers */
+#define TVP5150_VPS_DATA_REG1       0x9a /* VPS data registers */
+#define TVP5150_VPS_DATA_REG2       0x9b /* VPS data registers */
+#define TVP5150_VPS_DATA_REG3       0x9c /* VPS data registers */
+#define TVP5150_VPS_DATA_REG4       0x9d /* VPS data registers */
+#define TVP5150_VPS_DATA_REG5       0x9e /* VPS data registers */
+#define TVP5150_VPS_DATA_REG6       0x9f /* VPS data registers */
+#define TVP5150_VPS_DATA_REG7       0xa0 /* VPS data registers */
+#define TVP5150_VPS_DATA_REG8       0xa1 /* VPS data registers */
+#define TVP5150_VPS_DATA_REG9       0xa2 /* VPS data registers */
+#define TVP5150_VPS_DATA_REG10      0xa3 /* VPS data registers */
+#define TVP5150_VPS_DATA_REG11      0xa4 /* VPS data registers */
+#define TVP5150_VPS_DATA_REG12      0xa5 /* VPS data registers */
+#define TVP5150_VPS_DATA_REG13      0xa6 /* VPS data registers */
+#define TVP5150_VITC_DATA_REG1      0xa7 /* VITC data registers */
+#define TVP5150_VITC_DATA_REG2      0xa8 /* VITC data registers */
+#define TVP5150_VITC_DATA_REG3      0xa9 /* VITC data registers */
+#define TVP5150_VITC_DATA_REG4      0xaa /* VITC data registers */
+#define TVP5150_VITC_DATA_REG5      0xab /* VITC data registers */
+#define TVP5150_VITC_DATA_REG6      0xac /* VITC data registers */
+#define TVP5150_VITC_DATA_REG7      0xad /* VITC data registers */
+#define TVP5150_VITC_DATA_REG8      0xae /* VITC data registers */
+#define TVP5150_VITC_DATA_REG9      0xaf /* VITC data registers */
+#define TVP5150_VBI_FIFO_READ_DATA  0xb0 /* VBI FIFO read data */
+#define TVP5150_TELETEXT_FIL_1_1    0xb1 /* Teletext filter 1 */
+#define TVP5150_TELETEXT_FIL_1_2    0xb2 /* Teletext filter 1 */
+#define TVP5150_TELETEXT_FIL_1_3    0xb3 /* Teletext filter 1 */
+#define TVP5150_TELETEXT_FIL_1_4    0xb4 /* Teletext filter 1 */
+#define TVP5150_TELETEXT_FIL_1_5    0xb5 /* Teletext filter 1 */
+#define TVP5150_TELETEXT_FIL_2_1    0xb6 /* Teletext filter 2 */
+#define TVP5150_TELETEXT_FIL_2_2    0xb7 /* Teletext filter 2 */
+#define TVP5150_TELETEXT_FIL_2_3    0xb8 /* Teletext filter 2 */
+#define TVP5150_TELETEXT_FIL_2_4    0xb9 /* Teletext filter 2 */
+#define TVP5150_TELETEXT_FIL_2_5    0xba /* Teletext filter 2 */
+#define TVP5150_TELETEXT_FIL_ENA    0xbb /* Teletext filter enable */
+/* Reserved    BCh-BFh */
+#define TVP5150_INT_STATUS_REG_A    0xc0 /* Interrupt status register A */
+#define TVP5150_INT_ENABLE_REG_A    0xc1 /* Interrupt enable register A */
+#define TVP5150_INT_CONF            0xc2 /* Interrupt configuration */
+#define TVP5150_VDP_CONF_RAM_DATA   0xc3 /* VDP configuration RAM data */
+#define TVP5150_CONF_RAM_ADDR_LOW   0xc4 /* Configuration RAM address low byte */
+#define TVP5150_CONF_RAM_ADDR_HIGH  0xc5 /* Configuration RAM address high byte */
+#define TVP5150_VDP_STATUS_REG      0xc6 /* VDP status register */
+#define TVP5150_FIFO_WORD_COUNT     0xc7 /* FIFO word count */
+#define TVP5150_FIFO_INT_THRESHOLD  0xc8 /* FIFO interrupt threshold */
+#define TVP5150_FIFO_RESET          0xc9 /* FIFO reset */
+#define TVP5150_LINE_NUMBER_INT     0xca /* Line number interrupt */
+#define TVP5150_PIX_ALIGN_REG_LOW   0xcb /* Pixel alignment register low byte */
+#define TVP5150_PIX_ALIGN_REG_HIGH  0xcc /* Pixel alignment register high byte */
+#define TVP5150_FIFO_OUT_CTRL       0xcd /* FIFO output control */
+/* Reserved    CEh */
+#define TVP5150_FULL_FIELD_ENA_1    0xcf /* Full field enable 1 */
+#define TVP5150_FULL_FIELD_ENA_2    0xd0 /* Full field enable 2 */
+#define TVP5150_LINE_MODE_REG_1     0xd1 /* Line mode registers */
+#define TVP5150_LINE_MODE_REG_2     0xd2 /* Line mode registers */
+#define TVP5150_LINE_MODE_REG_3     0xd3 /* Line mode registers */
+#define TVP5150_LINE_MODE_REG_4     0xd4 /* Line mode registers */
+#define TVP5150_LINE_MODE_REG_5     0xd5 /* Line mode registers */
+#define TVP5150_LINE_MODE_REG_6     0xd6 /* Line mode registers */
+#define TVP5150_LINE_MODE_REG_7     0xd7 /* Line mode registers */
+#define TVP5150_LINE_MODE_REG_8     0xd8 /* Line mode registers */
+#define TVP5150_LINE_MODE_REG_9     0xd9 /* Line mode registers */
+#define TVP5150_LINE_MODE_REG_10    0xda /* Line mode registers */
+#define TVP5150_LINE_MODE_REG_11    0xdb /* Line mode registers */
+#define TVP5150_LINE_MODE_REG_12    0xdc /* Line mode registers */
+#define TVP5150_LINE_MODE_REG_13    0xdd /* Line mode registers */
+#define TVP5150_LINE_MODE_REG_14    0xde /* Line mode registers */
+#define TVP5150_LINE_MODE_REG_15    0xdf /* Line mode registers */
+#define TVP5150_LINE_MODE_REG_16    0xe0 /* Line mode registers */
+#define TVP5150_LINE_MODE_REG_17    0xe1 /* Line mode registers */
+#define TVP5150_LINE_MODE_REG_18    0xe2 /* Line mode registers */
+#define TVP5150_LINE_MODE_REG_19    0xe3 /* Line mode registers */
+#define TVP5150_LINE_MODE_REG_20    0xe4 /* Line mode registers */
+#define TVP5150_LINE_MODE_REG_21    0xe5 /* Line mode registers */
+#define TVP5150_LINE_MODE_REG_22    0xe6 /* Line mode registers */
+#define TVP5150_LINE_MODE_REG_23    0xe7 /* Line mode registers */
+#define TVP5150_LINE_MODE_REG_24    0xe8 /* Line mode registers */
+#define TVP5150_LINE_MODE_REG_25    0xe9 /* Line mode registers */
+#define TVP5150_LINE_MODE_REG_27    0xea /* Line mode registers */
+#define TVP5150_LINE_MODE_REG_28    0xeb /* Line mode registers */
+#define TVP5150_LINE_MODE_REG_29    0xec /* Line mode registers */
+#define TVP5150_LINE_MODE_REG_30    0xed /* Line mode registers */
+#define TVP5150_LINE_MODE_REG_31    0xee /* Line mode registers */
+#define TVP5150_LINE_MODE_REG_32    0xef /* Line mode registers */
+#define TVP5150_LINE_MODE_REG_33    0xf0 /* Line mode registers */
+#define TVP5150_LINE_MODE_REG_34    0xf1 /* Line mode registers */
+#define TVP5150_LINE_MODE_REG_35    0xf2 /* Line mode registers */
+#define TVP5150_LINE_MODE_REG_36    0xf3 /* Line mode registers */
+#define TVP5150_LINE_MODE_REG_37    0xf4 /* Line mode registers */
+#define TVP5150_LINE_MODE_REG_38    0xf5 /* Line mode registers */
+#define TVP5150_LINE_MODE_REG_39    0xf6 /* Line mode registers */
+#define TVP5150_LINE_MODE_REG_40    0xf7 /* Line mode registers */
+#define TVP5150_LINE_MODE_REG_41    0xf8 /* Line mode registers */
+#define TVP5150_LINE_MODE_REG_42    0xf9 /* Line mode registers */
+#define TVP5150_LINE_MODE_REG_43    0xfa /* Line mode registers */
+#define TVP5150_LINE_MODE_REG_44    0xfb /* Line mode registers */
+#define TVP5150_FULL_FIELD_MODE_REG 0xfc /* Full field mode register */
+/* Reserved    FDh-FFh */
index d679ca23ded71aac49e7ea70f229e40137ddd300..4134549d11a81c67f6d3156769a5da1201605b62 100644 (file)
@@ -708,7 +708,7 @@ v4l_compat_translate_ioctl(struct inode         *inode,
        }
        case VIDIOCGFREQ: /*  get frequency  */
        {
-               int *freq = arg;
+               unsigned long *freq = arg;
 
                freq2.tuner = 0;
                err = drv(inode, file, VIDIOC_G_FREQUENCY, &freq2);
@@ -720,7 +720,7 @@ v4l_compat_translate_ioctl(struct inode         *inode,
        }
        case VIDIOCSFREQ: /*  set frequency  */
        {
-               int *freq = arg;
+               unsigned long *freq = arg;
 
                freq2.tuner = 0;
                drv(inode, file, VIDIOC_G_FREQUENCY, &freq2);
@@ -960,7 +960,7 @@ v4l_compat_translate_ioctl(struct inode         *inode,
                fmt->start[1]         = fmt2->fmt.vbi.start[1];
                fmt->count[1]         = fmt2->fmt.vbi.count[1];
                fmt->flags            = fmt2->fmt.vbi.flags & 0x03;
-                break;
+               break;
        }
        case VIDIOCSVBIFMT:
        {
index 574b8e36f3c611e54e4698db948b2dd04c9b8cb3..acfd3a103f35ccdfa6cf31c44877d1f217262679 100644 (file)
@@ -147,7 +147,7 @@ int videobuf_dma_init_user(struct videobuf_dmabuf *dma, int direction,
                data,size,dma->nr_pages);
 
        down_read(&current->mm->mmap_sem);
-        err = get_user_pages(current,current->mm,
+       err = get_user_pages(current,current->mm,
                             data & PAGE_MASK, dma->nr_pages,
                             rw == READ, 1, /* force */
                             dma->pages, NULL);
@@ -750,9 +750,9 @@ videobuf_read_zerocopy(struct videobuf_queue *q, char __user *data,
 {
        enum v4l2_field field;
        unsigned long flags;
-        int retval;
+       int retval;
 
-        /* setup stuff */
+       /* setup stuff */
        retval = -ENOMEM;
        q->read_buf = videobuf_alloc(q->msize);
        if (NULL == q->read_buf)
@@ -760,18 +760,18 @@ videobuf_read_zerocopy(struct videobuf_queue *q, char __user *data,
 
        q->read_buf->memory = V4L2_MEMORY_USERPTR;
        q->read_buf->baddr  = (unsigned long)data;
-        q->read_buf->bsize  = count;
+       q->read_buf->bsize  = count;
        field = videobuf_next_field(q);
        retval = q->ops->buf_prepare(q,q->read_buf,field);
        if (0 != retval)
                goto done;
 
-        /* start capture & wait */
+       /* start capture & wait */
        spin_lock_irqsave(q->irqlock,flags);
        q->ops->buf_queue(q,q->read_buf);
        spin_unlock_irqrestore(q->irqlock,flags);
-        retval = videobuf_waiton(q->read_buf,0,0);
-        if (0 == retval) {
+       retval = videobuf_waiton(q->read_buf,0,0);
+       if (0 == retval) {
                videobuf_dma_pci_sync(q->pci,&q->read_buf->dma);
                if (STATE_ERROR == q->read_buf->state)
                        retval = -EIO;
@@ -828,7 +828,7 @@ ssize_t videobuf_read_one(struct videobuf_queue *q,
        }
 
        /* wait until capture is done */
-        retval = videobuf_waiton(q->read_buf, nonblocking, 1);
+       retval = videobuf_waiton(q->read_buf, nonblocking, 1);
        if (0 != retval)
                goto done;
        videobuf_dma_pci_sync(q->pci,&q->read_buf->dma);
@@ -1096,7 +1096,7 @@ videobuf_vm_nopage(struct vm_area_struct *vma, unsigned long vaddr,
 
        dprintk(3,"nopage: fault @ %08lx [vma %08lx-%08lx]\n",
                vaddr,vma->vm_start,vma->vm_end);
-        if (vaddr > vma->vm_end)
+       if (vaddr > vma->vm_end)
                return NOPAGE_SIGBUS;
        page = alloc_page(GFP_USER);
        if (!page)
diff --git a/drivers/media/video/wm8775.c b/drivers/media/video/wm8775.c
new file mode 100644 (file)
index 0000000..22f2862
--- /dev/null
@@ -0,0 +1,254 @@
+/*
+ * wm8775 - driver version 0.0.1
+ *
+ * Copyright (C) 2004 Ulf Eklund <ivtv at eklund.to>
+ *
+ * Based on saa7115 driver
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/ioctl.h>
+#include <asm/uaccess.h>
+#include <linux/i2c.h>
+#include <linux/i2c-id.h>
+#include <linux/videodev.h>
+#include <media/audiochip.h>
+
+MODULE_DESCRIPTION("wm8775 driver");
+MODULE_AUTHOR("Ulf Eklund");
+MODULE_LICENSE("GPL");
+
+#define wm8775_err(fmt, arg...) do { \
+       printk(KERN_ERR "%s %d-%04x: " fmt, client->driver->name, \
+              i2c_adapter_id(client->adapter), client->addr , ## arg); } while (0)
+#define wm8775_info(fmt, arg...) do { \
+       printk(KERN_INFO "%s %d-%04x: " fmt, client->driver->name, \
+              i2c_adapter_id(client->adapter), client->addr , ## arg); } while (0)
+
+
+static unsigned short normal_i2c[] = { 0x36 >> 1, I2C_CLIENT_END };
+
+
+I2C_CLIENT_INSMOD;
+
+/* ----------------------------------------------------------------------- */
+
+enum {
+       R7 = 7, R11 = 11,
+       R12, R13, R14, R15, R16, R17, R18, R19, R20, R21, R23 = 23,
+       TOT_REGS
+};
+
+struct wm8775_state {
+       u8 input;               /* Last selected input (0-0xf) */
+       u8 muted;
+};
+
+static int wm8775_write(struct i2c_client *client, int reg, u16 val)
+{
+       int i;
+
+       if (reg < 0 || reg >= TOT_REGS) {
+               wm8775_err("Invalid register R%d\n", reg);
+               return -1;
+       }
+
+       for (i = 0; i < 3; i++) {
+               if (i2c_smbus_write_byte_data(client, (reg << 1) |
+                                       (val >> 8), val & 0xff) == 0) {
+                       return 0;
+               }
+       }
+       wm8775_err("I2C: cannot write %03x to register R%d\n", val, reg);
+       return -1;
+}
+
+static int wm8775_command(struct i2c_client *client, unsigned int cmd,
+                         void *arg)
+{
+       struct wm8775_state *state = i2c_get_clientdata(client);
+       int *input = arg;
+
+       switch (cmd) {
+       case AUDC_SET_INPUT:
+               wm8775_write(client, R21, 0x0c0);
+               wm8775_write(client, R14, 0x1d4);
+               wm8775_write(client, R15, 0x1d4);
+
+               if (*input == AUDIO_RADIO) {
+                       wm8775_write(client, R21, 0x108);
+                       state->input = 8;
+                       state->muted = 0;
+                       break;
+               }
+               if (*input == AUDIO_MUTE) {
+                       state->muted = 1;
+                       break;
+               }
+               if (*input == AUDIO_UNMUTE) {
+                       wm8775_write(client, R21, 0x100 + state->input);
+                       state->muted = 0;
+                       break;
+               }
+               /* All other inputs... */
+               wm8775_write(client, R21, 0x102);
+               state->input = 2;
+               state->muted = 0;
+               break;
+
+       case VIDIOC_LOG_STATUS:
+               wm8775_info("Input: %s%s\n",
+                           state->input == 8 ? "radio" : "default",
+                           state->muted ? " (muted)" : "");
+               break;
+
+       case VIDIOC_S_FREQUENCY:
+               /* If I remove this, then it can happen that I have no
+                  sound the first time I tune from static to a valid channel.
+                  It's difficult to reproduce and is almost certainly related
+                  to the zero cross detect circuit. */
+               wm8775_write(client, R21, 0x0c0);
+               wm8775_write(client, R14, 0x1d4);
+               wm8775_write(client, R15, 0x1d4);
+               wm8775_write(client, R21, 0x100 + state->input);
+               break;
+
+       default:
+               return -EINVAL;
+       }
+       return 0;
+}
+
+/* ----------------------------------------------------------------------- */
+
+/* i2c implementation */
+
+/*
+ * Generic i2c probe
+ * concerning the addresses: i2c wants 7 bit (without the r/w bit), so '>>1'
+ */
+
+static struct i2c_driver i2c_driver;
+
+static int wm8775_attach(struct i2c_adapter *adapter, int address, int kind)
+{
+       struct i2c_client *client;
+       struct wm8775_state *state;
+
+       /* Check if the adapter supports the needed features */
+       if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA))
+               return 0;
+
+       client = kmalloc(sizeof(struct i2c_client), GFP_KERNEL);
+       if (client == 0)
+               return -ENOMEM;
+
+       memset(client, 0, sizeof(struct i2c_client));
+       client->addr = address;
+       client->adapter = adapter;
+       client->driver = &i2c_driver;
+       client->flags = I2C_CLIENT_ALLOW_USE;
+       snprintf(client->name, sizeof(client->name) - 1, "wm8775");
+
+       wm8775_info("chip found @ 0x%x (%s)\n", address << 1, adapter->name);
+
+       state = kmalloc(sizeof(struct wm8775_state), GFP_KERNEL);
+       if (state == NULL) {
+               kfree(client);
+               return -ENOMEM;
+       }
+       state->input = 2;
+       state->muted = 0;
+       i2c_set_clientdata(client, state);
+
+       /* initialize wm8775 */
+       wm8775_write(client, R23, 0x000);       /* RESET */
+       wm8775_write(client, R7, 0x000);        /* Disable zero cross detect timeout */
+       wm8775_write(client, R11, 0x021);       /* Left justified, 24-bit mode */
+       wm8775_write(client, R12, 0x102);       /* Master mode, clock ratio 256fs */
+       wm8775_write(client, R13, 0x000);       /* Powered up */
+       wm8775_write(client, R14, 0x1d4);       /* ADC gain +2.5dB, enable zero cross */
+       wm8775_write(client, R15, 0x1d4);       /* ADC gain +2.5dB, enable zero cross */
+       wm8775_write(client, R16, 0x1bf);       /* ALC Stereo, ALC target level -1dB FS */
+       /* max gain +8dB */
+       wm8775_write(client, R17, 0x185);       /* Enable gain control, use zero cross */
+       /* detection, ALC hold time 42.6 ms */
+       wm8775_write(client, R18, 0x0a2);       /* ALC gain ramp up delay 34 s, */
+       /* ALC gain ramp down delay 33 ms */
+       wm8775_write(client, R19, 0x005);       /* Enable noise gate, threshold -72dBfs */
+       wm8775_write(client, R20, 0x07a);       /* Transient window 4ms, lower PGA gain */
+       /* limit -1dB */
+       wm8775_write(client, R21, 0x102);       /* LRBOTH = 1, use input 2. */
+       i2c_attach_client(client);
+
+       return 0;
+}
+
+static int wm8775_probe(struct i2c_adapter *adapter)
+{
+#ifdef I2C_CLASS_TV_ANALOG
+       if (adapter->class & I2C_CLASS_TV_ANALOG)
+#else
+       if (adapter->id == I2C_HW_B_BT848)
+#endif
+               return i2c_probe(adapter, &addr_data, wm8775_attach);
+       return 0;
+}
+
+static int wm8775_detach(struct i2c_client *client)
+{
+       int err;
+
+       err = i2c_detach_client(client);
+       if (err) {
+               return err;
+       }
+       kfree(client);
+
+       return 0;
+}
+
+/* ----------------------------------------------------------------------- */
+
+/* i2c implementation */
+static struct i2c_driver i2c_driver = {
+       .name = "wm8775",
+
+       .id = I2C_DRIVERID_WM8775,
+       .flags = I2C_DF_NOTIFY,
+
+       .attach_adapter = wm8775_probe,
+       .detach_client = wm8775_detach,
+       .command = wm8775_command,
+       .owner = THIS_MODULE,
+};
+
+
+static int __init wm8775_init_module(void)
+{
+       return i2c_add_driver(&i2c_driver);
+}
+
+static void __exit wm8775_cleanup_module(void)
+{
+       i2c_del_driver(&i2c_driver);
+}
+
+module_init(wm8775_init_module);
+module_exit(wm8775_cleanup_module);
index d4740a89cea1c21fd3375969816af9c1f4e8f170..4ed898585c7082234aaec06bfd6e6150dd2068d4 100644 (file)
@@ -26,7 +26,6 @@
 
 #define ZR016_VERSION "v0.7"
 
-#include <linux/version.h>
 #include <linux/module.h>
 #include <linux/init.h>
 #include <linux/slab.h>
index 13b1e7b6fd6eb656bb1a7256d0b0dfe529b55ff6..0144576a61233d239e7bf35f1f0811418b8ed6b7 100644 (file)
@@ -26,7 +26,6 @@
 
 #define ZR050_VERSION "v0.7.1"
 
-#include <linux/version.h>
 #include <linux/module.h>
 #include <linux/init.h>
 #include <linux/slab.h>
index b50dc403e6db6017b86be378b9491629544e0b98..129744a07abd868c47609ad23adda80c42f8e82e 100644 (file)
@@ -26,7 +26,6 @@
 
 #define ZR060_VERSION "v0.7"
 
-#include <linux/version.h>
 #include <linux/module.h>
 #include <linux/init.h>
 #include <linux/slab.h>
index 790a2932ded99673bae69d0ab7cd16e99e2454b9..74022316fc63403392c7783ac13fc8226e098ceb 100644 (file)
@@ -47,7 +47,6 @@
 /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
 
 #include <linux/config.h>
-#include <linux/version.h>
 #include <linux/kernel.h>
 #include <linux/module.h>
 #include <linux/errno.h>
@@ -92,9 +91,9 @@ static int mfcounter = 0;
  *  Public data...
  */
 int mpt_lan_index = -1;
-int mpt_stm_index = -1;
+static int mpt_stm_index = -1;
 
-struct proc_dir_entry *mpt_proc_root_dir;
+static struct proc_dir_entry *mpt_proc_root_dir;
 
 #define WHOINIT_UNKNOWN                0xAA
 
@@ -6272,7 +6271,6 @@ EXPORT_SYMBOL(mpt_resume);
 EXPORT_SYMBOL(mpt_suspend);
 #endif
 EXPORT_SYMBOL(ioc_list);
-EXPORT_SYMBOL(mpt_proc_root_dir);
 EXPORT_SYMBOL(mpt_register);
 EXPORT_SYMBOL(mpt_deregister);
 EXPORT_SYMBOL(mpt_event_register);
@@ -6290,7 +6288,6 @@ EXPORT_SYMBOL(mpt_verify_adapter);
 EXPORT_SYMBOL(mpt_GetIocState);
 EXPORT_SYMBOL(mpt_print_ioc_summary);
 EXPORT_SYMBOL(mpt_lan_index);
-EXPORT_SYMBOL(mpt_stm_index);
 EXPORT_SYMBOL(mpt_HardResetHandler);
 EXPORT_SYMBOL(mpt_config);
 EXPORT_SYMBOL(mpt_toolbox);
index e7efeb7740b9ee325e9029dd43a164644aa5640f..8ad277a9afa16a37906045a522a7b9ca4e21a7f4 100644 (file)
@@ -49,7 +49,6 @@
 #define MPTBASE_H_INCLUDED
 /*{-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
 
-#include <linux/version.h>
 #include <linux/config.h>
 #include <linux/kernel.h>
 #include <linux/pci.h>
@@ -1007,10 +1006,8 @@ extern int        mptbase_sas_persist_operation(MPT_ADAPTER *ioc, u8 persist_opcode);
  *  Public data decl's...
  */
 extern struct list_head          ioc_list;
-extern struct proc_dir_entry   *mpt_proc_root_dir;
 
 extern int               mpt_lan_index;        /* needed by mptlan.c */
-extern int               mpt_stm_index;        /* needed by mptstm.c */
 
 /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
 #endif         /* } __KERNEL__ */
index cb2d59d5f5af76e395a8714bbe2e4e831557cfae..602138f8544db665ded8957738b1dcca7208a772 100644 (file)
@@ -45,7 +45,6 @@
 */
 /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
 
-#include <linux/version.h>
 #include <linux/kernel.h>
 #include <linux/module.h>
 #include <linux/errno.h>
index 28754a9cb8036a93cec4fa962e2e1cbeeb5e98af..518996e03481088f81ae3ce3ad165c205fb0c4a9 100644 (file)
@@ -49,7 +49,6 @@
 #define MPTCTL_H_INCLUDED
 /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
 
-#include "linux/version.h"
 
 
 /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
index 750e343eb98143bbdd76687dea3d070c705ac8a1..3726ecba570707357c8728ce7799224b2d1e2915 100644 (file)
@@ -66,7 +66,6 @@
 #include <linux/slab.h>
 #include <linux/miscdevice.h>
 #include <linux/spinlock.h>
-#include <linux/version.h>
 #include <linux/workqueue.h>
 #include <linux/delay.h>
 // #include <linux/trdevice.h>
index 9c4dd682ac74f1fcf92fab62e3b666fd2d54afb9..bc2b72b3290547dce8a0a0214f542e105bdeac73 100644 (file)
@@ -14,7 +14,6 @@
  *
  */
 
-#include <linux/version.h>
 #include <linux/module.h>
 #include <linux/kernel.h>
 #include <linux/spinlock.h>
index 165f3405df277f3ffef0f88a3028789b0e76e4b2..4bb461793851c0d704b8ac320a000571051f10ac 100644 (file)
@@ -14,7 +14,6 @@
  *
  */
 
-#include <linux/version.h>
 #include <linux/module.h>
 #include <linux/kernel.h>
 #include <linux/proc_fs.h>
index ecce4ffd3e23f21877df72759efba566c30e1bfe..d7e20a34f88db4b6b8661bbcd8435e4363c3f904 100644 (file)
@@ -31,7 +31,6 @@
 #include <linux/slab.h>
 #include <linux/config.h>
 #include <linux/module.h>
-#include <linux/version.h>
 #include <linux/interrupt.h>
 #include <linux/device.h>
 #include <linux/input.h>
index c4a19d2dc67f6aabdc88977311dbd4ba2fa109ce..0807c1c91e5544695df9f4ca76df1e4c6d1c2d77 100644 (file)
@@ -20,7 +20,6 @@
  *     - Plugged memory leak in cfi_staa_writev().
  */
 
-#include <linux/version.h>
 #include <linux/module.h>
 #include <linux/types.h>
 #include <linux/kernel.h>
index de48b35f5609e96957b2a7ec0e71de2572ca0236..666cce1bf60c0dddea6df065f47c89cd22330ef9 100644 (file)
@@ -82,7 +82,6 @@
  *       * Comb the init routine.  It's still a bit cludgy on a few things.
  */
 
-#include <linux/version.h>
 #include <linux/config.h>
 #include <linux/kernel.h>
 #include <linux/module.h>
index c0daf58357cacaba92fcf0550bac25d84e286eaf..60a6e51d662f33a80760738d57da53a85bdc0e2e 100644 (file)
@@ -21,7 +21,6 @@
 #include <linux/mtd/map.h>
 #include <linux/mtd/partitions.h>
 #include <linux/config.h>
-#include <linux/version.h>
 #include <asm/io.h>
 #include <asm/ibm44x.h>
 #include <platforms/4xx/ebony.h>
index 6e559bc146363e2abedbb17e83fd9a1017197118..c223514ca2ebef9a9da381ff7bfb93fc040edd7b 100644 (file)
@@ -19,7 +19,6 @@
 #include <linux/mtd/map.h>
 #include <linux/mtd/partitions.h>
 #include <linux/config.h>
-#include <linux/version.h>
 #include <asm/io.h>
 #include <asm/ibm44x.h>
 #include <platforms/4xx/ocotea.h>
index 5c17bca3a37e0d52e981b65ec638e59d75524b06..f46bec66150fe4ea89713e24405d33f45e06e26a 100644 (file)
@@ -21,7 +21,6 @@
 #include <linux/mtd/map.h>
 #include <linux/mtd/partitions.h>
 #include <linux/config.h>
-#include <linux/version.h>
 #include <asm/io.h>
 #include <asm/ibm4xx.h>
 #include <platforms/4xx/walnut.h>
index 3cafcdf28aedec5049949f21a25f19f53ed454e2..9c5945d6df882eecbe1bce15f6b62e0f22a4fbd4 100644 (file)
@@ -17,6 +17,7 @@
 #include <linux/mtd/mtd.h>
 #include <linux/mtd/nand.h>
 #include <linux/mtd/partitions.h>
+#include <linux/version.h>
 #include <asm/io.h>
 
 /* fixme: this is ugly */
index 056dfc17a075acb69600320ec3975e2f17cbfd17..a3c7fea404d096d84a9cbcdecce88ebfac2ebadf 100644 (file)
@@ -27,7 +27,6 @@
  *     10-06-2002 TG   128K card support added
  */
 
-#include <linux/version.h>
 #include <linux/slab.h>
 #include <linux/init.h>
 #include <linux/module.h>
index cc38fa0d45c6910747d77734226aa568f72b761f..f67d5d6eb9a68aa1f290b4e580429c13017cd5c1 100644 (file)
@@ -12,6 +12,8 @@
 #include <linux/kernel.h>
 #include <linux/module.h>
 #include <linux/init.h>
+#include <linux/sched.h>
+#include <linux/jiffies.h>
 #include <linux/mtd/mtd.h>
 #include <linux/mtd/onenand.h>
 #include <linux/mtd/partitions.h>
index 041ee59ea77dca661b547d86088e5fe9e7d16ff1..0ab8d29caeea07ecaf4e0434cfa7b2fd512496e7 100644 (file)
@@ -18,6 +18,7 @@
 #include <linux/mtd/blktrans.h>
 #include <linux/mtd/mtd.h>
 #include <linux/vmalloc.h>
+#include <linux/jiffies.h>
 
 #include <asm/types.h>
 
index e70315a85447c95b3cabb27b2587751ef5dbfd10..5c69d57f8548aa41b84f45e5cf2101fa80f47d64 100644 (file)
@@ -2523,6 +2523,19 @@ config PPP_BSDCOMP
          module; it is called bsd_comp and will show up in the directory
          modules once you have said "make modules". If unsure, say N.
 
+config PPP_MPPE
+       tristate "PPP MPPE compression (encryption) (EXPERIMENTAL)"
+       depends on PPP && EXPERIMENTAL
+       select CRYPTO
+       select CRYPTO_SHA1
+       select CRYPTO_ARC4
+       ---help---
+         Support for the MPPE Encryption protocol, as employed by the
+        Microsoft Point-to-Point Tunneling Protocol.
+
+        See http://pptpclient.sourceforge.net/ for information on
+        configuring PPTP clients and servers to utilize this method.
+
 config PPPOE
        tristate "PPP over Ethernet (EXPERIMENTAL)"
        depends on EXPERIMENTAL && PPP
index 7c313cb341b8874866b9f279141f70d6ed8d8d6a..4cffd34442aafaddc00865df86c26f410ccd61a2 100644 (file)
@@ -112,6 +112,7 @@ obj-$(CONFIG_PPP_ASYNC) += ppp_async.o
 obj-$(CONFIG_PPP_SYNC_TTY) += ppp_synctty.o
 obj-$(CONFIG_PPP_DEFLATE) += ppp_deflate.o
 obj-$(CONFIG_PPP_BSDCOMP) += bsd_comp.o
+obj-$(CONFIG_PPP_MPPE) += ppp_mppe.o
 obj-$(CONFIG_PPPOE) += pppox.o pppoe.o
 
 obj-$(CONFIG_SLIP) += slip.o
index b38fa245a607f417c17cac0b645e7f906ab5a84a..c53848f787ebb600632d4f8b05964de4b7b919dd 100644 (file)
@@ -18,7 +18,6 @@
 #include <linux/pci.h>
 #include <linux/delay.h>
 #include <linux/init.h>
-#include <linux/version.h>
 #include <linux/dma-mapping.h>
 
 #include <asm/uaccess.h>
index 50f43dbf31aed4c8313e72c3ef08729407be1a95..1f7ca453bb4a28c48a5e44da3024df4b8facdb5c 100644 (file)
@@ -67,7 +67,6 @@
  */
 
 #include <linux/config.h>
-#include <linux/version.h>
 
 #include <linux/module.h>
 #include <linux/kernel.h>
index c0af6fb1fbba210c3139bb18f66ad7960afd8780..f8c9bcdab68beca268889ad07e005848e597a623 100644 (file)
@@ -60,7 +60,6 @@
 #include <linux/etherdevice.h>
 #include <linux/init.h>
 #include <linux/skbuff.h>
-#include <linux/version.h>
 #include <linux/spinlock.h>
 #include <linux/crc32.h>
 #include <linux/mii.h>
index 1105543b9d888d664ff0a7dfe24f1d26fa6177cd..e7ec96c964a9fa0a3c2ee2a6f87a9badf46aef28 100644 (file)
@@ -4,7 +4,6 @@
 #include <linux/mii.h>
 #include <linux/netdevice.h>
 #include <linux/types.h>
-#include <linux/version.h>
 #include <linux/list.h>
 
 #include <linux/fs_enet_pd.h>
index 962580f2c4abb2b5fbdcf21e35db626df2400946..54d294ad6df59f4f8d75b9a0a19958e0bf3493d2 100644 (file)
@@ -90,7 +90,6 @@
 #include <asm/irq.h>
 #include <asm/uaccess.h>
 #include <linux/module.h>
-#include <linux/version.h>
 #include <linux/dma-mapping.h>
 #include <linux/crc32.h>
 #include <linux/mii.h>
index c77ca6c0d04a6d651c0e3d37ca749146b5e9bc5c..220084e53341ddce82122a82489328bd95013bbe 100644 (file)
@@ -43,7 +43,6 @@
 #include <asm/irq.h>
 #include <asm/uaccess.h>
 #include <linux/module.h>
-#include <linux/version.h>
 #include <linux/crc32.h>
 #include <linux/workqueue.h>
 #include <linux/ethtool.h>
index 68e3578e76133b8783b5dcfa1db03367c5e0d9ac..5a2d810ce57538534dba620dfdb9b547c7096cc4 100644 (file)
@@ -34,7 +34,6 @@
 #include <asm/irq.h>
 #include <asm/uaccess.h>
 #include <linux/module.h>
-#include <linux/version.h>
 #include <linux/crc32.h>
 #include <asm/types.h>
 #include <asm/uaccess.h>
index 5a74d3d3dbe1763befa68f4823ba4d7797def74d..7263395d78bbb6e3ccbf1f128b083f2f7abd16f7 100644 (file)
@@ -32,7 +32,6 @@
 #include <linux/spinlock.h>
 #include <linux/mm.h>
 #include <linux/module.h>
-#include <linux/version.h>
 #include <linux/platform_device.h>
 #include <asm/ocp.h>
 #include <linux/crc32.h>
index b71fab6e34f4268e0dc53ad9d675cac3f998309a..e92c17f6931c0e06ddb717231607a6f786fee83a 100644 (file)
@@ -96,7 +96,6 @@
 
 #undef HP100_MULTICAST_FILTER  /* Need to be debugged... */
 
-#include <linux/version.h>
 #include <linux/module.h>
 #include <linux/kernel.h>
 #include <linux/string.h>
index 94239f67f3a361b840067b939b8d23d2d8b4bdaf..be191d80ef9c3984e6ce0473762bbc7fc364e5b2 100644 (file)
@@ -35,7 +35,6 @@
 
 #include <linux/config.h>
 #include <linux/module.h>
-#include <linux/version.h>
 #include <linux/types.h>
 #include <linux/errno.h>
 #include <linux/ioport.h>
index 49e5467bdd7336a34dc9cb5bd5928291c683b408..6a3129bc15a6d6327c5dec32f8e518049e6c5787 100644 (file)
 #include <linux/udp.h>
 
 #ifdef CONFIG_SERIAL_8250
-#include <linux/serial.h>
-#include <asm/serial.h>
-#define IOC3_BAUD (22000000 / (3*16))
-#define IOC3_COM_FLAGS (ASYNC_BOOT_AUTOCONF | ASYNC_SKIP_TEST)
+#include <linux/serial_core.h>
+#include <linux/serial_8250.h>
 #endif
 
 #include <linux/netdevice.h>
@@ -1146,12 +1144,11 @@ static inline int ioc3_is_menet(struct pci_dev *pdev)
  * around ioc3 oddities in this respect.
  *
  * The IOC3 serials use a 22MHz clock rate with an additional divider by 3.
- * (IOC3_BAUD = (22000000 / (3*16)))
  */
 
 static void __devinit ioc3_serial_probe(struct pci_dev *pdev, struct ioc3 *ioc3)
 {
-       struct serial_struct req;
+       struct uart_port port;
 
        /*
         * We need to recognice and treat the fourth MENET serial as it
@@ -1165,20 +1162,25 @@ static void __devinit ioc3_serial_probe(struct pci_dev *pdev, struct ioc3 *ioc3)
        if (ioc3_is_menet(pdev) && PCI_SLOT(pdev->devfn) == 3)
                return;
 
-       /* Register to interrupt zero because we share the interrupt with
-          the serial driver which we don't properly support yet.  */
-       memset(&req, 0, sizeof(req));
-       req.irq             = 0;
-       req.flags           = IOC3_COM_FLAGS;
-       req.io_type         = SERIAL_IO_MEM;
-       req.iomem_reg_shift = 0;
-       req.baud_base       = IOC3_BAUD;
-
-       req.iomem_base      = (unsigned char *) &ioc3->sregs.uarta;
-       register_serial(&req);
-
-       req.iomem_base      = (unsigned char *) &ioc3->sregs.uartb;
-       register_serial(&req);
+       /*
+        * Register to interrupt zero because we share the interrupt with
+        * the serial driver which we don't properly support yet.
+        *
+        * Can't use UPF_IOREMAP as the whole of IOC3 resources have already
+        * been registered.
+        */
+       memset(&port, 0, sizeof(port));
+       port.irq      = 0;
+       port.flags    = UPF_SKIP_TEST | UPF_BOOT_AUTOCONF;
+       port.iotype   = UPIO_MEM;
+       port.regshift = 0;
+       port.uartclk  = 22000000 / 3;
+
+       port.membase  = (unsigned char *) &ioc3->sregs.uarta;
+       serial8250_register_port(&port);
+
+       port.membase  = (unsigned char *) &ioc3->sregs.uartb;
+       serial8250_register_port(&port);
 }
 #endif
 
index 0282771b1cbb3ca27d625c0b8b60dc8810672fcb..3137592d60c01816f3bb03bb0d4bd05227432f99 100644 (file)
@@ -1459,8 +1459,10 @@ toshoboe_net_ioctl (struct net_device *dev, struct ifreq *rq, int cmd)
        */
       IRDA_DEBUG (1, "%s(BANDWIDTH), %s, (%X/%ld\n", __FUNCTION__
           ,dev->name, INB (OBOE_STATUS), irq->ifr_baudrate );
-      if (!in_interrupt () && !capable (CAP_NET_ADMIN))
-        return -EPERM;
+      if (!in_interrupt () && !capable (CAP_NET_ADMIN)) {
+       ret = -EPERM;
+       goto out;
+      }
 
       /* self->speed=irq->ifr_baudrate; */
       /* toshoboe_setbaud(self); */
@@ -1470,8 +1472,10 @@ toshoboe_net_ioctl (struct net_device *dev, struct ifreq *rq, int cmd)
     case SIOCSMEDIABUSY:       /* Set media busy */
       IRDA_DEBUG (1, "%s(MEDIABUSY), %s, (%X/%x)\n", __FUNCTION__
           ,dev->name, INB (OBOE_STATUS), capable (CAP_NET_ADMIN) );
-      if (!capable (CAP_NET_ADMIN))
-        return -EPERM;
+      if (!capable (CAP_NET_ADMIN)) {
+       ret = -EPERM;
+       goto out;
+      }
       irda_device_set_media_busy (self->netdev, TRUE);
       break;
     case SIOCGRECEIVING:       /* Check if we are receiving right now */
@@ -1483,7 +1487,7 @@ toshoboe_net_ioctl (struct net_device *dev, struct ifreq *rq, int cmd)
       IRDA_DEBUG (1, "%s(?), %s, (cmd=0x%X)\n", __FUNCTION__, dev->name, cmd);
       ret = -EOPNOTSUPP;
     }
-
+out:
   spin_unlock_irqrestore(&self->spinlock, flags);
   return ret;
 
index d86d8f055a6cd7d12330237baec71550230e4609..77eadf84cb2cb7895597180ce5f35e77b34d2d0c 100644 (file)
@@ -58,7 +58,6 @@
 
 #include <linux/config.h>
 #include <linux/module.h>
-#include <linux/version.h>
 #include <linux/types.h>
 #include <linux/errno.h>
 #include <linux/ioport.h>
index ce5761816a64db16867085e3cb7ab11ae70142ed..d8c99f038fa0a7ce07400af7ef8352126b9167be 100644 (file)
@@ -15,7 +15,6 @@
  * and fixed access to Sonic Sys card which masquerades as a Farallon 
  * by rayk@knightsmanor.org */
 
-#include <linux/version.h>
 #include <linux/module.h>
 #include <linux/kernel.h>
 #include <linux/types.h>
index bcfda5192da02ef83fbe86e9a61c6a375221984b..f769f9b626ea96f7eddfbe3904f570cedf5bb2af 100644 (file)
@@ -1,7 +1,6 @@
 #ifndef __MV643XX_ETH_H__
 #define __MV643XX_ETH_H__
 
-#include <linux/version.h>
 #include <linux/module.h>
 #include <linux/kernel.h>
 #include <linux/spinlock.h>
index 59e8183c639e0be7e9a07dc9c8295d5bd78281e6..400f652282d76f4fe7c0d003ca0ec1f22d3da27f 100644 (file)
@@ -31,6 +31,7 @@
 #include <linux/spinlock.h>
 #include <linux/init.h>
 #include <asm/uaccess.h>
+#include <asm/string.h>
 
 #define PPP_VERSION    "2.4.2"
 
@@ -835,8 +836,11 @@ process_input_packet(struct asyncppp *ap)
  err:
        /* frame had an error, remember that, reset SC_TOSS & SC_ESCAPE */
        ap->state = SC_PREV_ERROR;
-       if (skb)
+       if (skb) {
+               /* make skb appear as freshly allocated */
                skb_trim(skb, 0);
+               skb_reserve(skb, - skb_headroom(skb));
+       }
 }
 
 /* Called when the tty driver has data for us. Runs parallel with the
@@ -889,10 +893,17 @@ ppp_async_input(struct asyncppp *ap, const unsigned char *buf,
                                skb = dev_alloc_skb(ap->mru + PPP_HDRLEN + 2);
                                if (skb == 0)
                                        goto nomem;
-                               /* Try to get the payload 4-byte aligned */
+                               ap->rpkt = skb;
+                       }
+                       if (skb->len == 0) {
+                               /* Try to get the payload 4-byte aligned.
+                                * This should match the
+                                * PPP_ALLSTATIONS/PPP_UI/compressed tests in
+                                * process_input_packet, but we do not have
+                                * enough chars here to test buf[1] and buf[2].
+                                */
                                if (buf[0] != PPP_ALLSTATIONS)
                                        skb_reserve(skb, 2 + (buf[0] & 1));
-                               ap->rpkt = skb;
                        }
                        if (n > skb_tailroom(skb)) {
                                /* packet overflowed MRU */
index d3c9958b00d06db4895a7d6e2b54a58726c2e088..50430f79f8cf8190541e47495d625cae0cd7a765 100644 (file)
@@ -137,13 +137,14 @@ struct ppp {
 
 /*
  * Bits in flags: SC_NO_TCP_CCID, SC_CCP_OPEN, SC_CCP_UP, SC_LOOP_TRAFFIC,
- * SC_MULTILINK, SC_MP_SHORTSEQ, SC_MP_XSHORTSEQ, SC_COMP_TCP, SC_REJ_COMP_TCP.
+ * SC_MULTILINK, SC_MP_SHORTSEQ, SC_MP_XSHORTSEQ, SC_COMP_TCP, SC_REJ_COMP_TCP,
+ * SC_MUST_COMP
  * Bits in rstate: SC_DECOMP_RUN, SC_DC_ERROR, SC_DC_FERROR.
  * Bits in xstate: SC_COMP_RUN
  */
 #define SC_FLAG_BITS   (SC_NO_TCP_CCID|SC_CCP_OPEN|SC_CCP_UP|SC_LOOP_TRAFFIC \
                         |SC_MULTILINK|SC_MP_SHORTSEQ|SC_MP_XSHORTSEQ \
-                        |SC_COMP_TCP|SC_REJ_COMP_TCP)
+                        |SC_COMP_TCP|SC_REJ_COMP_TCP|SC_MUST_COMP)
 
 /*
  * Private data structure for each channel.
@@ -1027,6 +1028,56 @@ ppp_xmit_process(struct ppp *ppp)
        ppp_xmit_unlock(ppp);
 }
 
+static inline struct sk_buff *
+pad_compress_skb(struct ppp *ppp, struct sk_buff *skb)
+{
+       struct sk_buff *new_skb;
+       int len;
+       int new_skb_size = ppp->dev->mtu +
+               ppp->xcomp->comp_extra + ppp->dev->hard_header_len;
+       int compressor_skb_size = ppp->dev->mtu +
+               ppp->xcomp->comp_extra + PPP_HDRLEN;
+       new_skb = alloc_skb(new_skb_size, GFP_ATOMIC);
+       if (!new_skb) {
+               if (net_ratelimit())
+                       printk(KERN_ERR "PPP: no memory (comp pkt)\n");
+               return NULL;
+       }
+       if (ppp->dev->hard_header_len > PPP_HDRLEN)
+               skb_reserve(new_skb,
+                           ppp->dev->hard_header_len - PPP_HDRLEN);
+
+       /* compressor still expects A/C bytes in hdr */
+       len = ppp->xcomp->compress(ppp->xc_state, skb->data - 2,
+                                  new_skb->data, skb->len + 2,
+                                  compressor_skb_size);
+       if (len > 0 && (ppp->flags & SC_CCP_UP)) {
+               kfree_skb(skb);
+               skb = new_skb;
+               skb_put(skb, len);
+               skb_pull(skb, 2);       /* pull off A/C bytes */
+       } else if (len == 0) {
+               /* didn't compress, or CCP not up yet */
+               kfree_skb(new_skb);
+               new_skb = skb;
+       } else {
+               /*
+                * (len < 0)
+                * MPPE requires that we do not send unencrypted
+                * frames.  The compressor will return -1 if we
+                * should drop the frame.  We cannot simply test
+                * the compress_proto because MPPE and MPPC share
+                * the same number.
+                */
+               if (net_ratelimit())
+                       printk(KERN_ERR "ppp: compressor dropped pkt\n");
+               kfree_skb(skb);
+               kfree_skb(new_skb);
+               new_skb = NULL;
+       }
+       return new_skb;
+}
+
 /*
  * Compress and send a frame.
  * The caller should have locked the xmit path,
@@ -1113,29 +1164,14 @@ ppp_send_frame(struct ppp *ppp, struct sk_buff *skb)
        /* try to do packet compression */
        if ((ppp->xstate & SC_COMP_RUN) && ppp->xc_state != 0
            && proto != PPP_LCP && proto != PPP_CCP) {
-               new_skb = alloc_skb(ppp->dev->mtu + ppp->dev->hard_header_len,
-                                   GFP_ATOMIC);
-               if (new_skb == 0) {
-                       printk(KERN_ERR "PPP: no memory (comp pkt)\n");
+               if (!(ppp->flags & SC_CCP_UP) && (ppp->flags & SC_MUST_COMP)) {
+                       if (net_ratelimit())
+                               printk(KERN_ERR "ppp: compression required but down - pkt dropped.\n");
                        goto drop;
                }
-               if (ppp->dev->hard_header_len > PPP_HDRLEN)
-                       skb_reserve(new_skb,
-                                   ppp->dev->hard_header_len - PPP_HDRLEN);
-
-               /* compressor still expects A/C bytes in hdr */
-               len = ppp->xcomp->compress(ppp->xc_state, skb->data - 2,
-                                          new_skb->data, skb->len + 2,
-                                          ppp->dev->mtu + PPP_HDRLEN);
-               if (len > 0 && (ppp->flags & SC_CCP_UP)) {
-                       kfree_skb(skb);
-                       skb = new_skb;
-                       skb_put(skb, len);
-                       skb_pull(skb, 2);       /* pull off A/C bytes */
-               } else {
-                       /* didn't compress, or CCP not up yet */
-                       kfree_skb(new_skb);
-               }
+               skb = pad_compress_skb(ppp, skb);
+               if (!skb)
+                       goto drop;
        }
 
        /*
@@ -1155,7 +1191,8 @@ ppp_send_frame(struct ppp *ppp, struct sk_buff *skb)
        return;
 
  drop:
-       kfree_skb(skb);
+       if (skb)
+               kfree_skb(skb);
        ++ppp->stats.tx_errors;
 }
 
@@ -1552,6 +1589,9 @@ ppp_receive_nonmp_frame(struct ppp *ppp, struct sk_buff *skb)
            && (ppp->rstate & (SC_DC_FERROR | SC_DC_ERROR)) == 0)
                skb = ppp_decompress_frame(ppp, skb);
 
+       if (ppp->flags & SC_MUST_COMP && ppp->rstate & SC_DC_FERROR)
+               goto err;
+
        proto = PPP_PROTO(skb);
        switch (proto) {
        case PPP_VJC_COMP:
diff --git a/drivers/net/ppp_mppe.c b/drivers/net/ppp_mppe.c
new file mode 100644 (file)
index 0000000..1985d1b
--- /dev/null
@@ -0,0 +1,724 @@
+/*
+ * ppp_mppe.c - interface MPPE to the PPP code.
+ * This version is for use with Linux kernel 2.6.14+
+ *
+ * By Frank Cusack <fcusack@fcusack.com>.
+ * Copyright (c) 2002,2003,2004 Google, Inc.
+ * All rights reserved.
+ *
+ * License:
+ * Permission to use, copy, modify, and distribute this software and its
+ * documentation is hereby granted, provided that the above copyright
+ * notice appears in all copies.  This software is provided without any
+ * warranty, express or implied.
+ *
+ * ALTERNATIVELY, provided that this notice is retained in full, this product
+ * may be distributed under the terms of the GNU General Public License (GPL),
+ * in which case the provisions of the GPL apply INSTEAD OF those given above.
+ *
+ *   This program is free software; you can redistribute it and/or modify
+ *   it under the terms of the GNU General Public License as published by
+ *   the Free Software Foundation; either version 2 of the License, or
+ *   (at your option) any later version.
+ *
+ *   This program is distributed in the hope that it will be useful,
+ *   but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *   GNU General Public License for more details.
+ *
+ *   You should have received a copy of the GNU General Public License
+ *   along with this program; if not, write to the Free Software
+ *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ *
+ * Changelog:
+ *      08/12/05 - Matt Domsch <Matt_Domsch@dell.com>
+ *                 Only need extra skb padding on transmit, not receive.
+ *      06/18/04 - Matt Domsch <Matt_Domsch@dell.com>, Oleg Makarenko <mole@quadra.ru>
+ *                 Use Linux kernel 2.6 arc4 and sha1 routines rather than
+ *                 providing our own.
+ *      2/15/04 - TS: added #include <version.h> and testing for Kernel
+ *                    version before using
+ *                    MOD_DEC_USAGE_COUNT/MOD_INC_USAGE_COUNT which are
+ *                    deprecated in 2.6
+ */
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/version.h>
+#include <linux/init.h>
+#include <linux/types.h>
+#include <linux/slab.h>
+#include <linux/string.h>
+#include <linux/crypto.h>
+#include <linux/mm.h>
+#include <linux/ppp_defs.h>
+#include <linux/ppp-comp.h>
+#include <asm/scatterlist.h>
+
+#include "ppp_mppe.h"
+
+MODULE_AUTHOR("Frank Cusack <fcusack@fcusack.com>");
+MODULE_DESCRIPTION("Point-to-Point Protocol Microsoft Point-to-Point Encryption support");
+MODULE_LICENSE("Dual BSD/GPL");
+MODULE_ALIAS("ppp-compress-" __stringify(CI_MPPE));
+MODULE_VERSION("1.0.2");
+
+static void
+setup_sg(struct scatterlist *sg, const void *address, unsigned int length)
+{
+       sg[0].page = virt_to_page(address);
+       sg[0].offset = offset_in_page(address);
+       sg[0].length = length;
+}
+
+#define SHA1_PAD_SIZE 40
+
+/*
+ * kernel crypto API needs its arguments to be in kmalloc'd memory, not in the module
+ * static data area.  That means sha_pad needs to be kmalloc'd.
+ */
+
+struct sha_pad {
+       unsigned char sha_pad1[SHA1_PAD_SIZE];
+       unsigned char sha_pad2[SHA1_PAD_SIZE];
+};
+static struct sha_pad *sha_pad;
+
+static inline void sha_pad_init(struct sha_pad *shapad)
+{
+       memset(shapad->sha_pad1, 0x00, sizeof(shapad->sha_pad1));
+       memset(shapad->sha_pad2, 0xF2, sizeof(shapad->sha_pad2));
+}
+
+/*
+ * State for an MPPE (de)compressor.
+ */
+struct ppp_mppe_state {
+       struct crypto_tfm *arc4;
+       struct crypto_tfm *sha1;
+       unsigned char *sha1_digest;
+       unsigned char master_key[MPPE_MAX_KEY_LEN];
+       unsigned char session_key[MPPE_MAX_KEY_LEN];
+       unsigned keylen;        /* key length in bytes             */
+       /* NB: 128-bit == 16, 40-bit == 8! */
+       /* If we want to support 56-bit,   */
+       /* the unit has to change to bits  */
+       unsigned char bits;     /* MPPE control bits */
+       unsigned ccount;        /* 12-bit coherency count (seqno)  */
+       unsigned stateful;      /* stateful mode flag */
+       int discard;            /* stateful mode packet loss flag */
+       int sanity_errors;      /* take down LCP if too many */
+       int unit;
+       int debug;
+       struct compstat stats;
+};
+
+/* struct ppp_mppe_state.bits definitions */
+#define MPPE_BIT_A     0x80    /* Encryption table were (re)inititalized */
+#define MPPE_BIT_B     0x40    /* MPPC only (not implemented) */
+#define MPPE_BIT_C     0x20    /* MPPC only (not implemented) */
+#define MPPE_BIT_D     0x10    /* This is an encrypted frame */
+
+#define MPPE_BIT_FLUSHED       MPPE_BIT_A
+#define MPPE_BIT_ENCRYPTED     MPPE_BIT_D
+
+#define MPPE_BITS(p) ((p)[4] & 0xf0)
+#define MPPE_CCOUNT(p) ((((p)[4] & 0x0f) << 8) + (p)[5])
+#define MPPE_CCOUNT_SPACE 0x1000       /* The size of the ccount space */
+
+#define MPPE_OVHD      2       /* MPPE overhead/packet */
+#define SANITY_MAX     1600    /* Max bogon factor we will tolerate */
+
+/*
+ * Key Derivation, from RFC 3078, RFC 3079.
+ * Equivalent to Get_Key() for MS-CHAP as described in RFC 3079.
+ */
+static void get_new_key_from_sha(struct ppp_mppe_state * state, unsigned char *InterimKey)
+{
+       struct scatterlist sg[4];
+
+       setup_sg(&sg[0], state->master_key, state->keylen);
+       setup_sg(&sg[1], sha_pad->sha_pad1, sizeof(sha_pad->sha_pad1));
+       setup_sg(&sg[2], state->session_key, state->keylen);
+       setup_sg(&sg[3], sha_pad->sha_pad2, sizeof(sha_pad->sha_pad2));
+
+       crypto_digest_digest (state->sha1, sg, 4, state->sha1_digest);
+
+       memcpy(InterimKey, state->sha1_digest, state->keylen);
+}
+
+/*
+ * Perform the MPPE rekey algorithm, from RFC 3078, sec. 7.3.
+ * Well, not what's written there, but rather what they meant.
+ */
+static void mppe_rekey(struct ppp_mppe_state * state, int initial_key)
+{
+       unsigned char InterimKey[MPPE_MAX_KEY_LEN];
+       struct scatterlist sg_in[1], sg_out[1];
+
+       get_new_key_from_sha(state, InterimKey);
+       if (!initial_key) {
+               crypto_cipher_setkey(state->arc4, InterimKey, state->keylen);
+               setup_sg(sg_in, InterimKey, state->keylen);
+               setup_sg(sg_out, state->session_key, state->keylen);
+               if (crypto_cipher_encrypt(state->arc4, sg_out, sg_in,
+                                     state->keylen) != 0) {
+                   printk(KERN_WARNING "mppe_rekey: cipher_encrypt failed\n");
+               }
+       } else {
+               memcpy(state->session_key, InterimKey, state->keylen);
+       }
+       if (state->keylen == 8) {
+               /* See RFC 3078 */
+               state->session_key[0] = 0xd1;
+               state->session_key[1] = 0x26;
+               state->session_key[2] = 0x9e;
+       }
+       crypto_cipher_setkey(state->arc4, state->session_key, state->keylen);
+}
+
+/*
+ * Allocate space for a (de)compressor.
+ */
+static void *mppe_alloc(unsigned char *options, int optlen)
+{
+       struct ppp_mppe_state *state;
+       unsigned int digestsize;
+
+       if (optlen != CILEN_MPPE + sizeof(state->master_key)
+           || options[0] != CI_MPPE || options[1] != CILEN_MPPE)
+               goto out;
+
+       state = (struct ppp_mppe_state *) kmalloc(sizeof(*state), GFP_KERNEL);
+       if (state == NULL)
+               goto out;
+
+       memset(state, 0, sizeof(*state));
+
+       state->arc4 = crypto_alloc_tfm("arc4", 0);
+       if (!state->arc4)
+               goto out_free;
+
+       state->sha1 = crypto_alloc_tfm("sha1", 0);
+       if (!state->sha1)
+               goto out_free;
+
+       digestsize = crypto_tfm_alg_digestsize(state->sha1);
+       if (digestsize < MPPE_MAX_KEY_LEN)
+               goto out_free;
+
+       state->sha1_digest = kmalloc(digestsize, GFP_KERNEL);
+       if (!state->sha1_digest)
+               goto out_free;
+
+       /* Save keys. */
+       memcpy(state->master_key, &options[CILEN_MPPE],
+              sizeof(state->master_key));
+       memcpy(state->session_key, state->master_key,
+              sizeof(state->master_key));
+
+       /*
+        * We defer initial key generation until mppe_init(), as mppe_alloc()
+        * is called frequently during negotiation.
+        */
+
+       return (void *)state;
+
+       out_free:
+           if (state->sha1_digest)
+               kfree(state->sha1_digest);
+           if (state->sha1)
+               crypto_free_tfm(state->sha1);
+           if (state->arc4)
+               crypto_free_tfm(state->arc4);
+           kfree(state);
+       out:
+       return NULL;
+}
+
+/*
+ * Deallocate space for a (de)compressor.
+ */
+static void mppe_free(void *arg)
+{
+       struct ppp_mppe_state *state = (struct ppp_mppe_state *) arg;
+       if (state) {
+           if (state->sha1_digest)
+               kfree(state->sha1_digest);
+           if (state->sha1)
+               crypto_free_tfm(state->sha1);
+           if (state->arc4)
+               crypto_free_tfm(state->arc4);
+           kfree(state);
+       }
+}
+
+/*
+ * Initialize (de)compressor state.
+ */
+static int
+mppe_init(void *arg, unsigned char *options, int optlen, int unit, int debug,
+         const char *debugstr)
+{
+       struct ppp_mppe_state *state = (struct ppp_mppe_state *) arg;
+       unsigned char mppe_opts;
+
+       if (optlen != CILEN_MPPE
+           || options[0] != CI_MPPE || options[1] != CILEN_MPPE)
+               return 0;
+
+       MPPE_CI_TO_OPTS(&options[2], mppe_opts);
+       if (mppe_opts & MPPE_OPT_128)
+               state->keylen = 16;
+       else if (mppe_opts & MPPE_OPT_40)
+               state->keylen = 8;
+       else {
+               printk(KERN_WARNING "%s[%d]: unknown key length\n", debugstr,
+                      unit);
+               return 0;
+       }
+       if (mppe_opts & MPPE_OPT_STATEFUL)
+               state->stateful = 1;
+
+       /* Generate the initial session key. */
+       mppe_rekey(state, 1);
+
+       if (debug) {
+               int i;
+               char mkey[sizeof(state->master_key) * 2 + 1];
+               char skey[sizeof(state->session_key) * 2 + 1];
+
+               printk(KERN_DEBUG "%s[%d]: initialized with %d-bit %s mode\n",
+                      debugstr, unit, (state->keylen == 16) ? 128 : 40,
+                      (state->stateful) ? "stateful" : "stateless");
+
+               for (i = 0; i < sizeof(state->master_key); i++)
+                       sprintf(mkey + i * 2, "%02x", state->master_key[i]);
+               for (i = 0; i < sizeof(state->session_key); i++)
+                       sprintf(skey + i * 2, "%02x", state->session_key[i]);
+               printk(KERN_DEBUG
+                      "%s[%d]: keys: master: %s initial session: %s\n",
+                      debugstr, unit, mkey, skey);
+       }
+
+       /*
+        * Initialize the coherency count.  The initial value is not specified
+        * in RFC 3078, but we can make a reasonable assumption that it will
+        * start at 0.  Setting it to the max here makes the comp/decomp code
+        * do the right thing (determined through experiment).
+        */
+       state->ccount = MPPE_CCOUNT_SPACE - 1;
+
+       /*
+        * Note that even though we have initialized the key table, we don't
+        * set the FLUSHED bit.  This is contrary to RFC 3078, sec. 3.1.
+        */
+       state->bits = MPPE_BIT_ENCRYPTED;
+
+       state->unit = unit;
+       state->debug = debug;
+
+       return 1;
+}
+
+static int
+mppe_comp_init(void *arg, unsigned char *options, int optlen, int unit,
+              int hdrlen, int debug)
+{
+       /* ARGSUSED */
+       return mppe_init(arg, options, optlen, unit, debug, "mppe_comp_init");
+}
+
+/*
+ * We received a CCP Reset-Request (actually, we are sending a Reset-Ack),
+ * tell the compressor to rekey.  Note that we MUST NOT rekey for
+ * every CCP Reset-Request; we only rekey on the next xmit packet.
+ * We might get multiple CCP Reset-Requests if our CCP Reset-Ack is lost.
+ * So, rekeying for every CCP Reset-Request is broken as the peer will not
+ * know how many times we've rekeyed.  (If we rekey and THEN get another
+ * CCP Reset-Request, we must rekey again.)
+ */
+static void mppe_comp_reset(void *arg)
+{
+       struct ppp_mppe_state *state = (struct ppp_mppe_state *) arg;
+
+       state->bits |= MPPE_BIT_FLUSHED;
+}
+
+/*
+ * Compress (encrypt) a packet.
+ * It's strange to call this a compressor, since the output is always
+ * MPPE_OVHD + 2 bytes larger than the input.
+ */
+static int
+mppe_compress(void *arg, unsigned char *ibuf, unsigned char *obuf,
+             int isize, int osize)
+{
+       struct ppp_mppe_state *state = (struct ppp_mppe_state *) arg;
+       int proto;
+       struct scatterlist sg_in[1], sg_out[1];
+
+       /*
+        * Check that the protocol is in the range we handle.
+        */
+       proto = PPP_PROTOCOL(ibuf);
+       if (proto < 0x0021 || proto > 0x00fa)
+               return 0;
+
+       /* Make sure we have enough room to generate an encrypted packet. */
+       if (osize < isize + MPPE_OVHD + 2) {
+               /* Drop the packet if we should encrypt it, but can't. */
+               printk(KERN_DEBUG "mppe_compress[%d]: osize too small! "
+                      "(have: %d need: %d)\n", state->unit,
+                      osize, osize + MPPE_OVHD + 2);
+               return -1;
+       }
+
+       osize = isize + MPPE_OVHD + 2;
+
+       /*
+        * Copy over the PPP header and set control bits.
+        */
+       obuf[0] = PPP_ADDRESS(ibuf);
+       obuf[1] = PPP_CONTROL(ibuf);
+       obuf[2] = PPP_COMP >> 8;        /* isize + MPPE_OVHD + 1 */
+       obuf[3] = PPP_COMP;     /* isize + MPPE_OVHD + 2 */
+       obuf += PPP_HDRLEN;
+
+       state->ccount = (state->ccount + 1) % MPPE_CCOUNT_SPACE;
+       if (state->debug >= 7)
+               printk(KERN_DEBUG "mppe_compress[%d]: ccount %d\n", state->unit,
+                      state->ccount);
+       obuf[0] = state->ccount >> 8;
+       obuf[1] = state->ccount & 0xff;
+
+       if (!state->stateful || /* stateless mode     */
+           ((state->ccount & 0xff) == 0xff) || /* "flag" packet      */
+           (state->bits & MPPE_BIT_FLUSHED)) { /* CCP Reset-Request  */
+               /* We must rekey */
+               if (state->debug && state->stateful)
+                       printk(KERN_DEBUG "mppe_compress[%d]: rekeying\n",
+                              state->unit);
+               mppe_rekey(state, 0);
+               state->bits |= MPPE_BIT_FLUSHED;
+       }
+       obuf[0] |= state->bits;
+       state->bits &= ~MPPE_BIT_FLUSHED;       /* reset for next xmit */
+
+       obuf += MPPE_OVHD;
+       ibuf += 2;              /* skip to proto field */
+       isize -= 2;
+
+       /* Encrypt packet */
+       setup_sg(sg_in, ibuf, isize);
+       setup_sg(sg_out, obuf, osize);
+       if (crypto_cipher_encrypt(state->arc4, sg_out, sg_in, isize) != 0) {
+               printk(KERN_DEBUG "crypto_cypher_encrypt failed\n");
+               return -1;
+       }
+
+       state->stats.unc_bytes += isize;
+       state->stats.unc_packets++;
+       state->stats.comp_bytes += osize;
+       state->stats.comp_packets++;
+
+       return osize;
+}
+
+/*
+ * Since every frame grows by MPPE_OVHD + 2 bytes, this is always going
+ * to look bad ... and the longer the link is up the worse it will get.
+ */
+static void mppe_comp_stats(void *arg, struct compstat *stats)
+{
+       struct ppp_mppe_state *state = (struct ppp_mppe_state *) arg;
+
+       *stats = state->stats;
+}
+
+static int
+mppe_decomp_init(void *arg, unsigned char *options, int optlen, int unit,
+                int hdrlen, int mru, int debug)
+{
+       /* ARGSUSED */
+       return mppe_init(arg, options, optlen, unit, debug, "mppe_decomp_init");
+}
+
+/*
+ * We received a CCP Reset-Ack.  Just ignore it.
+ */
+static void mppe_decomp_reset(void *arg)
+{
+       /* ARGSUSED */
+       return;
+}
+
+/*
+ * Decompress (decrypt) an MPPE packet.
+ */
+static int
+mppe_decompress(void *arg, unsigned char *ibuf, int isize, unsigned char *obuf,
+               int osize)
+{
+       struct ppp_mppe_state *state = (struct ppp_mppe_state *) arg;
+       unsigned ccount;
+       int flushed = MPPE_BITS(ibuf) & MPPE_BIT_FLUSHED;
+       int sanity = 0;
+       struct scatterlist sg_in[1], sg_out[1];
+
+       if (isize <= PPP_HDRLEN + MPPE_OVHD) {
+               if (state->debug)
+                       printk(KERN_DEBUG
+                              "mppe_decompress[%d]: short pkt (%d)\n",
+                              state->unit, isize);
+               return DECOMP_ERROR;
+       }
+
+       /*
+        * Make sure we have enough room to decrypt the packet.
+        * Note that for our test we only subtract 1 byte whereas in
+        * mppe_compress() we added 2 bytes (+MPPE_OVHD);
+        * this is to account for possible PFC.
+        */
+       if (osize < isize - MPPE_OVHD - 1) {
+               printk(KERN_DEBUG "mppe_decompress[%d]: osize too small! "
+                      "(have: %d need: %d)\n", state->unit,
+                      osize, isize - MPPE_OVHD - 1);
+               return DECOMP_ERROR;
+       }
+       osize = isize - MPPE_OVHD - 2;  /* assume no PFC */
+
+       ccount = MPPE_CCOUNT(ibuf);
+       if (state->debug >= 7)
+               printk(KERN_DEBUG "mppe_decompress[%d]: ccount %d\n",
+                      state->unit, ccount);
+
+       /* sanity checks -- terminate with extreme prejudice */
+       if (!(MPPE_BITS(ibuf) & MPPE_BIT_ENCRYPTED)) {
+               printk(KERN_DEBUG
+                      "mppe_decompress[%d]: ENCRYPTED bit not set!\n",
+                      state->unit);
+               state->sanity_errors += 100;
+               sanity = 1;
+       }
+       if (!state->stateful && !flushed) {
+               printk(KERN_DEBUG "mppe_decompress[%d]: FLUSHED bit not set in "
+                      "stateless mode!\n", state->unit);
+               state->sanity_errors += 100;
+               sanity = 1;
+       }
+       if (state->stateful && ((ccount & 0xff) == 0xff) && !flushed) {
+               printk(KERN_DEBUG "mppe_decompress[%d]: FLUSHED bit not set on "
+                      "flag packet!\n", state->unit);
+               state->sanity_errors += 100;
+               sanity = 1;
+       }
+
+       if (sanity) {
+               if (state->sanity_errors < SANITY_MAX)
+                       return DECOMP_ERROR;
+               else
+                       /*
+                        * Take LCP down if the peer is sending too many bogons.
+                        * We don't want to do this for a single or just a few
+                        * instances since it could just be due to packet corruption.
+                        */
+                       return DECOMP_FATALERROR;
+       }
+
+       /*
+        * Check the coherency count.
+        */
+
+       if (!state->stateful) {
+               /* RFC 3078, sec 8.1.  Rekey for every packet. */
+               while (state->ccount != ccount) {
+                       mppe_rekey(state, 0);
+                       state->ccount = (state->ccount + 1) % MPPE_CCOUNT_SPACE;
+               }
+       } else {
+               /* RFC 3078, sec 8.2. */
+               if (!state->discard) {
+                       /* normal state */
+                       state->ccount = (state->ccount + 1) % MPPE_CCOUNT_SPACE;
+                       if (ccount != state->ccount) {
+                               /*
+                                * (ccount > state->ccount)
+                                * Packet loss detected, enter the discard state.
+                                * Signal the peer to rekey (by sending a CCP Reset-Request).
+                                */
+                               state->discard = 1;
+                               return DECOMP_ERROR;
+                       }
+               } else {
+                       /* discard state */
+                       if (!flushed) {
+                               /* ccp.c will be silent (no additional CCP Reset-Requests). */
+                               return DECOMP_ERROR;
+                       } else {
+                               /* Rekey for every missed "flag" packet. */
+                               while ((ccount & ~0xff) !=
+                                      (state->ccount & ~0xff)) {
+                                       mppe_rekey(state, 0);
+                                       state->ccount =
+                                           (state->ccount +
+                                            256) % MPPE_CCOUNT_SPACE;
+                               }
+
+                               /* reset */
+                               state->discard = 0;
+                               state->ccount = ccount;
+                               /*
+                                * Another problem with RFC 3078 here.  It implies that the
+                                * peer need not send a Reset-Ack packet.  But RFC 1962
+                                * requires it.  Hopefully, M$ does send a Reset-Ack; even
+                                * though it isn't required for MPPE synchronization, it is
+                                * required to reset CCP state.
+                                */
+                       }
+               }
+               if (flushed)
+                       mppe_rekey(state, 0);
+       }
+
+       /*
+        * Fill in the first part of the PPP header.  The protocol field
+        * comes from the decrypted data.
+        */
+       obuf[0] = PPP_ADDRESS(ibuf);    /* +1 */
+       obuf[1] = PPP_CONTROL(ibuf);    /* +1 */
+       obuf += 2;
+       ibuf += PPP_HDRLEN + MPPE_OVHD;
+       isize -= PPP_HDRLEN + MPPE_OVHD;        /* -6 */
+       /* net osize: isize-4 */
+
+       /*
+        * Decrypt the first byte in order to check if it is
+        * a compressed or uncompressed protocol field.
+        */
+       setup_sg(sg_in, ibuf, 1);
+       setup_sg(sg_out, obuf, 1);
+       if (crypto_cipher_decrypt(state->arc4, sg_out, sg_in, 1) != 0) {
+               printk(KERN_DEBUG "crypto_cypher_decrypt failed\n");
+               return DECOMP_ERROR;
+       }
+
+       /*
+        * Do PFC decompression.
+        * This would be nicer if we were given the actual sk_buff
+        * instead of a char *.
+        */
+       if ((obuf[0] & 0x01) != 0) {
+               obuf[1] = obuf[0];
+               obuf[0] = 0;
+               obuf++;
+               osize++;
+       }
+
+       /* And finally, decrypt the rest of the packet. */
+       setup_sg(sg_in, ibuf + 1, isize - 1);
+       setup_sg(sg_out, obuf + 1, osize - 1);
+       if (crypto_cipher_decrypt(state->arc4, sg_out, sg_in, isize - 1) != 0) {
+               printk(KERN_DEBUG "crypto_cypher_decrypt failed\n");
+               return DECOMP_ERROR;
+       }
+
+       state->stats.unc_bytes += osize;
+       state->stats.unc_packets++;
+       state->stats.comp_bytes += isize;
+       state->stats.comp_packets++;
+
+       /* good packet credit */
+       state->sanity_errors >>= 1;
+
+       return osize;
+}
+
+/*
+ * Incompressible data has arrived (this should never happen!).
+ * We should probably drop the link if the protocol is in the range
+ * of what should be encrypted.  At the least, we should drop this
+ * packet.  (How to do this?)
+ */
+static void mppe_incomp(void *arg, unsigned char *ibuf, int icnt)
+{
+       struct ppp_mppe_state *state = (struct ppp_mppe_state *) arg;
+
+       if (state->debug &&
+           (PPP_PROTOCOL(ibuf) >= 0x0021 && PPP_PROTOCOL(ibuf) <= 0x00fa))
+               printk(KERN_DEBUG
+                      "mppe_incomp[%d]: incompressible (unencrypted) data! "
+                      "(proto %04x)\n", state->unit, PPP_PROTOCOL(ibuf));
+
+       state->stats.inc_bytes += icnt;
+       state->stats.inc_packets++;
+       state->stats.unc_bytes += icnt;
+       state->stats.unc_packets++;
+}
+
+/*************************************************************
+ * Module interface table
+ *************************************************************/
+
+/*
+ * Procedures exported to if_ppp.c.
+ */
+static struct compressor ppp_mppe = {
+       .compress_proto = CI_MPPE,
+       .comp_alloc     = mppe_alloc,
+       .comp_free      = mppe_free,
+       .comp_init      = mppe_comp_init,
+       .comp_reset     = mppe_comp_reset,
+       .compress       = mppe_compress,
+       .comp_stat      = mppe_comp_stats,
+       .decomp_alloc   = mppe_alloc,
+       .decomp_free    = mppe_free,
+       .decomp_init    = mppe_decomp_init,
+       .decomp_reset   = mppe_decomp_reset,
+       .decompress     = mppe_decompress,
+       .incomp         = mppe_incomp,
+       .decomp_stat    = mppe_comp_stats,
+       .owner          = THIS_MODULE,
+       .comp_extra     = MPPE_PAD,
+};
+
+/*
+ * ppp_mppe_init()
+ *
+ * Prior to allowing load, try to load the arc4 and sha1 crypto
+ * libraries.  The actual use will be allocated later, but
+ * this way the module will fail to insmod if they aren't available.
+ */
+
+static int __init ppp_mppe_init(void)
+{
+       int answer;
+       if (!(crypto_alg_available("arc4", 0) &&
+             crypto_alg_available("sha1", 0)))
+               return -ENODEV;
+
+       sha_pad = kmalloc(sizeof(struct sha_pad), GFP_KERNEL);
+       if (!sha_pad)
+               return -ENOMEM;
+       sha_pad_init(sha_pad);
+
+       answer = ppp_register_compressor(&ppp_mppe);
+
+       if (answer == 0)
+               printk(KERN_INFO "PPP MPPE Compression module registered\n");
+       else
+               kfree(sha_pad);
+
+       return answer;
+}
+
+static void __exit ppp_mppe_cleanup(void)
+{
+       ppp_unregister_compressor(&ppp_mppe);
+       kfree(sha_pad);
+}
+
+module_init(ppp_mppe_init);
+module_exit(ppp_mppe_cleanup);
diff --git a/drivers/net/ppp_mppe.h b/drivers/net/ppp_mppe.h
new file mode 100644 (file)
index 0000000..7a14e05
--- /dev/null
@@ -0,0 +1,86 @@
+#define MPPE_PAD                4      /* MPPE growth per frame */
+#define MPPE_MAX_KEY_LEN       16      /* largest key length (128-bit) */
+
+/* option bits for ccp_options.mppe */
+#define MPPE_OPT_40            0x01    /* 40 bit */
+#define MPPE_OPT_128           0x02    /* 128 bit */
+#define MPPE_OPT_STATEFUL      0x04    /* stateful mode */
+/* unsupported opts */
+#define MPPE_OPT_56            0x08    /* 56 bit */
+#define MPPE_OPT_MPPC          0x10    /* MPPC compression */
+#define MPPE_OPT_D             0x20    /* Unknown */
+#define MPPE_OPT_UNSUPPORTED (MPPE_OPT_56|MPPE_OPT_MPPC|MPPE_OPT_D)
+#define MPPE_OPT_UNKNOWN       0x40    /* Bits !defined in RFC 3078 were set */
+
+/*
+ * This is not nice ... the alternative is a bitfield struct though.
+ * And unfortunately, we cannot share the same bits for the option
+ * names above since C and H are the same bit.  We could do a u_int32
+ * but then we have to do a htonl() all the time and/or we still need
+ * to know which octet is which.
+ */
+#define MPPE_C_BIT             0x01    /* MPPC */
+#define MPPE_D_BIT             0x10    /* Obsolete, usage unknown */
+#define MPPE_L_BIT             0x20    /* 40-bit */
+#define MPPE_S_BIT             0x40    /* 128-bit */
+#define MPPE_M_BIT             0x80    /* 56-bit, not supported */
+#define MPPE_H_BIT             0x01    /* Stateless (in a different byte) */
+
+/* Does not include H bit; used for least significant octet only. */
+#define MPPE_ALL_BITS (MPPE_D_BIT|MPPE_L_BIT|MPPE_S_BIT|MPPE_M_BIT|MPPE_H_BIT)
+
+/* Build a CI from mppe opts (see RFC 3078) */
+#define MPPE_OPTS_TO_CI(opts, ci)              \
+    do {                                       \
+       u_char *ptr = ci; /* u_char[4] */       \
+                                               \
+       /* H bit */                             \
+       if (opts & MPPE_OPT_STATEFUL)           \
+           *ptr++ = 0x0;                       \
+       else                                    \
+           *ptr++ = MPPE_H_BIT;                \
+       *ptr++ = 0;                             \
+       *ptr++ = 0;                             \
+                                               \
+       /* S,L bits */                          \
+       *ptr = 0;                               \
+       if (opts & MPPE_OPT_128)                \
+           *ptr |= MPPE_S_BIT;                 \
+       if (opts & MPPE_OPT_40)                 \
+           *ptr |= MPPE_L_BIT;                 \
+       /* M,D,C bits not supported */          \
+    } while (/* CONSTCOND */ 0)
+
+/* The reverse of the above */
+#define MPPE_CI_TO_OPTS(ci, opts)              \
+    do {                                       \
+       u_char *ptr = ci; /* u_char[4] */       \
+                                               \
+       opts = 0;                               \
+                                               \
+       /* H bit */                             \
+       if (!(ptr[0] & MPPE_H_BIT))             \
+           opts |= MPPE_OPT_STATEFUL;          \
+                                               \
+       /* S,L bits */                          \
+       if (ptr[3] & MPPE_S_BIT)                \
+           opts |= MPPE_OPT_128;               \
+       if (ptr[3] & MPPE_L_BIT)                \
+           opts |= MPPE_OPT_40;                \
+                                               \
+       /* M,D,C bits */                        \
+       if (ptr[3] & MPPE_M_BIT)                \
+           opts |= MPPE_OPT_56;                \
+       if (ptr[3] & MPPE_D_BIT)                \
+           opts |= MPPE_OPT_D;                 \
+       if (ptr[3] & MPPE_C_BIT)                \
+           opts |= MPPE_OPT_MPPC;              \
+                                               \
+       /* Other bits */                        \
+       if (ptr[0] & ~MPPE_H_BIT)               \
+           opts |= MPPE_OPT_UNKNOWN;           \
+       if (ptr[1] || ptr[2])                   \
+           opts |= MPPE_OPT_UNKNOWN;           \
+       if (ptr[3] & ~MPPE_ALL_BITS)            \
+           opts |= MPPE_OPT_UNKNOWN;           \
+    } while (/* CONSTCOND */ 0)
index 24b7233a803c01dc0a1d0a66be0e8299597643e5..e57df8dfe6b4ec29b0c81b2f71d9c5809b1fa228 100644 (file)
@@ -55,7 +55,6 @@
 #include <linux/timex.h>
 #include <linux/sched.h>
 #include <linux/ethtool.h>
-#include <linux/version.h>
 #include <linux/workqueue.h>
 #include <linux/if_vlan.h>
 
index 308440bd0e126ca4bdd2b05e786d810761e524b2..91b8d4f45904fa0648a45a2cf594fd0c8bc65544 100644 (file)
@@ -39,9 +39,6 @@
 #ifndef __INC_SKDRV1ST_H
 #define __INC_SKDRV1ST_H
 
-/* Check kernel version */
-#include <linux/version.h>
-
 typedef struct s_AC    SK_AC;
 
 /* Set card versions */
index 4c56b8d8221b2b4562bffb1ac68cc78454155707..e5d6d95960c7b76a1c746e247170545fcf7ba4f7 100644 (file)
@@ -93,7 +93,6 @@ History:
 #include <linux/mca-legacy.h>
 #include <linux/init.h>
 #include <linux/module.h>
-#include <linux/version.h>
 #include <linux/netdevice.h>
 #include <linux/etherdevice.h>
 #include <linux/skbuff.h>
index 7e7c995827460831f4200c139d98ffaff9bd4f31..d6fa1823dfa625973867c49703785fea944dda39 100644 (file)
@@ -1,5 +1,3 @@
-#include <linux/version.h>
-
 #ifndef _SK_MCA_INCLUDE_
 #define _SK_MCA_INCLUDE_
 
index 38b2b0a3ce96fa900cb8891c67c6f7e39411687d..d167deda9a53a0cb8c05bc375af76105021d3967 100644 (file)
@@ -147,7 +147,6 @@ TODO:       - fix forced speed/duplexing code (broken a long time ago, when
 #define DRV_RELDATE    "October 3, 2005"
 
 #include <linux/config.h>
-#include <linux/version.h>
 #include <linux/module.h>
 #include <linux/kernel.h>
 #include <linux/pci.h>
index a368d08e7d1927fbcaa825b2efe639598b470598..82c6b757d30664e0ae7cf106fa36a6dd4411dfc3 100644 (file)
@@ -61,7 +61,6 @@
 #include <linux/timer.h>
 #include <linux/slab.h>
 #include <linux/interrupt.h>
-#include <linux/version.h>
 #include <linux/string.h>
 #include <linux/wait.h>
 #include <asm/io.h>
index 6a96cd9f2685c7d8d962ba7f9ef5de47c4896d23..3d2ea61033be52fd5d0b047ba34de1d2abf20d7d 100644 (file)
@@ -13,7 +13,6 @@
  */
 
 #include <linux/config.h>
-#include <linux/version.h>
 #include <linux/module.h>
 #include <linux/init.h>
 #include <linux/slab.h>
index 59fc15572395cc50a4e8f56b2643afd6800f43d1..abfae7fedebcfcc31a75b9631b8e6bcd993bd287 100644 (file)
@@ -31,7 +31,6 @@
 
 
 #include <linux/config.h>
-#include <linux/version.h>
 
 #include <asm/delay.h>
 #include <asm/uaccess.h>
index da0c80fb941cab99dac9d2c93cf0105010f90abd..2e85bdced2dd7fd74d721ef1f147065adecf8829 100644 (file)
@@ -5,7 +5,6 @@
  * Andy Warner <andyw@pobox.com> */
 
 #include <linux/config.h>
-#include <linux/version.h>
 #include <linux/module.h>
 #include <linux/init.h>
 #include <linux/if.h>
index 78d67b408b2f9423080bd276ba4bfc78644164a7..94fe2449f0990a43f72a023ed5da2dfb9f6ccc0c 100644 (file)
@@ -8,7 +8,6 @@
 
 
 #include <linux/config.h>
-#include <linux/version.h>
 #include <linux/module.h>
 #include <linux/init.h>
 #include <linux/if.h>
index a1a9cbcf6c2f13f959cc21d3a2a53a016ba111ab..140fdf2a0a09a58afdcbe36658a07476c16474c4 100644 (file)
@@ -37,7 +37,6 @@
 #include <linux/socket.h>
 #include <linux/if_arp.h>
 #include <linux/wireless.h>
-#include <linux/version.h>
 #include <net/iw_handler.h>    // new driver API
 
 #include <net/ieee80211.h>
index 136884cef9084b33b1058323cecea93bce605e1a..b0d195d1721a6b490107c864043596d0a0768d10 100644 (file)
@@ -31,6 +31,7 @@
 ******************************************************************************/
 
 #include "ipw2200.h"
+#include <linux/version.h>
 
 #define IPW2200_VERSION "git-1.0.8"
 #define DRV_DESCRIPTION        "Intel(R) PRO/Wireless 2200/2915 Network Driver"
index 617ec4dba17a6a3a5ab969e608bc9c0a2edc385a..1c98db0652c9458a9c61079e8e91cd8a6edb4d39 100644 (file)
@@ -34,7 +34,6 @@
 #include <linux/config.h>
 #include <linux/init.h>
 
-#include <linux/version.h>
 #include <linux/pci.h>
 #include <linux/netdevice.h>
 #include <linux/ethtool.h>
index 7a17bb31fc896da55e1943c021aaa2ad7c125c51..f5d856db92a1ce3337d18e2058831cac027f7037 100644 (file)
@@ -12,7 +12,6 @@
 #include <linux/netdevice.h>
 #include <linux/wireless.h>
 #include <net/iw_handler.h>
-#include <linux/version.h>
 
 #include "hermes.h"
 
index 866c476933c337e7506063702b97ecd07f168b7c..109a96d90007ba53ad39a15cec8be73ed56945f4 100644 (file)
@@ -18,7 +18,6 @@
  *
  */
 
-#include <linux/version.h>
 #include <linux/module.h>
 #include <linux/types.h>
 #include <linux/delay.h>
index e83e4912ab66033273a54b6c0c288f400f50062c..8af20980af8ddcdc44dabb9d83f9a332a72c11ad 100644 (file)
@@ -20,7 +20,6 @@
 #ifndef _ISL_38XX_H
 #define _ISL_38XX_H
 
-#include <linux/version.h>
 #include <asm/io.h>
 #include <asm/byteorder.h>
 
index 5c1a1adf1ff8b2421d93549f765c071c2bc9e0fb..135a156db25d9c07607d7ce0cae5cb9019636417 100644 (file)
@@ -20,7 +20,6 @@
  *
  */
 
-#include <linux/version.h>
 #include <linux/module.h>
 #include <linux/kernel.h>
 #include <linux/if_arp.h>
index 78bdb359835ef5945ae964882c04a95d3731e371..5ddf295990321b4bb466241e73481947ccab9897 100644 (file)
@@ -19,7 +19,6 @@
  *
  */
 
-#include <linux/version.h>
 #include <linux/module.h>
 
 #include <linux/netdevice.h>
index efbed439795111ac4e9021f56b60c4fc00ac2dad..07053165e4c587b121bcdcfa5cfe9bed1a877c22 100644 (file)
@@ -23,7 +23,6 @@
 #ifndef _ISLPCI_DEV_H
 #define _ISLPCI_DEV_H
 
-#include <linux/version.h>
 #include <linux/netdevice.h>
 #include <linux/wireless.h>
 #include <net/iw_handler.h>
index a92ce3af3fa94d5dda326b667017e8da7b095dc1..33d64d2ee53f7397fb3b9db833a6e6a89611f1ee 100644 (file)
@@ -17,7 +17,6 @@
  *
  */
 
-#include <linux/version.h>
 #include <linux/module.h>
 
 #include <linux/pci.h>
index dc040caab7d746e61a8c4c87c6149f33924e07cc..b41d666fea3c18ab588d4c28b3e1d945956c6a81 100644 (file)
@@ -18,7 +18,6 @@
  *
  */
 
-#include <linux/version.h>
 #include <linux/module.h>
 #include <linux/pci.h>
 #include <linux/delay.h>
index d414a3bb50b98814ca4c1be18244e45456915b0d..86c0808d6a057920bfe07412cf1e73c9efff7c2a 100644 (file)
@@ -30,7 +30,6 @@
 #include <linux/timer.h>
 #include <linux/mm.h>
 #include <linux/proc_fs.h>
-#include <linux/version.h>
 #include <linux/types.h>
 
 #include <pcmcia/cs_types.h>
index f113b69d699bf2ddfa8ccdfe8573095f1448d902..01a895bc9a4795d8cd78ee6c9908f740ff3c761f 100644 (file)
@@ -35,7 +35,6 @@
 #include <linux/timer.h>
 #include <linux/mm.h>
 #include <linux/proc_fs.h>
-#include <linux/version.h>
 #include <linux/types.h>
 
 #include <pcmcia/cs_types.h>
index fe5ea36e7de3878e63b7819cab7872c89d8acd49..56c58831e80e593eae62c2e33744fcd508ad7cd2 100644 (file)
 #include <asm/hardware.h>
 #include <asm/irq.h>
 #include <asm/hardware/scoop.h>
-#ifdef CONFIG_SA1100_COLLIE
-#include <asm/arch-sa1100/collie.h>
-#else
-#include <asm/arch-pxa/pxa-regs.h>
-#endif
 
 #include "soc_common.h"
 
 #define        NO_KEEP_VS 0x0001
 
+/* PCMCIA to Scoop linkage
+
+   There is no easy way to link multiple scoop devices into one
+   single entity for the pxa2xx_pcmcia device so this structure
+   is used which is setup by the platform code
+*/
+struct scoop_pcmcia_config *platform_scoop_config;
+#define SCOOP_DEV platform_scoop_config->devs
+
 static void sharpsl_pcmcia_init_reset(struct scoop_pcmcia_dev *scoopdev)
 {
        reset_scoop(scoopdev->dev);
@@ -43,38 +47,16 @@ static int sharpsl_pcmcia_hw_init(struct soc_pcmcia_socket *skt)
 {
        int ret;
 
-#ifndef CONFIG_SA1100_COLLIE
-       /*
-        * Setup default state of GPIO outputs
-        * before we enable them as outputs.
-        */
-       GPSR(GPIO48_nPOE) =
-               GPIO_bit(GPIO48_nPOE) |
-               GPIO_bit(GPIO49_nPWE) |
-               GPIO_bit(GPIO50_nPIOR) |
-               GPIO_bit(GPIO51_nPIOW) |
-               GPIO_bit(GPIO52_nPCE_1) |
-               GPIO_bit(GPIO53_nPCE_2);
-
-       pxa_gpio_mode(GPIO48_nPOE_MD);
-       pxa_gpio_mode(GPIO49_nPWE_MD);
-       pxa_gpio_mode(GPIO50_nPIOR_MD);
-       pxa_gpio_mode(GPIO51_nPIOW_MD);
-       pxa_gpio_mode(GPIO52_nPCE_1_MD);
-       pxa_gpio_mode(GPIO53_nPCE_2_MD);
-       pxa_gpio_mode(GPIO54_pSKTSEL_MD);
-       pxa_gpio_mode(GPIO55_nPREG_MD);
-       pxa_gpio_mode(GPIO56_nPWAIT_MD);
-       pxa_gpio_mode(GPIO57_nIOIS16_MD);
-#endif
+       if (platform_scoop_config->pcmcia_init)
+               platform_scoop_config->pcmcia_init();
 
        /* Register interrupts */
-       if (scoop_devs[skt->nr].cd_irq >= 0) {
+       if (SCOOP_DEV[skt->nr].cd_irq >= 0) {
                struct pcmcia_irqs cd_irq;
 
                cd_irq.sock = skt->nr;
-               cd_irq.irq  = scoop_devs[skt->nr].cd_irq;
-               cd_irq.str  = scoop_devs[skt->nr].cd_irq_str;
+               cd_irq.irq  = SCOOP_DEV[skt->nr].cd_irq;
+               cd_irq.str  = SCOOP_DEV[skt->nr].cd_irq_str;
                ret = soc_pcmcia_request_irqs(skt, &cd_irq, 1);
 
                if (ret) {
@@ -83,19 +65,19 @@ static int sharpsl_pcmcia_hw_init(struct soc_pcmcia_socket *skt)
                }
        }
 
-       skt->irq = scoop_devs[skt->nr].irq;
+       skt->irq = SCOOP_DEV[skt->nr].irq;
 
        return 0;
 }
 
 static void sharpsl_pcmcia_hw_shutdown(struct soc_pcmcia_socket *skt)
 {
-       if (scoop_devs[skt->nr].cd_irq >= 0) {
+       if (SCOOP_DEV[skt->nr].cd_irq >= 0) {
                struct pcmcia_irqs cd_irq;
 
                cd_irq.sock = skt->nr;
-               cd_irq.irq  = scoop_devs[skt->nr].cd_irq;
-               cd_irq.str  = scoop_devs[skt->nr].cd_irq_str;
+               cd_irq.irq  = SCOOP_DEV[skt->nr].cd_irq;
+               cd_irq.str  = SCOOP_DEV[skt->nr].cd_irq_str;
                soc_pcmcia_free_irqs(skt, &cd_irq, 1);
        }
 }
@@ -105,9 +87,9 @@ static void sharpsl_pcmcia_socket_state(struct soc_pcmcia_socket *skt,
                                    struct pcmcia_state *state)
 {
        unsigned short cpr, csr;
-       struct device *scoop = scoop_devs[skt->nr].dev;
+       struct device *scoop = SCOOP_DEV[skt->nr].dev;
 
-       cpr = read_scoop_reg(scoop_devs[skt->nr].dev, SCOOP_CPR);
+       cpr = read_scoop_reg(SCOOP_DEV[skt->nr].dev, SCOOP_CPR);
 
        write_scoop_reg(scoop, SCOOP_IRM, 0x00FF);
        write_scoop_reg(scoop, SCOOP_ISR, 0x0000);
@@ -116,21 +98,25 @@ static void sharpsl_pcmcia_socket_state(struct soc_pcmcia_socket *skt,
        if (csr & 0x0004) {
                /* card eject */
                write_scoop_reg(scoop, SCOOP_CDR, 0x0000);
-               scoop_devs[skt->nr].keep_vs = NO_KEEP_VS;
+               SCOOP_DEV[skt->nr].keep_vs = NO_KEEP_VS;
        }
-       else if (!(scoop_devs[skt->nr].keep_vs & NO_KEEP_VS)) {
+       else if (!(SCOOP_DEV[skt->nr].keep_vs & NO_KEEP_VS)) {
                /* keep vs1,vs2 */
                write_scoop_reg(scoop, SCOOP_CDR, 0x0000);
-               csr |= scoop_devs[skt->nr].keep_vs;
+               csr |= SCOOP_DEV[skt->nr].keep_vs;
        }
        else if (cpr & 0x0003) {
                /* power on */
                write_scoop_reg(scoop, SCOOP_CDR, 0x0000);
-               scoop_devs[skt->nr].keep_vs = (csr & 0x00C0);
+               SCOOP_DEV[skt->nr].keep_vs = (csr & 0x00C0);
        }
        else {
                /* card detect */
-               write_scoop_reg(scoop, SCOOP_CDR, 0x0002);
+               if ((machine_is_spitz() || machine_is_borzoi()) && skt->nr == 1) {
+                       write_scoop_reg(scoop, SCOOP_CDR, 0x0000);
+               } else {
+                       write_scoop_reg(scoop, SCOOP_CDR, 0x0002);
+               }
        }
 
        state->detect = (csr & 0x0004) ? 0 : 1;
@@ -144,7 +130,6 @@ static void sharpsl_pcmcia_socket_state(struct soc_pcmcia_socket *skt,
        if ((cpr & 0x0080) && ((cpr & 0x8040) != 0x8040)) {
                printk(KERN_ERR "sharpsl_pcmcia_socket_state(): CPR=%04X, Low voltage!\n", cpr);
        }
-
 }
 
 
@@ -152,7 +137,7 @@ static int sharpsl_pcmcia_configure_socket(struct soc_pcmcia_socket *skt,
                                       const socket_state_t *state)
 {
        unsigned long flags;
-       struct device *scoop = scoop_devs[skt->nr].dev;
+       struct device *scoop = SCOOP_DEV[skt->nr].dev;
 
        unsigned short cpr, ncpr, ccr, nccr, mcr, nmcr, imr, nimr;
 
@@ -177,8 +162,13 @@ static int sharpsl_pcmcia_configure_socket(struct soc_pcmcia_socket *skt,
        nccr = (ccr = read_scoop_reg(scoop, SCOOP_CCR)) & ~0x0080;
        nimr = (imr = read_scoop_reg(scoop, SCOOP_IMR)) & ~0x003E;
 
-       ncpr |= (state->Vcc == 33) ? 0x0001 :
-                               (state->Vcc == 50) ? 0x0002 : 0;
+       if ((machine_is_spitz() || machine_is_borzoi() || machine_is_akita()) && skt->nr == 0) {
+               ncpr |= (state->Vcc == 33) ? 0x0002 :
+                       (state->Vcc == 50) ? 0x0002 : 0;
+       } else {
+               ncpr |= (state->Vcc == 33) ? 0x0001 :
+                       (state->Vcc == 50) ? 0x0002 : 0;
+       }
        nmcr |= (state->flags&SS_IOCARD) ? 0x0010 : 0;
        ncpr |= (state->flags&SS_OUTPUT_ENA) ? 0x0080 : 0;
        nccr |= (state->flags&SS_RESET)? 0x0080: 0;
@@ -190,18 +180,22 @@ static int sharpsl_pcmcia_configure_socket(struct soc_pcmcia_socket *skt,
                        ((skt->status&SS_WRPROT) ? 0x0008 : 0);
 
        if (!(ncpr & 0x0003)) {
-               scoop_devs[skt->nr].keep_rd = 0;
-       } else if (!scoop_devs[skt->nr].keep_rd) {
+               SCOOP_DEV[skt->nr].keep_rd = 0;
+       } else if (!SCOOP_DEV[skt->nr].keep_rd) {
                if (nccr & 0x0080)
-                       scoop_devs[skt->nr].keep_rd = 1;
+                       SCOOP_DEV[skt->nr].keep_rd = 1;
                else
                        nccr |= 0x0080;
        }
 
        if (mcr != nmcr)
                write_scoop_reg(scoop, SCOOP_MCR, nmcr);
-       if (cpr != ncpr)
-               write_scoop_reg(scoop, SCOOP_CPR, ncpr);
+       if (cpr != ncpr) {
+               if (platform_scoop_config->power_ctrl)
+                       platform_scoop_config->power_ctrl(scoop, ncpr , skt->nr);
+               else
+                       write_scoop_reg(scoop, SCOOP_CPR, ncpr);
+       }
        if (ccr != nccr)
                write_scoop_reg(scoop, SCOOP_CCR, nccr);
        if (imr != nimr)
@@ -214,43 +208,43 @@ static int sharpsl_pcmcia_configure_socket(struct soc_pcmcia_socket *skt,
 
 static void sharpsl_pcmcia_socket_init(struct soc_pcmcia_socket *skt)
 {
-       sharpsl_pcmcia_init_reset(&scoop_devs[skt->nr]);
+       sharpsl_pcmcia_init_reset(&SCOOP_DEV[skt->nr]);
 
        /* Enable interrupt */
-       write_scoop_reg(scoop_devs[skt->nr].dev, SCOOP_IMR, 0x00C0);
-       write_scoop_reg(scoop_devs[skt->nr].dev, SCOOP_MCR, 0x0101);
-       scoop_devs[skt->nr].keep_vs = NO_KEEP_VS;
+       write_scoop_reg(SCOOP_DEV[skt->nr].dev, SCOOP_IMR, 0x00C0);
+       write_scoop_reg(SCOOP_DEV[skt->nr].dev, SCOOP_MCR, 0x0101);
+       SCOOP_DEV[skt->nr].keep_vs = NO_KEEP_VS;
 
        if (machine_is_collie())
                /* We need to disable SS_OUTPUT_ENA here. */
-               write_scoop_reg(scoop_devs[skt->nr].dev, SCOOP_CPR, read_scoop_reg(scoop_devs[skt->nr].dev, SCOOP_CPR) & ~0x0080);
+               write_scoop_reg(SCOOP_DEV[skt->nr].dev, SCOOP_CPR, read_scoop_reg(SCOOP_DEV[skt->nr].dev, SCOOP_CPR) & ~0x0080);
 }
 
 static void sharpsl_pcmcia_socket_suspend(struct soc_pcmcia_socket *skt)
 {
        /* CF_BUS_OFF */
-       sharpsl_pcmcia_init_reset(&scoop_devs[skt->nr]);
+       sharpsl_pcmcia_init_reset(&SCOOP_DEV[skt->nr]);
 
        if (machine_is_collie())
                /* We need to disable SS_OUTPUT_ENA here. */
-               write_scoop_reg(scoop_devs[skt->nr].dev, SCOOP_CPR, read_scoop_reg(scoop_devs[skt->nr].dev, SCOOP_CPR) & ~0x0080);
+               write_scoop_reg(SCOOP_DEV[skt->nr].dev, SCOOP_CPR, read_scoop_reg(SCOOP_DEV[skt->nr].dev, SCOOP_CPR) & ~0x0080);
 }
 
 static struct pcmcia_low_level sharpsl_pcmcia_ops = {
-       .owner                          = THIS_MODULE,
-       .hw_init                        = sharpsl_pcmcia_hw_init,
-       .hw_shutdown            = sharpsl_pcmcia_hw_shutdown,
-       .socket_state           = sharpsl_pcmcia_socket_state,
-       .configure_socket       = sharpsl_pcmcia_configure_socket,
-       .socket_init            = sharpsl_pcmcia_socket_init,
-       .socket_suspend         = sharpsl_pcmcia_socket_suspend,
-       .first                          = 0,
-       .nr                                     = 0,
+       .owner                  = THIS_MODULE,
+       .hw_init                = sharpsl_pcmcia_hw_init,
+       .hw_shutdown            = sharpsl_pcmcia_hw_shutdown,
+       .socket_state           = sharpsl_pcmcia_socket_state,
+       .configure_socket       = sharpsl_pcmcia_configure_socket,
+       .socket_init            = sharpsl_pcmcia_socket_init,
+       .socket_suspend         = sharpsl_pcmcia_socket_suspend,
+       .first                  = 0,
+       .nr                     = 0,
 };
 
-static struct platform_device *sharpsl_pcmcia_device;
-
 #ifdef CONFIG_SA1100_COLLIE
+#include "sa11xx_base.h"
+
 int __init pcmcia_collie_init(struct device *dev)
 {
        int ret = -ENODEV;
@@ -263,11 +257,13 @@ int __init pcmcia_collie_init(struct device *dev)
 
 #else
 
+static struct platform_device *sharpsl_pcmcia_device;
+
 static int __init sharpsl_pcmcia_init(void)
 {
        int ret;
 
-       sharpsl_pcmcia_ops.nr=scoop_num;
+       sharpsl_pcmcia_ops.nr=platform_scoop_config->num_devs;
        sharpsl_pcmcia_device = kmalloc(sizeof(*sharpsl_pcmcia_device), GFP_KERNEL);
        if (!sharpsl_pcmcia_device)
                return -ENOMEM;
@@ -275,7 +271,7 @@ static int __init sharpsl_pcmcia_init(void)
        memset(sharpsl_pcmcia_device, 0, sizeof(*sharpsl_pcmcia_device));
        sharpsl_pcmcia_device->name = "pxa2xx-pcmcia";
        sharpsl_pcmcia_device->dev.platform_data = &sharpsl_pcmcia_ops;
-       sharpsl_pcmcia_device->dev.parent=scoop_devs[0].dev;
+       sharpsl_pcmcia_device->dev.parent=platform_scoop_config->devs[0].dev;
 
        ret = platform_device_register(sharpsl_pcmcia_device);
        if (ret)
index 3b4da5a9cf7991693dce5d71746d1ae0de9edea5..f7bf45c6bf0de23899fb1ff7136fef865aa3d0f8 100644 (file)
@@ -41,14 +41,14 @@ int kbd_ioctl(struct kbd_data *, struct file *, unsigned int, unsigned long);
 /*
  * Helper Functions.
  */
-extern inline void
+static inline void
 kbd_put_queue(struct tty_struct *tty, int ch)
 {
        tty_insert_flip_char(tty, ch, 0);
        tty_schedule_flip(tty);
 }
 
-extern inline void
+static inline void
 kbd_puts_queue(struct tty_struct *tty, char *cp)
 {
        while (*cp)
index 6b8aa6a852bedb5230a9964edefca539da3c688a..328e31cc685429baa9c0c82fc30c8129137bcd72 100644 (file)
@@ -265,7 +265,7 @@ QDIO_PRINT_##importance(header "%02x %02x %02x %02x  %02x %02x %02x %02x  " \
 /*
  * Some instructions as assembly
  */
-extern __inline__ int 
+static inline int
 do_siga_sync(unsigned int irq, unsigned int mask1, unsigned int mask2)
 {
        int cc;
@@ -300,7 +300,7 @@ do_siga_sync(unsigned int irq, unsigned int mask1, unsigned int mask2)
        return cc;
 }
 
-extern __inline__ int
+static inline int
 do_siga_input(unsigned int irq, unsigned int mask)
 {
        int cc;
@@ -334,7 +334,7 @@ do_siga_input(unsigned int irq, unsigned int mask)
        return cc;
 }
 
-extern __inline__ int
+static inline int
 do_siga_output(unsigned long irq, unsigned long mask, __u32 *bb)
 {
        int cc;
@@ -401,7 +401,7 @@ do_siga_output(unsigned long irq, unsigned long mask, __u32 *bb)
        return cc;
 }
 
-extern __inline__ unsigned long
+static inline unsigned long
 do_clear_global_summary(void)
 {
 
index 04c2ef778ec69bc209bf830ab783a5234a56c108..4010f2bb85af92e783cc0b2cfa7d7217dafd973d 100644 (file)
@@ -37,7 +37,6 @@
 #include <linux/kobject_uevent.h>
 #include <linux/proc_fs.h>
 #include <linux/syscalls.h>
-#include <linux/version.h>
 #include "z90crypt.h"
 #include "z90common.h"
 
index 1a1c3decea728c0ec0ae48fcc50398e662d1ce41..6b63d21612ec71fd30e272f8272a352b37e18542 100644 (file)
@@ -88,7 +88,6 @@
 #include <linux/tcp.h>
 #include <linux/timer.h>
 #include <linux/types.h>
-#include <linux/version.h>
 
 #include "cu3088.h"
 #include "claw.h"
index 1b8a7e7c34f3cd9f9d95857b335999eced5ddf3f..5b98253be7aa43b1bc196d92fd2c4e7dc8b0f477 100644 (file)
@@ -140,7 +140,7 @@ fsm_record_history(fsm_instance *fi, int state, int event);
  *              1  if current state or event is out of range
  *              !0 if state and event in range, but no action defined.
  */
-extern __inline__ int
+static inline int
 fsm_event(fsm_instance *fi, int event, void *arg)
 {
        fsm_function_t r;
@@ -188,7 +188,7 @@ fsm_event(fsm_instance *fi, int event, void *arg)
  * @param fi    Pointer to FSM
  * @param state The new state for this FSM.
  */
-extern __inline__ void
+static inline void
 fsm_newstate(fsm_instance *fi, int newstate)
 {
        atomic_set(&fi->state,newstate);
@@ -208,7 +208,7 @@ fsm_newstate(fsm_instance *fi, int newstate)
  *
  * @return The current state of the FSM.
  */
-extern __inline__ int
+static inline int
 fsm_getstate(fsm_instance *fi)
 {
        return atomic_read(&fi->state);
index 4eaa70179182a62e9b28ef8d4a356f3b3e09096b..d9ea7ed2e46e9ceead16eab686ebdff3086ee8fe 100644 (file)
@@ -88,7 +88,7 @@ struct crw {
 #define CRW_ERC_PERRI    0x07 /* perm. error, facility init */
 #define CRW_ERC_PMOD     0x08 /* installed parameters modified */
 
-extern __inline__ int stcrw(struct crw *pcrw )
+static inline int stcrw(struct crw *pcrw )
 {
         int ccode;
 
index 5028ac2143262d44418d758682c31c766f6bd21f..383a95f34a0da4e8adec682df992786d572efe27 100644 (file)
@@ -596,6 +596,8 @@ static long openprom_compat_ioctl(struct file *file, unsigned int cmd,
                lock_kernel();
                break;
        }
+
+       return rval;
 }
 
 static int openprom_open(struct inode * inode, struct file * file)
@@ -623,6 +625,7 @@ static struct file_operations openprom_fops = {
        .owner =        THIS_MODULE,
        .llseek =       no_llseek,
        .ioctl =        openprom_ioctl,
+       .compat_ioctl = openprom_compat_ioctl,
        .open =         openprom_open,
        .release =      openprom_release,
 };
index 98bad773f24087e00c3b7aa08e48f39d1cff147c..4f81fc39ec57d7525a506021433aaefec0707702 100644 (file)
@@ -54,7 +54,6 @@
 #ifndef _3W_XXXX_H
 #define _3W_XXXX_H
 
-#include <linux/version.h>
 #include <linux/types.h>
 
 /* AEN strings */
index f7a1751e892dc34b18376313213f087e0a4998c4..30a14ba77a6a3e49925e1aefb268ce90de3f4b1e 100644 (file)
@@ -2,7 +2,6 @@
 #include <linux/mm.h>
 #include <linux/blkdev.h>
 #include <linux/sched.h>
-#include <linux/version.h>
 #include <linux/init.h>
 #include <linux/interrupt.h>
 
index 052c6619accc33c0aaee5b59b6f6acd8fd0c42b3..bc44222d6cc3b5bc0dedb6e9a012833333f706b7 100644 (file)
@@ -49,7 +49,6 @@
 #include <linux/ioport.h>
 #include <linux/pci.h>
 #include <linux/smp_lock.h>
-#include <linux/version.h>
 #include <linux/interrupt.h>
 #include <linux/module.h>
 #include <linux/slab.h>
index be9edbe26dbe0c128e486379ab48ab8f48ca3c9c..f2a95447142c38db38a2e41ef023975dccc43420 100644 (file)
@@ -66,7 +66,6 @@
 #include <linux/ioport.h>
 #include <linux/pci.h>
 #include <linux/smp_lock.h>
-#include <linux/version.h>
 #include <linux/interrupt.h>
 #include <linux/module.h>
 #include <linux/slab.h>
index 5f13546d6392bff527b4749e1156c035f057d369..dea8446f536088957cd9a480446c7a0149f4db76 100644 (file)
@@ -11,7 +11,6 @@
 #include <linux/mm.h>
 #include <linux/blkdev.h>
 #include <linux/sched.h>
-#include <linux/version.h>
 #include <linux/config.h>
 #include <linux/zorro.h>
 #include <linux/stat.h>
index 29c7ed30c09e0b65d5e4c4d61b4959362c078e8e..130f30f51a9b5ec847c6a9afdd889010523b643e 100644 (file)
@@ -7,7 +7,6 @@
 #include <linux/mm.h>
 #include <linux/blkdev.h>
 #include <linux/sched.h>
-#include <linux/version.h>
 #include <linux/zorro.h>
 
 #include <asm/setup.h>
index d12342fa81999e5938313cbb9f33734a63f44998..ab22387c9df14b6affeddae3a68bcd6dc7fa9812 100644 (file)
@@ -2,7 +2,6 @@
 #include <linux/mm.h>
 #include <linux/blkdev.h>
 #include <linux/sched.h>
-#include <linux/version.h>
 #include <linux/init.h>
 #include <linux/interrupt.h>
 
index 887a5c3ded28d51126286c04ce3beaf113bd2846..8d97999db60e8c32bf0e702ae6953a27e44ef02b 100644 (file)
  */
 
 #include <linux/config.h>
-#ifndef LINUX_VERSION_CODE
-#include <linux/version.h>
-#endif
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,45)
-#error "This driver works only with kernel 2.5.45 or higher!"
-#endif
 #include <linux/module.h>
 #include <linux/kernel.h>
 #include <linux/types.h>
index 505e967013dee182d9ca7cdbfae3df9c56c81114..adc6eabbf610459e32259a097696b71287356c37 100644 (file)
@@ -50,6 +50,7 @@
 #ifndef _IPS_H_
    #define _IPS_H_
 
+#include <linux/version.h>
    #include <asm/uaccess.h>
    #include <asm/io.h>
 
index 69df1a9b935d64126c53838fc1c8d350ebf6ac6d..8e547130e97d1fad4a30f7be5431eb82eeff9ebf 100644 (file)
@@ -25,7 +25,6 @@
 #include <linux/delay.h>
 #include <linux/blkdev.h>
 #include <linux/list.h>
-#include <linux/version.h>
 #include <linux/moduleparam.h>
 #include <linux/dma-mapping.h>
 #include <asm/semaphore.h>
index 7e36c46e7c4362e543a7ee3bbebfc78123d6ac92..eb8c390a0fa3f67f25de61a1c1c1c8b13237f763 100644 (file)
@@ -18,7 +18,6 @@
 #include <linux/spinlock.h>
 #include <linux/fs.h>
 #include <asm/uaccess.h>
-#include <linux/version.h>
 #include <linux/module.h>
 #include <linux/moduleparam.h>
 #include <linux/pci.h>
index 4245d05e628b7f4ef56fe852745fbdb4cd1b96c8..801a63bea8a5e64648318be99b51d37ac75bcc4e 100644 (file)
@@ -26,7 +26,6 @@
 #include <linux/types.h>
 #include <linux/pci.h>
 #include <linux/list.h>
-#include <linux/version.h>
 #include <linux/moduleparam.h>
 #include <linux/module.h>
 #include <linux/spinlock.h>
index 2fb31ee6d9f52a83ceb4a214ca98e7101a960cc2..33380cee9b77817ec12747a27f170494944449e9 100644 (file)
@@ -2,7 +2,6 @@
 #include <linux/mm.h>
 #include <linux/blkdev.h>
 #include <linux/sched.h>
-#include <linux/version.h>
 #include <linux/interrupt.h>
 
 #include <asm/page.h>
index b2d8d8ea1604d3e040b1c52e1e161e77db3a9944..29ec699e0e4d5637caf174b04b6f0f2a941bdd5c 100644 (file)
@@ -7,7 +7,6 @@
 #include <linux/mm.h>
 #include <linux/blkdev.h>
 #include <linux/sched.h>
-#include <linux/version.h>
 
 #include <asm/page.h>
 #include <asm/pgtable.h>
index 5664398fa0ad2aa66dd083a9fdbea47aeb4938dc..5addf9fb1e156b774edf4ee41d72016776333714 100644 (file)
@@ -16,6 +16,7 @@
 #ifndef _NSP32_H
 #define _NSP32_H
 
+#include <linux/version.h>
 //#define NSP32_DEBUG 9
 
 /*
index c65afc964121930d327a81d5bec21eedf80b4b75..6c962d7dca47ac30a22c063b03e6b4ada1edc622 100644 (file)
@@ -26,9 +26,6 @@
 #ifndef        PSI_EIDE_SCSIOP
 #define        PSI_EIDE_SCSIOP 1
 
-#ifndef LINUX_VERSION_CODE
-#include <linux/version.h>
-#endif 
 #define        LINUXVERSION(v,p,s)    (((v)<<16) + ((p)<<8) + (s))
 
 /************************************************/
index aadf051274fa50483d1fe72e1ef564ea9e1f7475..b61fb1295b8bcc1cb5263ba417e01ebf3b6a70d6 100644 (file)
 
 #include <linux/stat.h>
 
-#ifndef LINUX_VERSION_CODE
-#include <linux/version.h>
-#endif
-
 #include "scsi_logging.h"
 #include "scsi_debug.h"
 
index 62e3f340cc5200c38e630ff04151852fbf1c1a32..72ec59456e6934bfd67c42b35970b5eb0b9c6a87 100644 (file)
@@ -68,10 +68,6 @@ static int sg_proc_init(void);
 static void sg_proc_cleanup(void);
 #endif
 
-#ifndef LINUX_VERSION_CODE
-#include <linux/version.h>
-#endif                         /* LINUX_VERSION_CODE */
-
 #define SG_ALLOW_DIO_DEF 0
 #define SG_ALLOW_DIO_CODE /* compile out by commenting this define */
 
index 09fd203e4b86d480ee1fda1f15986f16be5ca10e..f37147f8f7bfa2494d560f1a044132a6a3038ca3 100644 (file)
@@ -15,7 +15,6 @@
 #include <linux/types.h>
 #include <linux/mm.h>
 #include <linux/blkdev.h>
-#include <linux/version.h>
 #include <linux/delay.h>
 #include <linux/dma-mapping.h>
 #include <linux/spinlock.h>
index 5754445fb36ad500fbe59291d2455acfadbe8ff2..fd63add6a577aba8ab03c1389e0ef7497ffc789f 100644 (file)
@@ -77,7 +77,6 @@
 #include <linux/sched.h>
 #include <linux/string.h>
 #include <linux/delay.h>
-#include <linux/version.h>
 #include <linux/init.h>
 #include <linux/blkdev.h>
 #include <asm/irq.h>
index 51e3f7f6597b2dfba83ecc26bb23dbe95408e43c..fbea4541c234bbcd4a83b9cdb4ddf75141e36aa2 100644 (file)
@@ -40,7 +40,6 @@
  *****************************************************************************/
 #define IXJ_VERSION 3031
 
-#include <linux/version.h>
 #include <linux/types.h>
 
 #include <linux/ixjuser.h>
index 975ace3f5b1eac13362d2be4f51c8514ffac5899..904519085334e8e6bb16f6e3ac79ac0a44a3b1a6 100644 (file)
@@ -49,7 +49,6 @@
 #include <linux/timer.h>
 #include <linux/list.h>
 #include <linux/interrupt.h>
-#include <linux/version.h>
 #include <linux/platform_device.h>
 #include <linux/usb.h>
 #include <linux/usb_gadget.h>
index 1bb455c045a979bffb9a7e6eda9eab28422ef243..9b2e6f7cbb8b3dc37980e8944074c89cd381c130 100644 (file)
@@ -29,7 +29,6 @@
 #include <linux/kernel.h>
 #include <linux/ioport.h>
 #include <linux/types.h>
-#include <linux/version.h>
 #include <linux/errno.h>
 #include <linux/delay.h>
 #include <linux/sched.h>
index ee9cd7869d9268723e00451839bb132b6e4f9440..510d28a924db95501edb3c69402148a9df208ea3 100644 (file)
@@ -32,7 +32,6 @@
 #include <linux/kernel.h>
 #include <linux/ioport.h>
 #include <linux/types.h>
-#include <linux/version.h>
 #include <linux/errno.h>
 #include <linux/delay.h>
 #include <linux/sched.h>
index 06b6eba925b59e5542378eca866387fe4ba9c15e..9689efeb364c20ab38a499d5106a0c122bb43d4c 100644 (file)
@@ -28,7 +28,6 @@
 #include <linux/moduleparam.h>
 #include <linux/kernel.h>
 #include <linux/errno.h>
-#include <linux/version.h>
 #include <linux/init.h>
 #include <linux/list.h>
 #include <linux/proc_fs.h>
index a8267cf17db4685b34da64dd1c4adec99fb5642c..0eaabeb37ac31ffe82049fa0de91753fa080ad91 100644 (file)
@@ -14,7 +14,6 @@
 #include <linux/unistd.h>
 #include <linux/interrupt.h>
 #include <linux/init.h>
-#include <linux/version.h>
 #include <linux/list.h>
 #include <linux/spinlock.h>
 
index b77e65c03659a0bdffda1a758f7ef04beb44201d..5524fd70210b3dc984b1160dd7a9a19249280404 100644 (file)
@@ -62,6 +62,7 @@
 #include <linux/poll.h>
 #include <linux/slab.h>
 #include <linux/vmalloc.h>
+#include <linux/version.h>
 #include <asm/io.h>
 
 #include "pwc.h"
index 267869dab185ad5146e8cab0473a0960528acc41..6dd76bb3dff16ae4f95f53744df0b094c4e3670c 100644 (file)
@@ -25,8 +25,6 @@
 #ifndef PWC_H
 #define PWC_H
 
-#include <linux/version.h>
-
 #include <linux/config.h>
 #include <linux/module.h>
 #include <linux/usb.h>
index f36c0b6c6e36cd3db2665863f001c93606f9f1c0..67612c81cb9fda53cc2313d3cde8a7b8cb410246 100644 (file)
@@ -25,7 +25,6 @@
  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.               *
  ***************************************************************************/
 
-#include <linux/version.h>
 #include <linux/module.h>
 #include <linux/kernel.h>
 #include <linux/kmod.h>
index c946c9a538a0602d3255ac66f3402a1428886138..41ef2b606751fc38c034ba8906809170fe78d9ec 100644 (file)
@@ -37,7 +37,6 @@
  */
 
 #include <linux/config.h>
-#include <linux/version.h>
 #include <linux/module.h>
 #include <linux/kernel.h>
 #include <linux/signal.h>
index 401ff21d7881c2a0a0c7383b102f1527f6abc77b..1d7a77cc7c4a90045d9a7ff3f6e663a0dd6622f6 100644 (file)
@@ -37,6 +37,7 @@
 #ifndef _SISUSB_H_
 #define _SISUSB_H_
 
+#include <linux/version.h>
 #ifdef CONFIG_COMPAT
 #if LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,10)
 #include <linux/ioctl32.h>
index 24584463553dfdd5050ef61aa88a9cf5a9c21b2c..be5c1a25ae21c1282b7a5d4637b8036b632e2192 100644 (file)
@@ -48,7 +48,6 @@
  */
 
 #include <linux/config.h>
-#include <linux/version.h>
 #include <linux/module.h>
 #include <linux/kernel.h>
 #include <linux/signal.h>
index f28bc240f9b695e0ea5cb55aa8b7143219a0cdf5..044fa4482f9f471764d99feaa43f9e8af01dfcda 100644 (file)
@@ -37,7 +37,6 @@
  */
 
 #include <linux/config.h>
-#include <linux/version.h>
 #include <linux/module.h>
 #include <linux/kernel.h>
 #include <linux/errno.h>
index 44b6ca290ce36bdcde56a22a8ec13b02e5fa8fd8..25b6ca6ad081a17d4c69ffe11cd388595a530291 100644 (file)
@@ -593,38 +593,6 @@ config FB_EPSON1355
          framebuffer.  Product specs at
          <http://www.erd.epson.com/vdc/html/products.htm>.
 
-config FB_E1356
-       tristate "Epson SED1356 framebuffer support"
-       depends on FB && EXPERIMENTAL && PCI && MIPS
-
-config PB1000_CRT
-       bool "Use CRT on Pb1000 (J65)"
-       depends on MIPS_PB1000=y && FB_E1356
-
-config PB1000_NTSC
-       bool "Use Compsite NTSC on Pb1000 (J63)"
-       depends on MIPS_PB1000=y && FB_E1356
-
-config PB1000_TFT
-       bool "Use TFT Panel on Pb1000 (J64)"
-       depends on MIPS_PB1000=y && FB_E1356
-
-config PB1500_CRT
-       bool "Use CRT on Pb1500 " if MIPS_PB1500=y
-       depends on FB_E1356
-
-config PB1500_CRT
-       prompt "Use CRT on Pb1100 "
-       depends on FB_E1356 && MIPS_PB1100=y
-
-config PB1500_TFT
-       bool "Use TFT Panel on Pb1500 " if MIPS_PB1500=y
-       depends on FB_E1356
-
-config PB1500_TFT
-       prompt "Use TFT Panel on Pb1100 "
-       depends on FB_E1356 && MIPS_PB1100=y
-
 config FB_S1D13XXX
        tristate "Epson S1D13XXX framebuffer support"
        depends on FB
index 467a1d7ebbdecdf14f129a34c172e8e0ae5ae5d9..a3c2c45e29e03e7d9e42a64036501904305ee4df 100644 (file)
@@ -518,7 +518,7 @@ static struct amba_driver clcd_driver = {
        .id_table       = clcdfb_id_table,
 };
 
-int __init amba_clcdfb_init(void)
+static int __init amba_clcdfb_init(void)
 {
        if (fb_get_options("ambafb", NULL))
                return -ENODEV;
index acc81cb01d566d709260b3889b386b835fdb2612..9d5015e99372c4d0f9f6c67fa95f39f9d460eb85 100644 (file)
@@ -5,7 +5,6 @@
  *
  */
 
-#include <linux/version.h>
 #include <linux/module.h>
 #include <linux/init.h>
 #include <linux/device.h>
index 470e6f0ee4dd808a21fdee829d5404f6a2ab74e2..68c690605aa7cfc9469c1189bee9200c0ba7639b 100644 (file)
@@ -5,7 +5,6 @@
  *
  */
 
-#include <linux/version.h>
 #include <linux/module.h>
 #include <linux/init.h>
 #include <linux/device.h>
index da664cea7ecac216072d5fda2aeaa05178a3e696..a7770c4f17d08f980c9e8724dc9e1d07ddd27ac5 100644 (file)
@@ -80,10 +80,12 @@ static u32 cfb_tab32[] = {
 #define LEFT_POS(bpp)          (32 - bpp)
 #define SHIFT_HIGH(val, bits)  ((val) >> (bits))
 #define SHIFT_LOW(val, bits)   ((val) << (bits))
+#define BIT_NR(b)              (7 - (b))
 #else
 #define LEFT_POS(bpp)          (0)
 #define SHIFT_HIGH(val, bits)  ((val) << (bits))
 #define SHIFT_LOW(val, bits)   ((val) >> (bits))
+#define BIT_NR(b)              (b)
 #endif
 
 static inline void color_imageblit(const struct fb_image *image, 
@@ -177,7 +179,7 @@ static inline void slow_imageblit(const struct fb_image *image, struct fb_info *
 
                while (j--) {
                        l--;
-                       color = (*s & (1 << l)) ? fgcolor : bgcolor;
+                       color = (*s & 1 << (BIT_NR(l))) ? fgcolor : bgcolor;
                        color <<= LEFT_POS(bpp);
                        val |= SHIFT_HIGH(color, shift);
                        
index fadf7c5d216e8dbae9c43c0a9eb8e91889e3dee6..94c5f1392ccedb29ecb0dd1d37b31372976e121f 100644 (file)
@@ -101,6 +101,16 @@ config FRAMEBUFFER_CONSOLE
        help
          Low-level framebuffer-based console driver.
 
+config FRAMEBUFFER_CONSOLE_ROTATION
+       bool "Framebuffer Console Rotation"
+       depends on FRAMEBUFFER_CONSOLE
+       help
+         Enable display rotation for the framebuffer console.  This is done
+         in software and may be significantly slower than a normally oriented
+         display.  Note that the rotation is done at the console level only
+         such that other users of the framebuffer will remain normally
+         oriented.
+
 config STI_CONSOLE
         tristate "STI text console" 
         depends on PARISC
index 5222628accce31ca8ea63ce844909dc2a286b64a..fed600c9ca5578fb9142f23d5849c7325c7f8450 100644 (file)
@@ -31,6 +31,10 @@ obj-$(CONFIG_FRAMEBUFFER_CONSOLE) += fbcon.o bitblit.o font.o softcursor.o
 ifeq ($(CONFIG_FB_TILEBLITTING),y)
 obj-$(CONFIG_FRAMEBUFFER_CONSOLE)     += tileblit.o
 endif
+ifeq ($(CONFIG_FRAMEBUFFER_CONSOLE_ROTATION),y)
+obj-$(CONFIG_FRAMEBUFFER_CONSOLE)     += fbcon_rotate.o fbcon_cw.o fbcon_ud.o \
+                                         fbcon_ccw.o
+endif
 
 obj-$(CONFIG_FB_STI)              += sticore.o font.o
 
index 67857b3cfc8b416f4fe081e940c634ee85531681..e65fc3ef7630ad5ac117843871d0fd9ad04476b3 100644 (file)
 /*
  * Accelerated handlers.
  */
-#define FBCON_ATTRIBUTE_UNDERLINE 1
-#define FBCON_ATTRIBUTE_REVERSE   2
-#define FBCON_ATTRIBUTE_BOLD      4
-
-static inline int real_y(struct display *p, int ypos)
-{
-       int rows = p->vrows;
-
-       ypos += p->yscroll;
-       return ypos < rows ? ypos : ypos - rows;
-}
-
-
-static inline int get_attribute(struct fb_info *info, u16 c)
-{
-       int attribute = 0;
-
-       if (fb_get_color_depth(&info->var, &info->fix) == 1) {
-               if (attr_underline(c))
-                       attribute |= FBCON_ATTRIBUTE_UNDERLINE;
-               if (attr_reverse(c))
-                       attribute |= FBCON_ATTRIBUTE_REVERSE;
-               if (attr_bold(c))
-                       attribute |= FBCON_ATTRIBUTE_BOLD;
-       }
-
-       return attribute;
-}
-
 static inline void update_attr(u8 *dst, u8 *src, int attribute,
                               struct vc_data *vc)
 {
@@ -418,6 +389,18 @@ static void bit_cursor(struct vc_data *vc, struct fb_info *info,
        ops->cursor_reset = 0;
 }
 
+static int bit_update_start(struct fb_info *info)
+{
+       struct fbcon_ops *ops = info->fbcon_par;
+       int err;
+
+       err = fb_pan_display(info, &ops->var);
+       ops->var.xoffset = info->var.xoffset;
+       ops->var.yoffset = info->var.yoffset;
+       ops->var.vmode = info->var.vmode;
+       return err;
+}
+
 void fbcon_set_bitops(struct fbcon_ops *ops)
 {
        ops->bmove = bit_bmove;
@@ -425,6 +408,11 @@ void fbcon_set_bitops(struct fbcon_ops *ops)
        ops->putcs = bit_putcs;
        ops->clear_margins = bit_clear_margins;
        ops->cursor = bit_cursor;
+       ops->update_start = bit_update_start;
+       ops->rotate_font = NULL;
+
+       if (ops->rotate)
+               fbcon_set_rotate(ops);
 }
 
 EXPORT_SYMBOL(fbcon_set_bitops);
index 3cf1b61ff1f8a1dfbdedade08a89cee7381e0c22..e7802ffe549ae402144f82aaf052e0ada28de9be 100644 (file)
@@ -107,6 +107,8 @@ enum {
 };
 
 struct display fb_display[MAX_NR_CONSOLES];
+EXPORT_SYMBOL(fb_display);
+
 static signed char con2fb_map[MAX_NR_CONSOLES];
 static signed char con2fb_map_boot[MAX_NR_CONSOLES];
 static int logo_height;
@@ -130,6 +132,9 @@ static char fontname[40];
 /* current fb_info */
 static int info_idx = -1;
 
+/* console rotation */
+static int rotate;
+
 static const struct consw fb_con;
 
 #define CM_SOFTBACK    (8)
@@ -176,7 +181,6 @@ static int fbcon_scrolldelta(struct vc_data *vc, int lines);
 /*
  *  Internal routines
  */
-static __inline__ int real_y(struct display *p, int ypos);
 static __inline__ void ywrap_up(struct vc_data *vc, int count);
 static __inline__ void ywrap_down(struct vc_data *vc, int count);
 static __inline__ void ypan_up(struct vc_data *vc, int count);
@@ -189,6 +193,8 @@ static void fbcon_preset_disp(struct fb_info *info, struct fb_var_screeninfo *va
                              int unit);
 static void fbcon_redraw_move(struct vc_data *vc, struct display *p,
                              int line, int count, int dy);
+static void fbcon_modechanged(struct fb_info *info);
+static void fbcon_set_all_vcs(struct fb_info *info);
 
 #ifdef CONFIG_MAC
 /*
@@ -203,6 +209,88 @@ static irqreturn_t fb_vbl_detect(int irq, void *dummy, struct pt_regs *fp)
 }
 #endif
 
+#ifdef CONFIG_FRAMEBUFFER_CONSOLE_ROTATION
+static inline void fbcon_set_rotation(struct fb_info *info, struct display *p)
+{
+       struct fbcon_ops *ops = info->fbcon_par;
+
+       if (!(info->flags & FBINFO_MISC_TILEBLITTING) &&
+           p->con_rotate < 4)
+               ops->rotate = p->con_rotate;
+       else
+               ops->rotate = 0;
+}
+
+static void fbcon_rotate(struct fb_info *info, u32 rotate)
+{
+       struct fbcon_ops *ops= info->fbcon_par;
+       struct fb_info *fb_info;
+
+       if (!ops || ops->currcon == -1)
+               return;
+
+       fb_info = registered_fb[con2fb_map[ops->currcon]];
+
+       if (info == fb_info) {
+               struct display *p = &fb_display[ops->currcon];
+
+               if (rotate < 4)
+                       p->con_rotate = rotate;
+               else
+                       p->con_rotate = 0;
+
+               fbcon_modechanged(info);
+       }
+}
+
+static void fbcon_rotate_all(struct fb_info *info, u32 rotate)
+{
+       struct fbcon_ops *ops = info->fbcon_par;
+       struct vc_data *vc;
+       struct display *p;
+       int i;
+
+       if (!ops || ops->currcon < 0 || rotate > 3)
+               return;
+
+       for (i = 0; i < MAX_NR_CONSOLES; i++) {
+               vc = vc_cons[i].d;
+               if (!vc || vc->vc_mode != KD_TEXT ||
+                   registered_fb[con2fb_map[i]] != info)
+                       continue;
+
+               p = &fb_display[vc->vc_num];
+               p->con_rotate = rotate;
+       }
+
+       fbcon_set_all_vcs(info);
+}
+#else
+static inline void fbcon_set_rotation(struct fb_info *info, struct display *p)
+{
+       struct fbcon_ops *ops = info->fbcon_par;
+
+       ops->rotate = FB_ROTATE_UR;
+}
+
+static void fbcon_rotate(struct fb_info *info, u32 rotate)
+{
+       return;
+}
+
+static void fbcon_rotate_all(struct fb_info *info, u32 rotate)
+{
+       return;
+}
+#endif /* CONFIG_FRAMEBUFFER_CONSOLE_ROTATION */
+
+static int fbcon_get_rotate(struct fb_info *info)
+{
+       struct fbcon_ops *ops = info->fbcon_par;
+
+       return (ops) ? ops->rotate : 0;
+}
+
 static inline int fbcon_is_inactive(struct vc_data *vc, struct fb_info *info)
 {
        struct fbcon_ops *ops = info->fbcon_par;
@@ -422,6 +510,14 @@ static int __init fb_console_setup(char *this_opt)
                                last_fb_vc = simple_strtoul(options, &options, 10) - 1;
                        fbcon_is_default = 0; 
                }       
+
+               if (!strncmp(options, "rotate:", 7)) {
+                       options += 7;
+                       if (*options)
+                               rotate = simple_strtoul(options, &options, 0);
+                       if (rotate > 3)
+                               rotate = 0;
+               }
        }
        return 0;
 }
@@ -480,6 +576,7 @@ static void fbcon_prepare_logo(struct vc_data *vc, struct fb_info *info,
                               int cols, int rows, int new_cols, int new_rows)
 {
        /* Need to make room for the logo */
+       struct fbcon_ops *ops = info->fbcon_par;
        int cnt, erase = vc->vc_video_erase_char, step;
        unsigned short *save = NULL, *r, *q;
 
@@ -489,7 +586,7 @@ static void fbcon_prepare_logo(struct vc_data *vc, struct fb_info *info,
         */
        if (fb_get_color_depth(&info->var, &info->fix) == 1)
                erase &= ~0x400;
-       logo_height = fb_prepare_logo(info);
+       logo_height = fb_prepare_logo(info, ops->rotate);
        logo_lines = (logo_height + vc->vc_font.height - 1) /
                vc->vc_font.height;
        q = (unsigned short *) (vc->vc_origin +
@@ -558,16 +655,24 @@ static void set_blitting_type(struct vc_data *vc, struct fb_info *info,
 
        if ((info->flags & FBINFO_MISC_TILEBLITTING))
                fbcon_set_tileops(vc, info, p, ops);
-       else
+       else {
+               struct display *disp;
+
+               disp = (p) ? p : &fb_display[vc->vc_num];
+               fbcon_set_rotation(info, disp);
                fbcon_set_bitops(ops);
+       }
 }
 #else
 static void set_blitting_type(struct vc_data *vc, struct fb_info *info,
                              struct display *p)
 {
        struct fbcon_ops *ops = info->fbcon_par;
+       struct display *disp;
 
        info->flags &= ~FBINFO_MISC_TILEBLITTING;
+       disp = (p) ? p : &fb_display[vc->vc_num];
+       fbcon_set_rotation(info, disp);
        fbcon_set_bitops(ops);
 }
 #endif /* CONFIG_MISC_TILEBLITTING */
@@ -627,6 +732,7 @@ static int con2fb_release_oldinfo(struct vc_data *vc, struct fb_info *oldinfo,
                fbcon_del_cursor_timer(oldinfo);
                kfree(ops->cursor_state.mask);
                kfree(ops->cursor_data);
+               kfree(ops->fontbuffer);
                kfree(oldinfo->fbcon_par);
                oldinfo->fbcon_par = NULL;
                module_put(oldinfo->fbops->owner);
@@ -827,7 +933,9 @@ static const char *fbcon_startup(void)
        memset(ops, 0, sizeof(struct fbcon_ops));
        ops->currcon = -1;
        ops->graphics = 1;
+       ops->cur_rotate = -1;
        info->fbcon_par = ops;
+       p->con_rotate = rotate;
        set_blitting_type(vc, info, NULL);
 
        if (info->fix.type != FB_TYPE_TEXT) {
@@ -866,8 +974,10 @@ static const char *fbcon_startup(void)
                vc->vc_font.charcount = 256; /* FIXME  Need to support more fonts */
        }
 
-       cols = info->var.xres / vc->vc_font.width;
-       rows = info->var.yres / vc->vc_font.height;
+       cols = FBCON_SWAP(ops->rotate, info->var.xres, info->var.yres);
+       rows = FBCON_SWAP(ops->rotate, info->var.yres, info->var.xres);
+       cols /= vc->vc_font.width;
+       rows /= vc->vc_font.height;
        vc_resize(vc, cols, rows);
 
        DPRINTK("mode:   %s\n", info->fix.id);
@@ -953,8 +1063,6 @@ static void fbcon_init(struct vc_data *vc, int init)
            (info->fix.type == FB_TYPE_TEXT))
                logo = 0;
 
-       info->var.xoffset = info->var.yoffset = p->yscroll = 0; /* reset wrap/pan */
-
        if (var_to_display(p, &info->var, info))
                return;
 
@@ -986,13 +1094,18 @@ static void fbcon_init(struct vc_data *vc, int init)
        if (!*vc->vc_uni_pagedir_loc)
                con_copy_unimap(vc, svc);
 
+       ops = info->fbcon_par;
+       p->con_rotate = rotate;
+       set_blitting_type(vc, info, NULL);
+
        cols = vc->vc_cols;
        rows = vc->vc_rows;
-       new_cols = info->var.xres / vc->vc_font.width;
-       new_rows = info->var.yres / vc->vc_font.height;
+       new_cols = FBCON_SWAP(ops->rotate, info->var.xres, info->var.yres);
+       new_rows = FBCON_SWAP(ops->rotate, info->var.yres, info->var.xres);
+       new_cols /= vc->vc_font.width;
+       new_rows /= vc->vc_font.height;
        vc_resize(vc, new_cols, new_rows);
 
-       ops = info->fbcon_par;
        /*
         * We must always set the mode. The mode of the previous console
         * driver could be in the same resolution but we are using different
@@ -1030,6 +1143,12 @@ static void fbcon_init(struct vc_data *vc, int init)
 
        if (vc == svc && softback_buf)
                fbcon_update_softback(vc);
+
+       if (ops->rotate_font && ops->rotate_font(info, vc, p)) {
+               ops->rotate = FB_ROTATE_UR;
+               set_blitting_type(vc, info, p);
+       }
+
 }
 
 static void fbcon_deinit(struct vc_data *vc)
@@ -1066,15 +1185,6 @@ static void fbcon_deinit(struct vc_data *vc)
  *  restriction is simplicity & efficiency at the moment.
  */
 
-static __inline__ int real_y(struct display *p, int ypos)
-{
-       int rows = p->vrows;
-
-       ypos += p->yscroll;
-       return ypos < rows ? ypos : ypos - rows;
-}
-
-
 static void fbcon_clear(struct vc_data *vc, int sy, int sx, int height,
                        int width)
 {
@@ -1162,13 +1272,6 @@ static int scrollback_phys_max = 0;
 static int scrollback_max = 0;
 static int scrollback_current = 0;
 
-static int update_var(int con, struct fb_info *info)
-{
-       if (con == ((struct fbcon_ops *)info->fbcon_par)->currcon)
-               return fb_pan_display(info, &info->var);
-       return 0;
-}
-
 /*
  * If no vc is existent yet, just set struct display
  */
@@ -1178,7 +1281,6 @@ static void fbcon_preset_disp(struct fb_info *info, struct fb_var_screeninfo *va
        struct display *p = &fb_display[unit];
        struct display *t = &fb_display[fg_console];
 
-       var->xoffset = var->yoffset = p->yscroll = 0;
        if (var_to_display(p, var, info))
                return;
 
@@ -1194,9 +1296,9 @@ static void fbcon_set_disp(struct fb_info *info, struct fb_var_screeninfo *var,
        struct display *p = &fb_display[vc->vc_num], *t;
        struct vc_data **default_mode = vc->vc_display_fg;
        struct vc_data *svc = *default_mode;
+       struct fbcon_ops *ops = info->fbcon_par;
        int rows, cols, charcnt = 256;
 
-       var->xoffset = var->yoffset = p->yscroll = 0;
        if (var_to_display(p, var, info))
                return;
        t = &fb_display[svc->vc_num];
@@ -1213,9 +1315,10 @@ static void fbcon_set_disp(struct fb_info *info, struct fb_var_screeninfo *var,
 
        var->activate = FB_ACTIVATE_NOW;
        info->var.activate = var->activate;
-       info->var.yoffset = info->var.xoffset = 0;
+       var->yoffset = info->var.yoffset;
+       var->xoffset = info->var.xoffset;
        fb_set_var(info, var);
-
+       ops->var = info->var;
        vc->vc_can_do_color = (fb_get_color_depth(&info->var, &info->fix)!=1);
        vc->vc_complement_mask = vc->vc_can_do_color ? 0x7700 : 0x0800;
        if (charcnt == 256) {
@@ -1231,9 +1334,12 @@ static void fbcon_set_disp(struct fb_info *info, struct fb_var_screeninfo *var,
        if (!*vc->vc_uni_pagedir_loc)
                con_copy_unimap(vc, svc);
 
-       cols = var->xres / vc->vc_font.width;
-       rows = var->yres / vc->vc_font.height;
+       cols = FBCON_SWAP(ops->rotate, info->var.xres, info->var.yres);
+       rows = FBCON_SWAP(ops->rotate, info->var.yres, info->var.xres);
+       cols /= vc->vc_font.width;
+       rows /= vc->vc_font.height;
        vc_resize(vc, cols, rows);
+
        if (CON_IS_VISIBLE(vc)) {
                update_screen(vc);
                if (softback_buf)
@@ -1244,15 +1350,16 @@ static void fbcon_set_disp(struct fb_info *info, struct fb_var_screeninfo *var,
 static __inline__ void ywrap_up(struct vc_data *vc, int count)
 {
        struct fb_info *info = registered_fb[con2fb_map[vc->vc_num]];
+       struct fbcon_ops *ops = info->fbcon_par;
        struct display *p = &fb_display[vc->vc_num];
        
        p->yscroll += count;
        if (p->yscroll >= p->vrows)     /* Deal with wrap */
                p->yscroll -= p->vrows;
-       info->var.xoffset = 0;
-       info->var.yoffset = p->yscroll * vc->vc_font.height;
-       info->var.vmode |= FB_VMODE_YWRAP;
-       update_var(vc->vc_num, info);
+       ops->var.xoffset = 0;
+       ops->var.yoffset = p->yscroll * vc->vc_font.height;
+       ops->var.vmode |= FB_VMODE_YWRAP;
+       ops->update_start(info);
        scrollback_max += count;
        if (scrollback_max > scrollback_phys_max)
                scrollback_max = scrollback_phys_max;
@@ -1262,15 +1369,16 @@ static __inline__ void ywrap_up(struct vc_data *vc, int count)
 static __inline__ void ywrap_down(struct vc_data *vc, int count)
 {
        struct fb_info *info = registered_fb[con2fb_map[vc->vc_num]];
+       struct fbcon_ops *ops = info->fbcon_par;
        struct display *p = &fb_display[vc->vc_num];
        
        p->yscroll -= count;
        if (p->yscroll < 0)     /* Deal with wrap */
                p->yscroll += p->vrows;
-       info->var.xoffset = 0;
-       info->var.yoffset = p->yscroll * vc->vc_font.height;
-       info->var.vmode |= FB_VMODE_YWRAP;
-       update_var(vc->vc_num, info);
+       ops->var.xoffset = 0;
+       ops->var.yoffset = p->yscroll * vc->vc_font.height;
+       ops->var.vmode |= FB_VMODE_YWRAP;
+       ops->update_start(info);
        scrollback_max -= count;
        if (scrollback_max < 0)
                scrollback_max = 0;
@@ -1289,10 +1397,11 @@ static __inline__ void ypan_up(struct vc_data *vc, int count)
                            0, 0, 0, vc->vc_rows, vc->vc_cols);
                p->yscroll -= p->vrows - vc->vc_rows;
        }
-       info->var.xoffset = 0;
-       info->var.yoffset = p->yscroll * vc->vc_font.height;
-       info->var.vmode &= ~FB_VMODE_YWRAP;
-       update_var(vc->vc_num, info);
+
+       ops->var.xoffset = 0;
+       ops->var.yoffset = p->yscroll * vc->vc_font.height;
+       ops->var.vmode &= ~FB_VMODE_YWRAP;
+       ops->update_start(info);
        fbcon_clear_margins(vc, 1);
        scrollback_max += count;
        if (scrollback_max > scrollback_phys_max)
@@ -1303,6 +1412,7 @@ static __inline__ void ypan_up(struct vc_data *vc, int count)
 static __inline__ void ypan_up_redraw(struct vc_data *vc, int t, int count)
 {
        struct fb_info *info = registered_fb[con2fb_map[vc->vc_num]];
+       struct fbcon_ops *ops = info->fbcon_par;
        struct display *p = &fb_display[vc->vc_num];
        int redraw = 0;
 
@@ -1312,12 +1422,13 @@ static __inline__ void ypan_up_redraw(struct vc_data *vc, int t, int count)
                redraw = 1;
        }
 
-       info->var.xoffset = 0;
-       info->var.yoffset = p->yscroll * vc->vc_font.height;
-       info->var.vmode &= ~FB_VMODE_YWRAP;
        if (redraw)
                fbcon_redraw_move(vc, p, t + count, vc->vc_rows - count, t);
-       update_var(vc->vc_num, info);
+
+       ops->var.xoffset = 0;
+       ops->var.yoffset = p->yscroll * vc->vc_font.height;
+       ops->var.vmode &= ~FB_VMODE_YWRAP;
+       ops->update_start(info);
        fbcon_clear_margins(vc, 1);
        scrollback_max += count;
        if (scrollback_max > scrollback_phys_max)
@@ -1337,10 +1448,11 @@ static __inline__ void ypan_down(struct vc_data *vc, int count)
                            0, vc->vc_rows, vc->vc_cols);
                p->yscroll += p->vrows - vc->vc_rows;
        }
-       info->var.xoffset = 0;
-       info->var.yoffset = p->yscroll * vc->vc_font.height;
-       info->var.vmode &= ~FB_VMODE_YWRAP;
-       update_var(vc->vc_num, info);
+
+       ops->var.xoffset = 0;
+       ops->var.yoffset = p->yscroll * vc->vc_font.height;
+       ops->var.vmode &= ~FB_VMODE_YWRAP;
+       ops->update_start(info);
        fbcon_clear_margins(vc, 1);
        scrollback_max -= count;
        if (scrollback_max < 0)
@@ -1351,6 +1463,7 @@ static __inline__ void ypan_down(struct vc_data *vc, int count)
 static __inline__ void ypan_down_redraw(struct vc_data *vc, int t, int count)
 {
        struct fb_info *info = registered_fb[con2fb_map[vc->vc_num]];
+       struct fbcon_ops *ops = info->fbcon_par;
        struct display *p = &fb_display[vc->vc_num];
        int redraw = 0;
 
@@ -1359,12 +1472,14 @@ static __inline__ void ypan_down_redraw(struct vc_data *vc, int t, int count)
                p->yscroll += p->vrows - vc->vc_rows;
                redraw = 1;
        }
-       info->var.xoffset = 0;
-       info->var.yoffset = p->yscroll * vc->vc_font.height;
-       info->var.vmode &= ~FB_VMODE_YWRAP;
+
        if (redraw)
                fbcon_redraw_move(vc, p, t, vc->vc_rows - count, t + count);
-       update_var(vc->vc_num, info);
+
+       ops->var.xoffset = 0;
+       ops->var.yoffset = p->yscroll * vc->vc_font.height;
+       ops->var.vmode &= ~FB_VMODE_YWRAP;
+       ops->update_start(info);
        fbcon_clear_margins(vc, 1);
        scrollback_max -= count;
        if (scrollback_max < 0)
@@ -1838,31 +1953,41 @@ static void fbcon_bmove_rec(struct vc_data *vc, struct display *p, int sy, int s
                   height, width);
 }
 
-static __inline__ void updatescrollmode(struct display *p, struct fb_info *info,
+static __inline__ void updatescrollmode(struct display *p,
+                                       struct fb_info *info,
                                        struct vc_data *vc)
 {
+       struct fbcon_ops *ops = info->fbcon_par;
        int fh = vc->vc_font.height;
        int cap = info->flags;
-       int good_pan = (cap & FBINFO_HWACCEL_YPAN)
-                && divides(info->fix.ypanstep, vc->vc_font.height)
-                && info->var.yres_virtual > info->var.yres;
-       int good_wrap = (cap & FBINFO_HWACCEL_YWRAP)
-                && divides(info->fix.ywrapstep, vc->vc_font.height)
-                && divides(vc->vc_font.height, info->var.yres_virtual);
+       u16 t = 0;
+       int ypan = FBCON_SWAP(ops->rotate, info->fix.ypanstep,
+                                 info->fix.xpanstep);
+       int ywrap = FBCON_SWAP(ops->rotate, info->fix.ywrapstep, t);
+       int yres = FBCON_SWAP(ops->rotate, info->var.yres, info->var.xres);
+       int vyres = FBCON_SWAP(ops->rotate, info->var.yres_virtual,
+                                  info->var.xres_virtual);
+       int good_pan = (cap & FBINFO_HWACCEL_YPAN) &&
+               divides(ypan, vc->vc_font.height) && vyres > yres;
+       int good_wrap = (cap & FBINFO_HWACCEL_YWRAP) &&
+               divides(ywrap, vc->vc_font.height) &&
+               divides(vc->vc_font.height, vyres);
        int reading_fast = cap & FBINFO_READS_FAST;
-       int fast_copyarea = (cap & FBINFO_HWACCEL_COPYAREA) && !(cap & FBINFO_HWACCEL_DISABLED);
-       int fast_imageblit = (cap & FBINFO_HWACCEL_IMAGEBLIT) && !(cap & FBINFO_HWACCEL_DISABLED);
-
-       p->vrows = info->var.yres_virtual/fh;
-       if (info->var.yres > (fh * (vc->vc_rows + 1)))
-               p->vrows -= (info->var.yres - (fh * vc->vc_rows)) / fh;
-       if ((info->var.yres % fh) && (info->var.yres_virtual % fh <
-                                     info->var.yres % fh))
+       int fast_copyarea = (cap & FBINFO_HWACCEL_COPYAREA) &&
+               !(cap & FBINFO_HWACCEL_DISABLED);
+       int fast_imageblit = (cap & FBINFO_HWACCEL_IMAGEBLIT) &&
+               !(cap & FBINFO_HWACCEL_DISABLED);
+
+       p->vrows = vyres/fh;
+       if (yres > (fh * (vc->vc_rows + 1)))
+               p->vrows -= (yres - (fh * vc->vc_rows)) / fh;
+       if ((yres % fh) && (vyres % fh < yres % fh))
                p->vrows--;
 
        if (good_wrap || good_pan) {
                if (reading_fast || fast_copyarea)
-                       p->scrollmode = good_wrap ? SCROLL_WRAP_MOVE : SCROLL_PAN_MOVE;
+                       p->scrollmode = good_wrap ?
+                               SCROLL_WRAP_MOVE : SCROLL_PAN_MOVE;
                else
                        p->scrollmode = good_wrap ? SCROLL_REDRAW :
                                SCROLL_PAN_REDRAW;
@@ -1878,17 +2003,23 @@ static int fbcon_resize(struct vc_data *vc, unsigned int width,
                        unsigned int height)
 {
        struct fb_info *info = registered_fb[con2fb_map[vc->vc_num]];
+       struct fbcon_ops *ops = info->fbcon_par;
        struct display *p = &fb_display[vc->vc_num];
        struct fb_var_screeninfo var = info->var;
-       int x_diff, y_diff;
-       int fw = vc->vc_font.width;
-       int fh = vc->vc_font.height;
-
-       var.xres = width * fw;
-       var.yres = height * fh;
+       int x_diff, y_diff, virt_w, virt_h, virt_fw, virt_fh;
+
+       virt_w = FBCON_SWAP(ops->rotate, width, height);
+       virt_h = FBCON_SWAP(ops->rotate, height, width);
+       virt_fw = FBCON_SWAP(ops->rotate, vc->vc_font.width,
+                                vc->vc_font.height);
+       virt_fh = FBCON_SWAP(ops->rotate, vc->vc_font.height,
+                                vc->vc_font.width);
+       var.xres = virt_w * virt_fw;
+       var.yres = virt_h * virt_fh;
        x_diff = info->var.xres - var.xres;
        y_diff = info->var.yres - var.yres;
-       if (x_diff < 0 || x_diff > fw || (y_diff < 0 || y_diff > fh)) {
+       if (x_diff < 0 || x_diff > virt_fw ||
+           y_diff < 0 || y_diff > virt_fh) {
                struct fb_videomode *mode;
 
                DPRINTK("attempting resize %ix%i\n", var.xres, var.yres);
@@ -1898,7 +2029,7 @@ static int fbcon_resize(struct vc_data *vc, unsigned int width,
                display_to_var(&var, p);
                fb_videomode_to_var(&var, mode);
 
-               if (width > var.xres/fw || height > var.yres/fh)
+               if (virt_w > var.xres/virt_fw || virt_h > var.yres/virt_fh)
                        return -EINVAL;
 
                DPRINTK("resize now %ix%i\n", var.xres, var.yres);
@@ -1908,6 +2039,7 @@ static int fbcon_resize(struct vc_data *vc, unsigned int width,
                        fb_set_var(info, &var);
                }
                var_to_display(p, &info->var, info);
+               ops->var = info->var;
        }
        updatescrollmode(p, info, vc);
        return 0;
@@ -1916,11 +2048,13 @@ static int fbcon_resize(struct vc_data *vc, unsigned int width,
 static int fbcon_switch(struct vc_data *vc)
 {
        struct fb_info *info, *old_info = NULL;
+       struct fbcon_ops *ops;
        struct display *p = &fb_display[vc->vc_num];
        struct fb_var_screeninfo var;
        int i, prev_console;
 
        info = registered_fb[con2fb_map[vc->vc_num]];
+       ops = info->fbcon_par;
 
        if (softback_top) {
                if (softback_lines)
@@ -1939,7 +2073,7 @@ static int fbcon_switch(struct vc_data *vc)
                logo_shown = FBCON_LOGO_CANSHOW;
        }
 
-       prev_console = ((struct fbcon_ops *)info->fbcon_par)->currcon;
+       prev_console = ops->currcon;
        if (prev_console != -1)
                old_info = registered_fb[con2fb_map[prev_console]];
        /*
@@ -1952,9 +2086,9 @@ static int fbcon_switch(struct vc_data *vc)
         */
        for (i = 0; i < FB_MAX; i++) {
                if (registered_fb[i] != NULL && registered_fb[i]->fbcon_par) {
-                       struct fbcon_ops *ops = registered_fb[i]->fbcon_par;
+                       struct fbcon_ops *o = registered_fb[i]->fbcon_par;
 
-                       ops->currcon = vc->vc_num;
+                       o->currcon = vc->vc_num;
                }
        }
        memset(&var, 0, sizeof(struct fb_var_screeninfo));
@@ -1966,8 +2100,11 @@ static int fbcon_switch(struct vc_data *vc)
         * in fb_set_var()
         */
        info->var.activate = var.activate;
-       info->var.yoffset = info->var.xoffset = p->yscroll = 0;
+       var.yoffset = info->var.yoffset;
+       var.xoffset = info->var.xoffset;
+       var.vmode = info->var.vmode;
        fb_set_var(info, &var);
+       ops->var = info->var;
 
        if (old_info != NULL && old_info != info) {
                if (info->fbops->fb_set_par)
@@ -1977,7 +2114,12 @@ static int fbcon_switch(struct vc_data *vc)
        }
 
        set_blitting_type(vc, info, p);
-       ((struct fbcon_ops *)info->fbcon_par)->cursor_reset = 1;
+       ops->cursor_reset = 1;
+
+       if (ops->rotate_font && ops->rotate_font(info, vc, p)) {
+               ops->rotate = FB_ROTATE_UR;
+               set_blitting_type(vc, info, p);
+       }
 
        vc->vc_can_do_color = (fb_get_color_depth(&info->var, &info->fix)!=1);
        vc->vc_complement_mask = vc->vc_can_do_color ? 0x7700 : 0x0800;
@@ -1997,10 +2139,11 @@ static int fbcon_switch(struct vc_data *vc)
                scrollback_phys_max = 0;
                break;
        }
+
        scrollback_max = 0;
        scrollback_current = 0;
-
-       update_var(vc->vc_num, info);
+       ops->var.xoffset = ops->var.yoffset = p->yscroll = 0;
+       ops->update_start(info);
        fbcon_set_palette(vc, color_table);     
        fbcon_clear_margins(vc, 0);
 
@@ -2008,7 +2151,7 @@ static int fbcon_switch(struct vc_data *vc)
 
                logo_shown = fg_console;
                /* This is protected above by initmem_freed */
-               fb_show_logo(info);
+               fb_show_logo(info, ops->rotate);
                update_region(vc,
                              vc->vc_origin + vc->vc_size_row * vc->vc_top,
                              vc->vc_size_row * (vc->vc_bottom -
@@ -2047,6 +2190,7 @@ static int fbcon_blank(struct vc_data *vc, int blank, int mode_switch)
                        var.activate = FB_ACTIVATE_NOW | FB_ACTIVATE_FORCE;
                        fb_set_var(info, &var);
                        ops->graphics = 0;
+                       ops->var = info->var;
                }
        }
 
@@ -2135,6 +2279,7 @@ static int fbcon_do_set_font(struct vc_data *vc, int w, int h,
                             const u8 * data, int userfont)
 {
        struct fb_info *info = registered_fb[con2fb_map[vc->vc_num]];
+       struct fbcon_ops *ops = info->fbcon_par;
        struct display *p = &fb_display[vc->vc_num];
        int resize;
        int cnt;
@@ -2214,9 +2359,13 @@ static int fbcon_do_set_font(struct vc_data *vc, int w, int h,
        }
 
        if (resize) {
-               /* reset wrap/pan */
-               info->var.xoffset = info->var.yoffset = p->yscroll = 0;
-               vc_resize(vc, info->var.xres / w, info->var.yres / h);
+               int cols, rows;
+
+               cols = FBCON_SWAP(ops->rotate, info->var.xres, info->var.yres);
+               rows = FBCON_SWAP(ops->rotate, info->var.yres, info->var.xres);
+               cols /= w;
+               rows /= h;
+               vc_resize(vc, cols, rows);
                if (CON_IS_VISIBLE(vc) && softback_buf)
                        fbcon_update_softback(vc);
        } else if (CON_IS_VISIBLE(vc)
@@ -2444,6 +2593,7 @@ static void fbcon_invert_region(struct vc_data *vc, u16 * p, int cnt)
 static int fbcon_scrolldelta(struct vc_data *vc, int lines)
 {
        struct fb_info *info = registered_fb[con2fb_map[fg_console]];
+       struct fbcon_ops *ops = info->fbcon_par;
        struct display *p = &fb_display[fg_console];
        int offset, limit, scrollback_old;
 
@@ -2520,9 +2670,11 @@ static int fbcon_scrolldelta(struct vc_data *vc, int lines)
                offset += limit;
        else if (offset >= limit)
                offset -= limit;
-       info->var.xoffset = 0;
-       info->var.yoffset = offset * vc->vc_font.height;
-       update_var(vc->vc_num, info);
+
+       ops->var.xoffset = 0;
+       ops->var.yoffset = offset * vc->vc_font.height;
+       ops->update_start(info);
+
        if (!scrollback_current)
                fbcon_cursor(vc, CM_DRAW);
        return 0;
@@ -2570,22 +2722,25 @@ static void fbcon_modechanged(struct fb_info *info)
        if (!ops || ops->currcon < 0)
                return;
        vc = vc_cons[ops->currcon].d;
-       if (vc->vc_mode != KD_TEXT || registered_fb[con2fb_map[ops->currcon]] != info)
+       if (vc->vc_mode != KD_TEXT ||
+           registered_fb[con2fb_map[ops->currcon]] != info)
                return;
 
        p = &fb_display[vc->vc_num];
-
-       info->var.xoffset = info->var.yoffset = p->yscroll = 0;
+       set_blitting_type(vc, info, p);
 
        if (CON_IS_VISIBLE(vc)) {
                var_to_display(p, &info->var, info);
-               cols = info->var.xres / vc->vc_font.width;
-               rows = info->var.yres / vc->vc_font.height;
+               cols = FBCON_SWAP(ops->rotate, info->var.xres, info->var.yres);
+               rows = FBCON_SWAP(ops->rotate, info->var.yres, info->var.xres);
+               cols /= vc->vc_font.width;
+               rows /= vc->vc_font.height;
                vc_resize(vc, cols, rows);
                updatescrollmode(p, info, vc);
                scrollback_max = 0;
                scrollback_current = 0;
-               update_var(vc->vc_num, info);
+               ops->var.xoffset = ops->var.yoffset = p->yscroll = 0;
+               ops->update_start(info);
                fbcon_set_palette(vc, color_table);
                update_screen(vc);
                if (softback_buf)
@@ -2610,18 +2765,20 @@ static void fbcon_set_all_vcs(struct fb_info *info)
                        continue;
 
                p = &fb_display[vc->vc_num];
-
-               info->var.xoffset = info->var.yoffset = p->yscroll = 0;
+               set_blitting_type(vc, info, p);
                var_to_display(p, &info->var, info);
-               cols = info->var.xres / vc->vc_font.width;
-               rows = info->var.yres / vc->vc_font.height;
+               cols = FBCON_SWAP(ops->rotate, info->var.xres, info->var.yres);
+               rows = FBCON_SWAP(ops->rotate, info->var.yres, info->var.xres);
+               cols /= vc->vc_font.width;
+               rows /= vc->vc_font.height;
                vc_resize(vc, cols, rows);
 
                if (CON_IS_VISIBLE(vc)) {
                        updatescrollmode(p, info, vc);
                        scrollback_max = 0;
                        scrollback_current = 0;
-                       update_var(vc->vc_num, info);
+                       ops->var.xoffset = ops->var.yoffset = p->yscroll = 0;
+                       ops->update_start(info);
                        fbcon_set_palette(vc, color_table);
                        update_screen(vc);
                        if (softback_buf)
@@ -2771,6 +2928,14 @@ static int fbcon_event_notify(struct notifier_block *self,
        case FB_EVENT_NEW_MODELIST:
                fbcon_new_modelist(info);
                break;
+       case FB_EVENT_SET_CON_ROTATE:
+               fbcon_rotate(info, *(int *)event->data);
+               break;
+       case FB_EVENT_GET_CON_ROTATE:
+               ret = fbcon_get_rotate(info);
+               break;
+       case FB_EVENT_SET_CON_ROTATE_ALL:
+               fbcon_rotate_all(info, *(int *)event->data);
        }
 
        return ret;
index b68e0e2c2d1657c1c4c5e1aabd2b26591404bc02..accfd7bd8e9317927000ee4a791eaf1100da1d3a 100644 (file)
     */
 
 struct display {
-    /* Filled in by the frame buffer device */
-    u_short inverse;                /* != 0 text black on white as default */
     /* Filled in by the low-level console driver */
     const u_char *fontdata;
     int userfont;                   /* != 0 if fontdata kmalloc()ed */
     u_short scrollmode;             /* Scroll Method */
+    u_short inverse;                /* != 0 text black on white as default */
     short yscroll;                  /* Hardware scrolling */
     int vrows;                      /* number of virtual rows */
     int cursor_shape;
+    int con_rotate;
     u32 xres_virtual;
     u32 yres_virtual;
     u32 height;
@@ -52,6 +52,8 @@ struct display {
     struct fb_videomode *mode;
 };
 
+extern struct display fb_display[];
+
 struct fbcon_ops {
        void (*bmove)(struct vc_data *vc, struct fb_info *info, int sy,
                      int sx, int dy, int dx, int height, int width);
@@ -63,8 +65,12 @@ struct fbcon_ops {
        void (*clear_margins)(struct vc_data *vc, struct fb_info *info,
                              int bottom_only);
        void (*cursor)(struct vc_data *vc, struct fb_info *info,
-                      struct display *p, int mode, int softback_lines, int fg, int bg);
-
+                      struct display *p, int mode, int softback_lines,
+                      int fg, int bg);
+       int  (*update_start)(struct fb_info *info);
+       int  (*rotate_font)(struct fb_info *info, struct vc_data *vc,
+                           struct display *p);
+       struct fb_var_screeninfo var;  /* copy of the current fb_var_screeninfo */
        struct timer_list cursor_timer; /* Cursor timer */
        struct fb_cursor cursor_state;
         int    currcon;                        /* Current VC. */
@@ -73,7 +79,12 @@ struct fbcon_ops {
        int    blank_state;
        int    graphics;
        int    flags;
+       int    rotate;
+       int    cur_rotate;
        char  *cursor_data;
+       u8    *fontbuffer;
+       u8    *fontdata;
+       u32    fd_size;
 };
     /*
      *  Attribute Decoding
@@ -168,4 +179,47 @@ extern void fbcon_set_tileops(struct vc_data *vc, struct fb_info *info,
 #endif
 extern void fbcon_set_bitops(struct fbcon_ops *ops);
 extern int  soft_cursor(struct fb_info *info, struct fb_cursor *cursor);
+
+#define FBCON_ATTRIBUTE_UNDERLINE 1
+#define FBCON_ATTRIBUTE_REVERSE   2
+#define FBCON_ATTRIBUTE_BOLD      4
+
+static inline int real_y(struct display *p, int ypos)
+{
+       int rows = p->vrows;
+
+       ypos += p->yscroll;
+       return ypos < rows ? ypos : ypos - rows;
+}
+
+
+static inline int get_attribute(struct fb_info *info, u16 c)
+{
+       int attribute = 0;
+
+       if (fb_get_color_depth(&info->var, &info->fix) == 1) {
+               if (attr_underline(c))
+                       attribute |= FBCON_ATTRIBUTE_UNDERLINE;
+               if (attr_reverse(c))
+                       attribute |= FBCON_ATTRIBUTE_REVERSE;
+               if (attr_bold(c))
+                       attribute |= FBCON_ATTRIBUTE_BOLD;
+       }
+
+       return attribute;
+}
+
+#define FBCON_SWAP(i,r,v) ({ \
+        typeof(r) _r = (r);  \
+        typeof(v) _v = (v);  \
+        (void) (&_r == &_v); \
+        (i == FB_ROTATE_UR || i == FB_ROTATE_UD) ? _r : _v; })
+
+#ifdef CONFIG_FRAMEBUFFER_CONSOLE_ROTATION
+extern void fbcon_set_rotate(struct fbcon_ops *ops);
+#else
+#define fbcon_set_rotate(x) do {} while(0)
+#endif /* CONFIG_FRAMEBUFFER_CONSOLE_ROTATION */
+
 #endif /* _VIDEO_FBCON_H */
+
diff --git a/drivers/video/console/fbcon_ccw.c b/drivers/video/console/fbcon_ccw.c
new file mode 100644 (file)
index 0000000..680aaba
--- /dev/null
@@ -0,0 +1,428 @@
+/*
+ *  linux/drivers/video/console/fbcon_ccw.c -- Software Rotation - 270 degrees
+ *
+ *      Copyright (C) 2005 Antonino Daplas <adaplas @pol.net>
+ *
+ *  This file is subject to the terms and conditions of the GNU General Public
+ *  License.  See the file COPYING in the main directory of this archive for
+ *  more details.
+ */
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/string.h>
+#include <linux/fb.h>
+#include <linux/vt_kern.h>
+#include <linux/console.h>
+#include <asm/types.h>
+#include "fbcon.h"
+#include "fbcon_rotate.h"
+
+/*
+ * Rotation 270 degrees
+ */
+
+static inline void ccw_update_attr(u8 *dst, u8 *src, int attribute,
+                                 struct vc_data *vc)
+{
+       int i, j, offset = (vc->vc_font.height < 10) ? 1 : 2;
+       int width = (vc->vc_font.height + 7) >> 3;
+       int mod = vc->vc_font.height % 8;
+       u8 c, msk = ~(0xff << offset), msk1 = 0;
+
+       if (mod)
+               msk <<= (8 - mod);
+
+       if (offset > mod)
+               set_bit(FBCON_BIT(7), (void *)&msk1);
+
+       for (i = 0; i < vc->vc_font.width; i++) {
+               for (j = 0; j < width; j++) {
+                       c = *src;
+
+                       if (attribute & FBCON_ATTRIBUTE_UNDERLINE) {
+                               if (j == width - 1)
+                                       c |= msk;
+
+                               if (msk1 && j == width - 2)
+                                       c |= msk1;
+                       }
+
+                       if (attribute & FBCON_ATTRIBUTE_BOLD && i)
+                               *(dst - width) |= c;
+
+                       if (attribute & FBCON_ATTRIBUTE_REVERSE)
+                               c = ~c;
+                       src++;
+                       *dst++ = c;
+               }
+       }
+}
+
+
+static void ccw_bmove(struct vc_data *vc, struct fb_info *info, int sy,
+                    int sx, int dy, int dx, int height, int width)
+{
+       struct display *p = &fb_display[vc->vc_num];
+       struct fb_copyarea area;
+       u32 vyres = GETVYRES(p->scrollmode, info);
+
+       area.sx = sy * vc->vc_font.height;
+       area.sy = vyres - ((sx + width) * vc->vc_font.width);
+       area.dx = dy * vc->vc_font.height;
+       area.dy = vyres - ((dx + width) * vc->vc_font.width);
+       area.width = height * vc->vc_font.height;
+       area.height  = width * vc->vc_font.width;
+
+       info->fbops->fb_copyarea(info, &area);
+}
+
+static void ccw_clear(struct vc_data *vc, struct fb_info *info, int sy,
+                    int sx, int height, int width)
+{
+       struct display *p = &fb_display[vc->vc_num];
+       struct fb_fillrect region;
+       int bgshift = (vc->vc_hi_font_mask) ? 13 : 12;
+       u32 vyres = GETVYRES(p->scrollmode, info);
+
+       region.color = attr_bgcol_ec(bgshift,vc);
+       region.dx = sy * vc->vc_font.height;
+       region.dy = vyres - ((sx + width) * vc->vc_font.width);
+       region.height = width * vc->vc_font.width;
+       region.width = height * vc->vc_font.height;
+       region.rop = ROP_COPY;
+
+       info->fbops->fb_fillrect(info, &region);
+}
+
+static inline void ccw_putcs_aligned(struct vc_data *vc, struct fb_info *info,
+                                   const u16 *s, u32 attr, u32 cnt,
+                                   u32 d_pitch, u32 s_pitch, u32 cellsize,
+                                   struct fb_image *image, u8 *buf, u8 *dst)
+{
+       struct fbcon_ops *ops = info->fbcon_par;
+       u16 charmask = vc->vc_hi_font_mask ? 0x1ff : 0xff;
+       u32 idx = (vc->vc_font.height + 7) >> 3;
+       u8 *src;
+
+       while (cnt--) {
+               src = ops->fontbuffer + (scr_readw(s--) & charmask)*cellsize;
+
+               if (attr) {
+                       ccw_update_attr(buf, src, attr, vc);
+                       src = buf;
+               }
+
+               if (likely(idx == 1))
+                       __fb_pad_aligned_buffer(dst, d_pitch, src, idx,
+                                               vc->vc_font.width);
+               else
+                       fb_pad_aligned_buffer(dst, d_pitch, src, idx,
+                                             vc->vc_font.width);
+
+               dst += d_pitch * vc->vc_font.width;
+       }
+
+       info->fbops->fb_imageblit(info, image);
+}
+
+static void ccw_putcs(struct vc_data *vc, struct fb_info *info,
+                     const unsigned short *s, int count, int yy, int xx,
+                     int fg, int bg)
+{
+       struct fb_image image;
+       struct display *p = &fb_display[vc->vc_num];
+       struct fbcon_ops *ops = info->fbcon_par;
+       u32 width = (vc->vc_font.height + 7)/8;
+       u32 cellsize = width * vc->vc_font.width;
+       u32 maxcnt = info->pixmap.size/cellsize;
+       u32 scan_align = info->pixmap.scan_align - 1;
+       u32 buf_align = info->pixmap.buf_align - 1;
+       u32 cnt, pitch, size;
+       u32 attribute = get_attribute(info, scr_readw(s));
+       u8 *dst, *buf = NULL;
+       u32 vyres = GETVYRES(p->scrollmode, info);
+
+       if (!ops->fontbuffer)
+               return;
+
+       image.fg_color = fg;
+       image.bg_color = bg;
+       image.dx = yy * vc->vc_font.height;
+       image.dy = vyres - ((xx + count) * vc->vc_font.width);
+       image.width = vc->vc_font.height;
+       image.depth = 1;
+
+       if (attribute) {
+               buf = kmalloc(cellsize, GFP_KERNEL);
+               if (!buf)
+                       return;
+       }
+
+       s += count - 1;
+
+       while (count) {
+               if (count > maxcnt)
+                       cnt = maxcnt;
+               else
+                       cnt = count;
+
+               image.height = vc->vc_font.width * cnt;
+               pitch = ((image.width + 7) >> 3) + scan_align;
+               pitch &= ~scan_align;
+               size = pitch * image.height + buf_align;
+               size &= ~buf_align;
+               dst = fb_get_buffer_offset(info, &info->pixmap, size);
+               image.data = dst;
+               ccw_putcs_aligned(vc, info, s, attribute, cnt, pitch,
+                                width, cellsize, &image, buf, dst);
+               image.dy += image.height;
+               count -= cnt;
+               s -= cnt;
+       }
+
+       /* buf is always NULL except when in monochrome mode, so in this case
+          it's a gain to check buf against NULL even though kfree() handles
+          NULL pointers just fine */
+       if (unlikely(buf))
+               kfree(buf);
+
+}
+
+static void ccw_clear_margins(struct vc_data *vc, struct fb_info *info,
+                            int bottom_only)
+{
+       unsigned int cw = vc->vc_font.width;
+       unsigned int ch = vc->vc_font.height;
+       unsigned int rw = info->var.yres - (vc->vc_cols*cw);
+       unsigned int bh = info->var.xres - (vc->vc_rows*ch);
+       unsigned int bs = vc->vc_rows*ch;
+       struct fb_fillrect region;
+       int bgshift = (vc->vc_hi_font_mask) ? 13 : 12;
+
+       region.color = attr_bgcol_ec(bgshift,vc);
+       region.rop = ROP_COPY;
+
+       if (rw && !bottom_only) {
+               region.dx = 0;
+               region.dy = info->var.yoffset;
+               region.height = rw;
+               region.width = info->var.xres_virtual;
+               info->fbops->fb_fillrect(info, &region);
+       }
+
+       if (bh) {
+               region.dx = info->var.xoffset + bs;
+               region.dy = 0;
+                region.height = info->var.yres_virtual;
+                region.width = bh;
+               info->fbops->fb_fillrect(info, &region);
+       }
+}
+
+static void ccw_cursor(struct vc_data *vc, struct fb_info *info,
+                     struct display *p, int mode, int softback_lines,
+                     int fg, int bg)
+{
+       struct fb_cursor cursor;
+       struct fbcon_ops *ops = (struct fbcon_ops *) info->fbcon_par;
+       unsigned short charmask = vc->vc_hi_font_mask ? 0x1ff : 0xff;
+       int w = (vc->vc_font.height + 7) >> 3, c;
+       int y = real_y(p, vc->vc_y);
+       int attribute, use_sw = (vc->vc_cursor_type & 0x10);
+       int err = 1, dx, dy;
+       char *src;
+       u32 vyres = GETVYRES(p->scrollmode, info);
+
+       if (!ops->fontbuffer)
+               return;
+
+       cursor.set = 0;
+
+       if (softback_lines) {
+               if (y + softback_lines >= vc->vc_rows) {
+                       mode = CM_ERASE;
+                       ops->cursor_flash = 0;
+                       return;
+               } else
+                       y += softback_lines;
+       }
+
+       c = scr_readw((u16 *) vc->vc_pos);
+       attribute = get_attribute(info, c);
+       src = ops->fontbuffer + ((c & charmask) * (w * vc->vc_font.width));
+
+       if (ops->cursor_state.image.data != src ||
+           ops->cursor_reset) {
+           ops->cursor_state.image.data = src;
+           cursor.set |= FB_CUR_SETIMAGE;
+       }
+
+       if (attribute) {
+               u8 *dst;
+
+               dst = kmalloc(w * vc->vc_font.width, GFP_ATOMIC);
+               if (!dst)
+                       return;
+               kfree(ops->cursor_data);
+               ops->cursor_data = dst;
+               ccw_update_attr(dst, src, attribute, vc);
+               src = dst;
+       }
+
+       if (ops->cursor_state.image.fg_color != fg ||
+           ops->cursor_state.image.bg_color != bg ||
+           ops->cursor_reset) {
+               ops->cursor_state.image.fg_color = fg;
+               ops->cursor_state.image.bg_color = bg;
+               cursor.set |= FB_CUR_SETCMAP;
+       }
+
+       if (ops->cursor_state.image.height != vc->vc_font.width ||
+           ops->cursor_state.image.width != vc->vc_font.height ||
+           ops->cursor_reset) {
+               ops->cursor_state.image.height = vc->vc_font.width;
+               ops->cursor_state.image.width = vc->vc_font.height;
+               cursor.set |= FB_CUR_SETSIZE;
+       }
+
+       dx = y * vc->vc_font.height;
+       dy = vyres - ((vc->vc_x + 1) * vc->vc_font.width);
+
+       if (ops->cursor_state.image.dx != dx ||
+           ops->cursor_state.image.dy != dy ||
+           ops->cursor_reset) {
+               ops->cursor_state.image.dx = dx;
+               ops->cursor_state.image.dy = dy;
+               cursor.set |= FB_CUR_SETPOS;
+       }
+
+       if (ops->cursor_state.hot.x || ops->cursor_state.hot.y ||
+           ops->cursor_reset) {
+               ops->cursor_state.hot.x = cursor.hot.y = 0;
+               cursor.set |= FB_CUR_SETHOT;
+       }
+
+       if (cursor.set & FB_CUR_SETSIZE ||
+           vc->vc_cursor_type != p->cursor_shape ||
+           ops->cursor_state.mask == NULL ||
+           ops->cursor_reset) {
+               char *tmp, *mask = kmalloc(w*vc->vc_font.width, GFP_ATOMIC);
+               int cur_height, size, i = 0;
+               int width = (vc->vc_font.width + 7)/8;
+
+               if (!mask)
+                       return;
+
+               tmp = kmalloc(width * vc->vc_font.height, GFP_ATOMIC);
+
+               if (!tmp) {
+                       kfree(mask);
+                       return;
+               }
+
+               kfree(ops->cursor_state.mask);
+               ops->cursor_state.mask = mask;
+
+               p->cursor_shape = vc->vc_cursor_type;
+               cursor.set |= FB_CUR_SETSHAPE;
+
+               switch (p->cursor_shape & CUR_HWMASK) {
+               case CUR_NONE:
+                       cur_height = 0;
+                       break;
+               case CUR_UNDERLINE:
+                       cur_height = (vc->vc_font.height < 10) ? 1 : 2;
+                       break;
+               case CUR_LOWER_THIRD:
+                       cur_height = vc->vc_font.height/3;
+                       break;
+               case CUR_LOWER_HALF:
+                       cur_height = vc->vc_font.height >> 1;
+                       break;
+               case CUR_TWO_THIRDS:
+                       cur_height = (vc->vc_font.height << 1)/3;
+                       break;
+               case CUR_BLOCK:
+               default:
+                       cur_height = vc->vc_font.height;
+                       break;
+               }
+
+               size = (vc->vc_font.height - cur_height) * width;
+               while (size--)
+                       tmp[i++] = 0;
+               size = cur_height * width;
+               while (size--)
+                       tmp[i++] = 0xff;
+               memset(mask, 0, w * vc->vc_font.width);
+               rotate_ccw(tmp, mask, vc->vc_font.width, vc->vc_font.height);
+               kfree(tmp);
+       }
+
+       switch (mode) {
+       case CM_ERASE:
+               ops->cursor_state.enable = 0;
+               break;
+       case CM_DRAW:
+       case CM_MOVE:
+       default:
+               ops->cursor_state.enable = (use_sw) ? 0 : 1;
+               break;
+       }
+
+       cursor.image.data = src;
+       cursor.image.fg_color = ops->cursor_state.image.fg_color;
+       cursor.image.bg_color = ops->cursor_state.image.bg_color;
+       cursor.image.dx = ops->cursor_state.image.dx;
+       cursor.image.dy = ops->cursor_state.image.dy;
+       cursor.image.height = ops->cursor_state.image.height;
+       cursor.image.width = ops->cursor_state.image.width;
+       cursor.hot.x = ops->cursor_state.hot.x;
+       cursor.hot.y = ops->cursor_state.hot.y;
+       cursor.mask = ops->cursor_state.mask;
+       cursor.enable = ops->cursor_state.enable;
+       cursor.image.depth = 1;
+       cursor.rop = ROP_XOR;
+
+       if (info->fbops->fb_cursor)
+               err = info->fbops->fb_cursor(info, &cursor);
+
+       if (err)
+               soft_cursor(info, &cursor);
+
+       ops->cursor_reset = 0;
+}
+
+int ccw_update_start(struct fb_info *info)
+{
+       struct fbcon_ops *ops = info->fbcon_par;
+       struct display *p = &fb_display[ops->currcon];
+       u32 yoffset;
+       u32 vyres = GETVYRES(p->scrollmode, info);
+       int err;
+
+       yoffset = (vyres - info->var.yres) - ops->var.xoffset;
+       ops->var.xoffset = ops->var.yoffset;
+       ops->var.yoffset = yoffset;
+       err = fb_pan_display(info, &ops->var);
+       ops->var.xoffset = info->var.xoffset;
+       ops->var.yoffset = info->var.yoffset;
+       ops->var.vmode = info->var.vmode;
+       return err;
+}
+
+void fbcon_rotate_ccw(struct fbcon_ops *ops)
+{
+       ops->bmove = ccw_bmove;
+       ops->clear = ccw_clear;
+       ops->putcs = ccw_putcs;
+       ops->clear_margins = ccw_clear_margins;
+       ops->cursor = ccw_cursor;
+       ops->update_start = ccw_update_start;
+}
+EXPORT_SYMBOL(fbcon_rotate_ccw);
+
+MODULE_AUTHOR("Antonino Daplas <adaplas@pol.net>");
+MODULE_DESCRIPTION("Console Rotation (270 degrees) Support");
+MODULE_LICENSE("GPL");
diff --git a/drivers/video/console/fbcon_cw.c b/drivers/video/console/fbcon_cw.c
new file mode 100644 (file)
index 0000000..6c6f3b6
--- /dev/null
@@ -0,0 +1,412 @@
+/*
+ *  linux/drivers/video/console/fbcon_ud.c -- Software Rotation - 90 degrees
+ *
+ *      Copyright (C) 2005 Antonino Daplas <adaplas @pol.net>
+ *
+ *  This file is subject to the terms and conditions of the GNU General Public
+ *  License.  See the file COPYING in the main directory of this archive for
+ *  more details.
+ */
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/string.h>
+#include <linux/fb.h>
+#include <linux/vt_kern.h>
+#include <linux/console.h>
+#include <asm/types.h>
+#include "fbcon.h"
+#include "fbcon_rotate.h"
+
+/*
+ * Rotation 90 degrees
+ */
+
+static inline void cw_update_attr(u8 *dst, u8 *src, int attribute,
+                                 struct vc_data *vc)
+{
+       int i, j, offset = (vc->vc_font.height < 10) ? 1 : 2;
+       int width = (vc->vc_font.height + 7) >> 3;
+       u8 c, t = 0, msk = ~(0xff >> offset);
+
+       for (i = 0; i < vc->vc_font.width; i++) {
+               for (j = 0; j < width; j++) {
+                       c = *src;
+                       if (attribute & FBCON_ATTRIBUTE_UNDERLINE && !j)
+                               c |= msk;
+                       if (attribute & FBCON_ATTRIBUTE_BOLD && i)
+                               c |= *(src-width);
+                       if (attribute & FBCON_ATTRIBUTE_REVERSE)
+                               c = ~c;
+                       src++;
+                       *dst++ = c;
+                       t = c;
+               }
+       }
+}
+
+
+static void cw_bmove(struct vc_data *vc, struct fb_info *info, int sy,
+                    int sx, int dy, int dx, int height, int width)
+{
+       struct display *p = &fb_display[vc->vc_num];
+       struct fb_copyarea area;
+       u32 vxres = GETVXRES(p->scrollmode, info);
+
+       area.sx = vxres - ((sy + height) * vc->vc_font.height);
+       area.sy = sx * vc->vc_font.width;
+       area.dx = vxres - ((dy + height) * vc->vc_font.height);
+       area.dy = dx * vc->vc_font.width;
+       area.width = height * vc->vc_font.height;
+       area.height  = width * vc->vc_font.width;
+
+       info->fbops->fb_copyarea(info, &area);
+}
+
+static void cw_clear(struct vc_data *vc, struct fb_info *info, int sy,
+                    int sx, int height, int width)
+{
+       struct display *p = &fb_display[vc->vc_num];
+       struct fb_fillrect region;
+       int bgshift = (vc->vc_hi_font_mask) ? 13 : 12;
+       u32 vxres = GETVXRES(p->scrollmode, info);
+
+       region.color = attr_bgcol_ec(bgshift,vc);
+       region.dx = vxres - ((sy + height) * vc->vc_font.height);
+       region.dy = sx *  vc->vc_font.width;
+       region.height = width * vc->vc_font.width;
+       region.width = height * vc->vc_font.height;
+       region.rop = ROP_COPY;
+
+       info->fbops->fb_fillrect(info, &region);
+}
+
+static inline void cw_putcs_aligned(struct vc_data *vc, struct fb_info *info,
+                                   const u16 *s, u32 attr, u32 cnt,
+                                   u32 d_pitch, u32 s_pitch, u32 cellsize,
+                                   struct fb_image *image, u8 *buf, u8 *dst)
+{
+       struct fbcon_ops *ops = info->fbcon_par;
+       u16 charmask = vc->vc_hi_font_mask ? 0x1ff : 0xff;
+       u32 idx = (vc->vc_font.height + 7) >> 3;
+       u8 *src;
+
+       while (cnt--) {
+               src = ops->fontbuffer + (scr_readw(s++) & charmask)*cellsize;
+
+               if (attr) {
+                       cw_update_attr(buf, src, attr, vc);
+                       src = buf;
+               }
+
+               if (likely(idx == 1))
+                       __fb_pad_aligned_buffer(dst, d_pitch, src, idx,
+                                               vc->vc_font.width);
+               else
+                       fb_pad_aligned_buffer(dst, d_pitch, src, idx,
+                                             vc->vc_font.width);
+
+               dst += d_pitch * vc->vc_font.width;
+       }
+
+       info->fbops->fb_imageblit(info, image);
+}
+
+static void cw_putcs(struct vc_data *vc, struct fb_info *info,
+                     const unsigned short *s, int count, int yy, int xx,
+                     int fg, int bg)
+{
+       struct fb_image image;
+       struct display *p = &fb_display[vc->vc_num];
+       struct fbcon_ops *ops = info->fbcon_par;
+       u32 width = (vc->vc_font.height + 7)/8;
+       u32 cellsize = width * vc->vc_font.width;
+       u32 maxcnt = info->pixmap.size/cellsize;
+       u32 scan_align = info->pixmap.scan_align - 1;
+       u32 buf_align = info->pixmap.buf_align - 1;
+       u32 cnt, pitch, size;
+       u32 attribute = get_attribute(info, scr_readw(s));
+       u8 *dst, *buf = NULL;
+       u32 vxres = GETVXRES(p->scrollmode, info);
+
+       if (!ops->fontbuffer)
+               return;
+
+       image.fg_color = fg;
+       image.bg_color = bg;
+       image.dx = vxres - ((yy + 1) * vc->vc_font.height);
+       image.dy = xx * vc->vc_font.width;
+       image.width = vc->vc_font.height;
+       image.depth = 1;
+
+       if (attribute) {
+               buf = kmalloc(cellsize, GFP_KERNEL);
+               if (!buf)
+                       return;
+       }
+
+       while (count) {
+               if (count > maxcnt)
+                       cnt = maxcnt;
+               else
+                       cnt = count;
+
+               image.height = vc->vc_font.width * cnt;
+               pitch = ((image.width + 7) >> 3) + scan_align;
+               pitch &= ~scan_align;
+               size = pitch * image.height + buf_align;
+               size &= ~buf_align;
+               dst = fb_get_buffer_offset(info, &info->pixmap, size);
+               image.data = dst;
+               cw_putcs_aligned(vc, info, s, attribute, cnt, pitch,
+                                width, cellsize, &image, buf, dst);
+               image.dy += image.height;
+               count -= cnt;
+               s += cnt;
+       }
+
+       /* buf is always NULL except when in monochrome mode, so in this case
+          it's a gain to check buf against NULL even though kfree() handles
+          NULL pointers just fine */
+       if (unlikely(buf))
+               kfree(buf);
+
+}
+
+static void cw_clear_margins(struct vc_data *vc, struct fb_info *info,
+                            int bottom_only)
+{
+       unsigned int cw = vc->vc_font.width;
+       unsigned int ch = vc->vc_font.height;
+       unsigned int rw = info->var.yres - (vc->vc_cols*cw);
+       unsigned int bh = info->var.xres - (vc->vc_rows*ch);
+       unsigned int rs = info->var.yres - rw;
+       struct fb_fillrect region;
+       int bgshift = (vc->vc_hi_font_mask) ? 13 : 12;
+
+       region.color = attr_bgcol_ec(bgshift,vc);
+       region.rop = ROP_COPY;
+
+       if (rw && !bottom_only) {
+               region.dx = 0;
+               region.dy = info->var.yoffset + rs;
+               region.height = rw;
+               region.width = info->var.xres_virtual;
+               info->fbops->fb_fillrect(info, &region);
+       }
+
+       if (bh) {
+               region.dx = info->var.xoffset;
+               region.dy = info->var.yoffset;
+                region.height = info->var.yres;
+                region.width = bh;
+               info->fbops->fb_fillrect(info, &region);
+       }
+}
+
+static void cw_cursor(struct vc_data *vc, struct fb_info *info,
+                     struct display *p, int mode, int softback_lines,
+                     int fg, int bg)
+{
+       struct fb_cursor cursor;
+       struct fbcon_ops *ops = (struct fbcon_ops *) info->fbcon_par;
+       unsigned short charmask = vc->vc_hi_font_mask ? 0x1ff : 0xff;
+       int w = (vc->vc_font.height + 7) >> 3, c;
+       int y = real_y(p, vc->vc_y);
+       int attribute, use_sw = (vc->vc_cursor_type & 0x10);
+       int err = 1, dx, dy;
+       char *src;
+       u32 vxres = GETVXRES(p->scrollmode, info);
+
+       if (!ops->fontbuffer)
+               return;
+
+       cursor.set = 0;
+
+       if (softback_lines) {
+               if (y + softback_lines >= vc->vc_rows) {
+                       mode = CM_ERASE;
+                       ops->cursor_flash = 0;
+                       return;
+               } else
+                       y += softback_lines;
+       }
+
+       c = scr_readw((u16 *) vc->vc_pos);
+       attribute = get_attribute(info, c);
+       src = ops->fontbuffer + ((c & charmask) * (w * vc->vc_font.width));
+
+       if (ops->cursor_state.image.data != src ||
+           ops->cursor_reset) {
+           ops->cursor_state.image.data = src;
+           cursor.set |= FB_CUR_SETIMAGE;
+       }
+
+       if (attribute) {
+               u8 *dst;
+
+               dst = kmalloc(w * vc->vc_font.width, GFP_ATOMIC);
+               if (!dst)
+                       return;
+               kfree(ops->cursor_data);
+               ops->cursor_data = dst;
+               cw_update_attr(dst, src, attribute, vc);
+               src = dst;
+       }
+
+       if (ops->cursor_state.image.fg_color != fg ||
+           ops->cursor_state.image.bg_color != bg ||
+           ops->cursor_reset) {
+               ops->cursor_state.image.fg_color = fg;
+               ops->cursor_state.image.bg_color = bg;
+               cursor.set |= FB_CUR_SETCMAP;
+       }
+
+       if (ops->cursor_state.image.height != vc->vc_font.width ||
+           ops->cursor_state.image.width != vc->vc_font.height ||
+           ops->cursor_reset) {
+               ops->cursor_state.image.height = vc->vc_font.width;
+               ops->cursor_state.image.width = vc->vc_font.height;
+               cursor.set |= FB_CUR_SETSIZE;
+       }
+
+       dx = vxres - ((y * vc->vc_font.height) + vc->vc_font.height);
+       dy = vc->vc_x * vc->vc_font.width;
+
+       if (ops->cursor_state.image.dx != dx ||
+           ops->cursor_state.image.dy != dy ||
+           ops->cursor_reset) {
+               ops->cursor_state.image.dx = dx;
+               ops->cursor_state.image.dy = dy;
+               cursor.set |= FB_CUR_SETPOS;
+       }
+
+       if (ops->cursor_state.hot.x || ops->cursor_state.hot.y ||
+           ops->cursor_reset) {
+               ops->cursor_state.hot.x = cursor.hot.y = 0;
+               cursor.set |= FB_CUR_SETHOT;
+       }
+
+       if (cursor.set & FB_CUR_SETSIZE ||
+           vc->vc_cursor_type != p->cursor_shape ||
+           ops->cursor_state.mask == NULL ||
+           ops->cursor_reset) {
+               char *tmp, *mask = kmalloc(w*vc->vc_font.width, GFP_ATOMIC);
+               int cur_height, size, i = 0;
+               int width = (vc->vc_font.width + 7)/8;
+
+               if (!mask)
+                       return;
+
+               tmp = kmalloc(width * vc->vc_font.height, GFP_ATOMIC);
+
+               if (!tmp) {
+                       kfree(mask);
+                       return;
+               }
+
+               kfree(ops->cursor_state.mask);
+               ops->cursor_state.mask = mask;
+
+               p->cursor_shape = vc->vc_cursor_type;
+               cursor.set |= FB_CUR_SETSHAPE;
+
+               switch (p->cursor_shape & CUR_HWMASK) {
+               case CUR_NONE:
+                       cur_height = 0;
+                       break;
+               case CUR_UNDERLINE:
+                       cur_height = (vc->vc_font.height < 10) ? 1 : 2;
+                       break;
+               case CUR_LOWER_THIRD:
+                       cur_height = vc->vc_font.height/3;
+                       break;
+               case CUR_LOWER_HALF:
+                       cur_height = vc->vc_font.height >> 1;
+                       break;
+               case CUR_TWO_THIRDS:
+                       cur_height = (vc->vc_font.height << 1)/3;
+                       break;
+               case CUR_BLOCK:
+               default:
+                       cur_height = vc->vc_font.height;
+                       break;
+               }
+
+               size = (vc->vc_font.height - cur_height) * width;
+               while (size--)
+                       tmp[i++] = 0;
+               size = cur_height * width;
+               while (size--)
+                       tmp[i++] = 0xff;
+               memset(mask, 0, w * vc->vc_font.width);
+               rotate_cw(tmp, mask, vc->vc_font.width, vc->vc_font.height);
+               kfree(tmp);
+       }
+
+       switch (mode) {
+       case CM_ERASE:
+               ops->cursor_state.enable = 0;
+               break;
+       case CM_DRAW:
+       case CM_MOVE:
+       default:
+               ops->cursor_state.enable = (use_sw) ? 0 : 1;
+               break;
+       }
+
+       cursor.image.data = src;
+       cursor.image.fg_color = ops->cursor_state.image.fg_color;
+       cursor.image.bg_color = ops->cursor_state.image.bg_color;
+       cursor.image.dx = ops->cursor_state.image.dx;
+       cursor.image.dy = ops->cursor_state.image.dy;
+       cursor.image.height = ops->cursor_state.image.height;
+       cursor.image.width = ops->cursor_state.image.width;
+       cursor.hot.x = ops->cursor_state.hot.x;
+       cursor.hot.y = ops->cursor_state.hot.y;
+       cursor.mask = ops->cursor_state.mask;
+       cursor.enable = ops->cursor_state.enable;
+       cursor.image.depth = 1;
+       cursor.rop = ROP_XOR;
+
+       if (info->fbops->fb_cursor)
+               err = info->fbops->fb_cursor(info, &cursor);
+
+       if (err)
+               soft_cursor(info, &cursor);
+
+       ops->cursor_reset = 0;
+}
+
+int cw_update_start(struct fb_info *info)
+{
+       struct fbcon_ops *ops = info->fbcon_par;
+       struct display *p = &fb_display[ops->currcon];
+       u32 vxres = GETVXRES(p->scrollmode, info);
+       u32 xoffset;
+       int err;
+
+       xoffset = vxres - (info->var.xres + ops->var.yoffset);
+       ops->var.yoffset = ops->var.xoffset;
+       ops->var.xoffset = xoffset;
+       err = fb_pan_display(info, &ops->var);
+       ops->var.xoffset = info->var.xoffset;
+       ops->var.yoffset = info->var.yoffset;
+       ops->var.vmode = info->var.vmode;
+       return err;
+}
+
+void fbcon_rotate_cw(struct fbcon_ops *ops)
+{
+       ops->bmove = cw_bmove;
+       ops->clear = cw_clear;
+       ops->putcs = cw_putcs;
+       ops->clear_margins = cw_clear_margins;
+       ops->cursor = cw_cursor;
+       ops->update_start = cw_update_start;
+}
+EXPORT_SYMBOL(fbcon_rotate_cw);
+
+MODULE_AUTHOR("Antonino Daplas <adaplas@pol.net>");
+MODULE_DESCRIPTION("Console Rotation (90 degrees) Support");
+MODULE_LICENSE("GPL");
diff --git a/drivers/video/console/fbcon_rotate.c b/drivers/video/console/fbcon_rotate.c
new file mode 100644 (file)
index 0000000..ec0dd8f
--- /dev/null
@@ -0,0 +1,117 @@
+/*
+ *  linux/drivers/video/console/fbcon_rotate.c -- Software Rotation
+ *
+ *      Copyright (C) 2005 Antonino Daplas <adaplas @pol.net>
+ *
+ *  This file is subject to the terms and conditions of the GNU General Public
+ *  License.  See the file COPYING in the main directory of this archive for
+ *  more details.
+ */
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/string.h>
+#include <linux/fb.h>
+#include <linux/vt_kern.h>
+#include <linux/console.h>
+#include <asm/types.h>
+#include "fbcon.h"
+#include "fbcon_rotate.h"
+
+static int fbcon_rotate_font(struct fb_info *info, struct vc_data *vc,
+                            struct display *p)
+{
+       struct fbcon_ops *ops = info->fbcon_par;
+       int len, err = 0;
+       int s_cellsize, d_cellsize, i;
+       const u8 *src;
+       u8 *dst;
+
+       if (vc->vc_font.data == ops->fontdata &&
+           p->con_rotate == ops->cur_rotate)
+               goto finished;
+
+       src = ops->fontdata = vc->vc_font.data;
+       ops->cur_rotate = p->con_rotate;
+       len = (!p->userfont) ? 256 : FNTCHARCNT(src);
+       s_cellsize = ((vc->vc_font.width + 7)/8) *
+               vc->vc_font.height;
+       d_cellsize = s_cellsize;
+
+       if (ops->rotate == FB_ROTATE_CW ||
+           ops->rotate == FB_ROTATE_CCW)
+               d_cellsize = ((vc->vc_font.height + 7)/8) *
+                       vc->vc_font.width;
+
+       if (info->fbops->fb_sync)
+               info->fbops->fb_sync(info);
+
+       if (ops->fd_size < d_cellsize * len) {
+               dst = kmalloc(d_cellsize * len, GFP_KERNEL);
+
+               if (dst == NULL) {
+                       err = -ENOMEM;
+                       goto finished;
+               }
+
+               ops->fd_size = d_cellsize * len;
+               kfree(ops->fontbuffer);
+               ops->fontbuffer = dst;
+       }
+
+       dst = ops->fontbuffer;
+       memset(dst, 0, ops->fd_size);
+
+       switch (ops->rotate) {
+       case FB_ROTATE_UD:
+               for (i = len; i--; ) {
+                       rotate_ud(src, dst, vc->vc_font.width,
+                                 vc->vc_font.height);
+
+                       src += s_cellsize;
+                       dst += d_cellsize;
+               }
+               break;
+       case FB_ROTATE_CW:
+               for (i = len; i--; ) {
+                       rotate_cw(src, dst, vc->vc_font.width,
+                                 vc->vc_font.height);
+                       src += s_cellsize;
+                       dst += d_cellsize;
+               }
+               break;
+       case FB_ROTATE_CCW:
+               for (i = len; i--; ) {
+                       rotate_ccw(src, dst, vc->vc_font.width,
+                                  vc->vc_font.height);
+                       src += s_cellsize;
+                       dst += d_cellsize;
+               }
+               break;
+       }
+
+finished:
+       return err;
+}
+
+void fbcon_set_rotate(struct fbcon_ops *ops)
+{
+       ops->rotate_font = fbcon_rotate_font;
+
+       switch(ops->rotate) {
+       case FB_ROTATE_CW:
+               fbcon_rotate_cw(ops);
+               break;
+       case FB_ROTATE_UD:
+               fbcon_rotate_ud(ops);
+               break;
+       case FB_ROTATE_CCW:
+               fbcon_rotate_ccw(ops);
+               break;
+       }
+}
+EXPORT_SYMBOL(fbcon_set_rotate);
+
+MODULE_AUTHOR("Antonino Daplas <adaplas@pol.net>");
+MODULE_DESCRIPTION("Console Rotation Support");
+MODULE_LICENSE("GPL");
diff --git a/drivers/video/console/fbcon_rotate.h b/drivers/video/console/fbcon_rotate.h
new file mode 100644 (file)
index 0000000..90c6720
--- /dev/null
@@ -0,0 +1,105 @@
+/*
+ *  linux/drivers/video/console/fbcon_rotate.h -- Software Display Rotation
+ *
+ *     Copyright (C) 2005 Antonino Daplas <adaplas@pol.net>
+ *
+ *  This file is subject to the terms and conditions of the GNU General Public
+ *  License.  See the file COPYING in the main directory of this archive
+ *  for more details.
+ */
+
+#ifndef _FBCON_ROTATE_H
+#define _FBCON_ROTATE_H
+
+#define FNTCHARCNT(fd) (((int *)(fd))[-3])
+
+#define GETVYRES(s,i) ({                           \
+        (s == SCROLL_REDRAW || s == SCROLL_MOVE) ? \
+        (i)->var.yres : (i)->var.yres_virtual; })
+
+#define GETVXRES(s,i) ({                           \
+        (s == SCROLL_REDRAW || s == SCROLL_MOVE || !(i)->fix.xpanstep) ? \
+        (i)->var.xres : (i)->var.xres_virtual; })
+
+/*
+ * The bitmap is always big endian
+ */
+#if defined(__LITTLE_ENDIAN)
+#define FBCON_BIT(b) (7 - (b))
+#else
+#define FBCON_BIT(b) (b)
+#endif
+
+static inline int pattern_test_bit(u32 x, u32 y, u32 pitch, const char *pat)
+{
+       u32 tmp = (y * pitch) + x, index = tmp / 8,  bit = tmp % 8;
+
+       pat +=index;
+       return (test_bit(FBCON_BIT(bit), (void *)pat));
+}
+
+static inline void pattern_set_bit(u32 x, u32 y, u32 pitch, char *pat)
+{
+       u32 tmp = (y * pitch) + x, index = tmp / 8, bit = tmp % 8;
+
+       pat += index;
+       set_bit(FBCON_BIT(bit), (void *)pat);
+}
+
+static inline void rotate_ud(const char *in, char *out, u32 width, u32 height)
+{
+       int i, j;
+       int shift = width % 8;
+
+       width = (width + 7) & ~7;
+
+       for (i = 0; i < height; i++) {
+               for (j = 0; j < width; j++) {
+                       if (pattern_test_bit(j, i, width, in))
+                               pattern_set_bit(width - (1 + j + shift),
+                                               height - (1 + i),
+                                               width, out);
+               }
+
+       }
+}
+
+static inline void rotate_cw(const char *in, char *out, u32 width, u32 height)
+{
+       int i, j, h = height, w = width;
+       int shift = (8 - (height % 8)) & 7;
+
+       width = (width + 7) & ~7;
+       height = (height + 7) & ~7;
+
+       for (i = 0; i < h; i++) {
+               for (j = 0; j < w; j++) {
+                       if (pattern_test_bit(j, i, width, in))
+                               pattern_set_bit(height - 1 - i - shift, j,
+                                               height, out);
+
+               }
+       }
+}
+
+static inline void rotate_ccw(const char *in, char *out, u32 width, u32 height)
+{
+       int i, j, h = height, w = width;
+       int shift = width % 8;
+
+       width = (width + 7) & ~7;
+       height = (height + 7) & ~7;
+
+       for (i = 0; i < h; i++) {
+               for (j = 0; j < w; j++) {
+                       if (pattern_test_bit(j, i, width, in))
+                               pattern_set_bit(i, width - 1 - j - shift,
+                                               height, out);
+               }
+       }
+}
+
+extern void fbcon_rotate_cw(struct fbcon_ops *ops);
+extern void fbcon_rotate_ud(struct fbcon_ops *ops);
+extern void fbcon_rotate_ccw(struct fbcon_ops *ops);
+#endif
diff --git a/drivers/video/console/fbcon_ud.c b/drivers/video/console/fbcon_ud.c
new file mode 100644 (file)
index 0000000..2e1d9d4
--- /dev/null
@@ -0,0 +1,454 @@
+/*
+ *  linux/drivers/video/console/fbcon_ud.c -- Software Rotation - 180 degrees
+ *
+ *      Copyright (C) 2005 Antonino Daplas <adaplas @pol.net>
+ *
+ *  This file is subject to the terms and conditions of the GNU General Public
+ *  License.  See the file COPYING in the main directory of this archive for
+ *  more details.
+ */
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/string.h>
+#include <linux/fb.h>
+#include <linux/vt_kern.h>
+#include <linux/console.h>
+#include <asm/types.h>
+#include "fbcon.h"
+#include "fbcon_rotate.h"
+
+/*
+ * Rotation 180 degrees
+ */
+
+static inline void ud_update_attr(u8 *dst, u8 *src, int attribute,
+                                 struct vc_data *vc)
+{
+       int i, offset = (vc->vc_font.height < 10) ? 1 : 2;
+       int width = (vc->vc_font.width + 7) >> 3;
+       unsigned int cellsize = vc->vc_font.height * width;
+       u8 c;
+
+       offset = offset * width;
+
+       for (i = 0; i < cellsize; i++) {
+               c = src[i];
+               if (attribute & FBCON_ATTRIBUTE_UNDERLINE && i < offset)
+                       c = 0xff;
+               if (attribute & FBCON_ATTRIBUTE_BOLD)
+                       c |= c << 1;
+               if (attribute & FBCON_ATTRIBUTE_REVERSE)
+                       c = ~c;
+               dst[i] = c;
+       }
+}
+
+
+static void ud_bmove(struct vc_data *vc, struct fb_info *info, int sy,
+                    int sx, int dy, int dx, int height, int width)
+{
+       struct display *p = &fb_display[vc->vc_num];
+       struct fb_copyarea area;
+       u32 vyres = GETVYRES(p->scrollmode, info);
+       u32 vxres = GETVXRES(p->scrollmode, info);
+
+       area.sy = vyres - ((sy + height) * vc->vc_font.height);
+       area.sx = vxres - ((sx + width) * vc->vc_font.width);
+       area.dy = vyres - ((dy + height) * vc->vc_font.height);
+       area.dx = vxres - ((dx + width) * vc->vc_font.width);
+       area.height = height * vc->vc_font.height;
+       area.width  = width * vc->vc_font.width;
+
+       info->fbops->fb_copyarea(info, &area);
+}
+
+static void ud_clear(struct vc_data *vc, struct fb_info *info, int sy,
+                    int sx, int height, int width)
+{
+       struct display *p = &fb_display[vc->vc_num];
+       struct fb_fillrect region;
+       int bgshift = (vc->vc_hi_font_mask) ? 13 : 12;
+       u32 vyres = GETVYRES(p->scrollmode, info);
+       u32 vxres = GETVXRES(p->scrollmode, info);
+
+       region.color = attr_bgcol_ec(bgshift,vc);
+       region.dy = vyres - ((sy + height) * vc->vc_font.height);
+       region.dx = vxres - ((sx + width) *  vc->vc_font.width);
+       region.width = width * vc->vc_font.width;
+       region.height = height * vc->vc_font.height;
+       region.rop = ROP_COPY;
+
+       info->fbops->fb_fillrect(info, &region);
+}
+
+static inline void ud_putcs_aligned(struct vc_data *vc, struct fb_info *info,
+                                   const u16 *s, u32 attr, u32 cnt,
+                                   u32 d_pitch, u32 s_pitch, u32 cellsize,
+                                   struct fb_image *image, u8 *buf, u8 *dst)
+{
+       struct fbcon_ops *ops = info->fbcon_par;
+       u16 charmask = vc->vc_hi_font_mask ? 0x1ff : 0xff;
+       u32 idx = vc->vc_font.width >> 3;
+       u8 *src;
+
+       while (cnt--) {
+               src = ops->fontbuffer + (scr_readw(s--) & charmask)*cellsize;
+
+               if (attr) {
+                       ud_update_attr(buf, src, attr, vc);
+                       src = buf;
+               }
+
+               if (likely(idx == 1))
+                       __fb_pad_aligned_buffer(dst, d_pitch, src, idx,
+                                               image->height);
+               else
+                       fb_pad_aligned_buffer(dst, d_pitch, src, idx,
+                                             image->height);
+
+               dst += s_pitch;
+       }
+
+       info->fbops->fb_imageblit(info, image);
+}
+
+static inline void ud_putcs_unaligned(struct vc_data *vc,
+                                     struct fb_info *info, const u16 *s,
+                                     u32 attr, u32 cnt, u32 d_pitch,
+                                     u32 s_pitch, u32 cellsize,
+                                     struct fb_image *image, u8 *buf,
+                                     u8 *dst)
+{
+       struct fbcon_ops *ops = info->fbcon_par;
+       u16 charmask = vc->vc_hi_font_mask ? 0x1ff : 0xff;
+       u32 shift_low = 0, mod = vc->vc_font.width % 8;
+       u32 shift_high = 8;
+       u32 idx = vc->vc_font.width >> 3;
+       u8 *src;
+
+       while (cnt--) {
+               src = ops->fontbuffer + (scr_readw(s--) & charmask)*cellsize;
+
+               if (attr) {
+                       ud_update_attr(buf, src, attr, vc);
+                       src = buf;
+               }
+
+               fb_pad_unaligned_buffer(dst, d_pitch, src, idx,
+                                       image->height, shift_high,
+                                       shift_low, mod);
+               shift_low += mod;
+               dst += (shift_low >= 8) ? s_pitch : s_pitch - 1;
+               shift_low &= 7;
+               shift_high = 8 - shift_low;
+       }
+
+       info->fbops->fb_imageblit(info, image);
+
+}
+
+static void ud_putcs(struct vc_data *vc, struct fb_info *info,
+                     const unsigned short *s, int count, int yy, int xx,
+                     int fg, int bg)
+{
+       struct fb_image image;
+       struct display *p = &fb_display[vc->vc_num];
+       struct fbcon_ops *ops = info->fbcon_par;
+       u32 width = (vc->vc_font.width + 7)/8;
+       u32 cellsize = width * vc->vc_font.height;
+       u32 maxcnt = info->pixmap.size/cellsize;
+       u32 scan_align = info->pixmap.scan_align - 1;
+       u32 buf_align = info->pixmap.buf_align - 1;
+       u32 mod = vc->vc_font.width % 8, cnt, pitch, size;
+       u32 attribute = get_attribute(info, scr_readw(s));
+       u8 *dst, *buf = NULL;
+       u32 vyres = GETVYRES(p->scrollmode, info);
+       u32 vxres = GETVXRES(p->scrollmode, info);
+
+       if (!ops->fontbuffer)
+               return;
+
+       image.fg_color = fg;
+       image.bg_color = bg;
+       image.dy = vyres - ((yy * vc->vc_font.height) + vc->vc_font.height);
+       image.dx = vxres - ((xx + count) * vc->vc_font.width);
+       image.height = vc->vc_font.height;
+       image.depth = 1;
+
+       if (attribute) {
+               buf = kmalloc(cellsize, GFP_KERNEL);
+               if (!buf)
+                       return;
+       }
+
+       s += count - 1;
+
+       while (count) {
+               if (count > maxcnt)
+                       cnt = maxcnt;
+               else
+                       cnt = count;
+
+               image.width = vc->vc_font.width * cnt;
+               pitch = ((image.width + 7) >> 3) + scan_align;
+               pitch &= ~scan_align;
+               size = pitch * image.height + buf_align;
+               size &= ~buf_align;
+               dst = fb_get_buffer_offset(info, &info->pixmap, size);
+               image.data = dst;
+
+               if (!mod)
+                       ud_putcs_aligned(vc, info, s, attribute, cnt, pitch,
+                                        width, cellsize, &image, buf, dst);
+               else
+                       ud_putcs_unaligned(vc, info, s, attribute, cnt, pitch,
+                                          width, cellsize, &image,
+                                          buf, dst);
+
+               image.dx += image.width;
+               count -= cnt;
+               s -= cnt;
+               xx += cnt;
+       }
+
+       /* buf is always NULL except when in monochrome mode, so in this case
+          it's a gain to check buf against NULL even though kfree() handles
+          NULL pointers just fine */
+       if (unlikely(buf))
+               kfree(buf);
+
+}
+
+static void ud_clear_margins(struct vc_data *vc, struct fb_info *info,
+                            int bottom_only)
+{
+       unsigned int cw = vc->vc_font.width;
+       unsigned int ch = vc->vc_font.height;
+       unsigned int rw = info->var.xres - (vc->vc_cols*cw);
+       unsigned int bh = info->var.yres - (vc->vc_rows*ch);
+       struct fb_fillrect region;
+       int bgshift = (vc->vc_hi_font_mask) ? 13 : 12;
+
+       region.color = attr_bgcol_ec(bgshift,vc);
+       region.rop = ROP_COPY;
+
+       if (rw && !bottom_only) {
+               region.dy = 0;
+               region.dx = info->var.xoffset;
+               region.width  = rw;
+               region.height = info->var.yres_virtual;
+               info->fbops->fb_fillrect(info, &region);
+       }
+
+       if (bh) {
+               region.dy = info->var.yoffset;
+               region.dx = info->var.xoffset;
+                region.height  = bh;
+                region.width = info->var.xres;
+               info->fbops->fb_fillrect(info, &region);
+       }
+}
+
+static void ud_cursor(struct vc_data *vc, struct fb_info *info,
+                     struct display *p, int mode, int softback_lines,
+                     int fg, int bg)
+{
+       struct fb_cursor cursor;
+       struct fbcon_ops *ops = (struct fbcon_ops *) info->fbcon_par;
+       unsigned short charmask = vc->vc_hi_font_mask ? 0x1ff : 0xff;
+       int w = (vc->vc_font.width + 7) >> 3, c;
+       int y = real_y(p, vc->vc_y);
+       int attribute, use_sw = (vc->vc_cursor_type & 0x10);
+       int err = 1, dx, dy;
+       char *src;
+       u32 vyres = GETVYRES(p->scrollmode, info);
+       u32 vxres = GETVXRES(p->scrollmode, info);
+
+       if (!ops->fontbuffer)
+               return;
+
+       cursor.set = 0;
+
+       if (softback_lines) {
+               if (y + softback_lines >= vc->vc_rows) {
+                       mode = CM_ERASE;
+                       ops->cursor_flash = 0;
+                       return;
+               } else
+                       y += softback_lines;
+       }
+
+       c = scr_readw((u16 *) vc->vc_pos);
+       attribute = get_attribute(info, c);
+       src = ops->fontbuffer + ((c & charmask) * (w * vc->vc_font.height));
+
+       if (ops->cursor_state.image.data != src ||
+           ops->cursor_reset) {
+           ops->cursor_state.image.data = src;
+           cursor.set |= FB_CUR_SETIMAGE;
+       }
+
+       if (attribute) {
+               u8 *dst;
+
+               dst = kmalloc(w * vc->vc_font.height, GFP_ATOMIC);
+               if (!dst)
+                       return;
+               kfree(ops->cursor_data);
+               ops->cursor_data = dst;
+               ud_update_attr(dst, src, attribute, vc);
+               src = dst;
+       }
+
+       if (ops->cursor_state.image.fg_color != fg ||
+           ops->cursor_state.image.bg_color != bg ||
+           ops->cursor_reset) {
+               ops->cursor_state.image.fg_color = fg;
+               ops->cursor_state.image.bg_color = bg;
+               cursor.set |= FB_CUR_SETCMAP;
+       }
+
+       if (ops->cursor_state.image.height != vc->vc_font.height ||
+           ops->cursor_state.image.width != vc->vc_font.width ||
+           ops->cursor_reset) {
+               ops->cursor_state.image.height = vc->vc_font.height;
+               ops->cursor_state.image.width = vc->vc_font.width;
+               cursor.set |= FB_CUR_SETSIZE;
+       }
+
+       dy = vyres - ((y * vc->vc_font.height) + vc->vc_font.height);
+       dx = vxres - ((vc->vc_x * vc->vc_font.width) + vc->vc_font.width);
+
+       if (ops->cursor_state.image.dx != dx ||
+           ops->cursor_state.image.dy != dy ||
+           ops->cursor_reset) {
+               ops->cursor_state.image.dx = dx;
+               ops->cursor_state.image.dy = dy;
+               cursor.set |= FB_CUR_SETPOS;
+       }
+
+       if (ops->cursor_state.hot.x || ops->cursor_state.hot.y ||
+           ops->cursor_reset) {
+               ops->cursor_state.hot.x = cursor.hot.y = 0;
+               cursor.set |= FB_CUR_SETHOT;
+       }
+
+       if (cursor.set & FB_CUR_SETSIZE ||
+           vc->vc_cursor_type != p->cursor_shape ||
+           ops->cursor_state.mask == NULL ||
+           ops->cursor_reset) {
+               char *mask = kmalloc(w*vc->vc_font.height, GFP_ATOMIC);
+               int cur_height, size, i = 0;
+               u8 msk = 0xff;
+
+               if (!mask)
+                       return;
+
+               kfree(ops->cursor_state.mask);
+               ops->cursor_state.mask = mask;
+
+               p->cursor_shape = vc->vc_cursor_type;
+               cursor.set |= FB_CUR_SETSHAPE;
+
+               switch (p->cursor_shape & CUR_HWMASK) {
+               case CUR_NONE:
+                       cur_height = 0;
+                       break;
+               case CUR_UNDERLINE:
+                       cur_height = (vc->vc_font.height < 10) ? 1 : 2;
+                       break;
+               case CUR_LOWER_THIRD:
+                       cur_height = vc->vc_font.height/3;
+                       break;
+               case CUR_LOWER_HALF:
+                       cur_height = vc->vc_font.height >> 1;
+                       break;
+               case CUR_TWO_THIRDS:
+                       cur_height = (vc->vc_font.height << 1)/3;
+                       break;
+               case CUR_BLOCK:
+               default:
+                       cur_height = vc->vc_font.height;
+                       break;
+               }
+
+               size = cur_height * w;
+
+               while (size--)
+                       mask[i++] = msk;
+
+               size = (vc->vc_font.height - cur_height) * w;
+
+               while (size--)
+                       mask[i++] = ~msk;
+       }
+
+       switch (mode) {
+       case CM_ERASE:
+               ops->cursor_state.enable = 0;
+               break;
+       case CM_DRAW:
+       case CM_MOVE:
+       default:
+               ops->cursor_state.enable = (use_sw) ? 0 : 1;
+               break;
+       }
+
+       cursor.image.data = src;
+       cursor.image.fg_color = ops->cursor_state.image.fg_color;
+       cursor.image.bg_color = ops->cursor_state.image.bg_color;
+       cursor.image.dx = ops->cursor_state.image.dx;
+       cursor.image.dy = ops->cursor_state.image.dy;
+       cursor.image.height = ops->cursor_state.image.height;
+       cursor.image.width = ops->cursor_state.image.width;
+       cursor.hot.x = ops->cursor_state.hot.x;
+       cursor.hot.y = ops->cursor_state.hot.y;
+       cursor.mask = ops->cursor_state.mask;
+       cursor.enable = ops->cursor_state.enable;
+       cursor.image.depth = 1;
+       cursor.rop = ROP_XOR;
+
+       if (info->fbops->fb_cursor)
+               err = info->fbops->fb_cursor(info, &cursor);
+
+       if (err)
+               soft_cursor(info, &cursor);
+
+       ops->cursor_reset = 0;
+}
+
+int ud_update_start(struct fb_info *info)
+{
+       struct fbcon_ops *ops = info->fbcon_par;
+       struct display *p = &fb_display[ops->currcon];
+       u32 xoffset, yoffset;
+       u32 vyres = GETVYRES(p->scrollmode, info);
+       u32 vxres = GETVXRES(p->scrollmode, info);
+       int err;
+
+       xoffset = (vxres - info->var.xres) - ops->var.xoffset;
+       yoffset = (vyres - info->var.yres) - ops->var.yoffset;
+       ops->var.xoffset = xoffset;
+       ops->var.yoffset = yoffset;
+       err = fb_pan_display(info, &ops->var);
+       ops->var.xoffset = info->var.xoffset;
+       ops->var.yoffset = info->var.yoffset;
+       ops->var.vmode = info->var.vmode;
+       return err;
+}
+
+void fbcon_rotate_ud(struct fbcon_ops *ops)
+{
+       ops->bmove = ud_bmove;
+       ops->clear = ud_clear;
+       ops->putcs = ud_putcs;
+       ops->clear_margins = ud_clear_margins;
+       ops->cursor = ud_cursor;
+       ops->update_start = ud_update_start;
+}
+EXPORT_SYMBOL(fbcon_rotate_ud);
+
+MODULE_AUTHOR("Antonino Daplas <adaplas@pol.net>");
+MODULE_DESCRIPTION("Console Rotation (180 degrees) Support");
+MODULE_LICENSE("GPL");
index 7f76e2c6a4a1791580325b43d7ac84ac0d85aa5b..cb25324a56357bfbdb0c7a9fe8619153441799ba 100644 (file)
@@ -118,6 +118,18 @@ static void tile_cursor(struct vc_data *vc, struct fb_info *info,
        info->tileops->fb_tilecursor(info, &cursor);
 }
 
+static int tile_update_start(struct fb_info *info)
+{
+       struct fbcon_ops *ops = info->fbcon_par;
+       int err;
+
+       err = fb_pan_display(info, &ops->var);
+       ops->var.xoffset = info->var.xoffset;
+       ops->var.yoffset = info->var.yoffset;
+       ops->var.vmode = info->var.vmode;
+       return err;
+}
+
 void fbcon_set_tileops(struct vc_data *vc, struct fb_info *info,
                       struct display *p, struct fbcon_ops *ops)
 {
@@ -128,6 +140,7 @@ void fbcon_set_tileops(struct vc_data *vc, struct fb_info *info,
        ops->putcs = tile_putcs;
        ops->clear_margins = tile_clear_margins;
        ops->cursor = tile_cursor;
+       ops->update_start = tile_update_start;
 
        if (p) {
                map.width = vc->vc_font.width;
index e2667ddab3f11033fd440cf10ed57365741ae35e..9f180096c896f6330678adc74c78316aef458b0e 100644 (file)
@@ -14,6 +14,7 @@
 #include <linux/config.h>
 #include <linux/module.h>
 
+#include <linux/compat.h>
 #include <linux/types.h>
 #include <linux/errno.h>
 #include <linux/sched.h>
@@ -323,9 +324,103 @@ static struct logo_data {
        const struct linux_logo *logo;
 } fb_logo;
 
-int fb_prepare_logo(struct fb_info *info)
+static void fb_rotate_logo_ud(const u8 *in, u8 *out, u32 width, u32 height)
+{
+       u32 size = width * height, i;
+
+       out += size - 1;
+
+       for (i = size; i--; )
+               *out-- = *in++;
+}
+
+static void fb_rotate_logo_cw(const u8 *in, u8 *out, u32 width, u32 height)
+{
+       int i, j, w = width - 1;
+
+       for (i = 0; i < height; i++)
+               for (j = 0; j < width; j++)
+                       out[height * j + w - i] = *in++;
+}
+
+static void fb_rotate_logo_ccw(const u8 *in, u8 *out, u32 width, u32 height)
+{
+       int i, j, w = width - 1;
+
+       for (i = 0; i < height; i++)
+               for (j = 0; j < width; j++)
+                       out[height * (w - j) + i] = *in++;
+}
+
+static void fb_rotate_logo(struct fb_info *info, u8 *dst,
+                          struct fb_image *image, int rotate)
+{
+       u32 tmp;
+
+       if (rotate == FB_ROTATE_UD) {
+               image->dx = info->var.xres - image->width;
+               image->dy = info->var.yres - image->height;
+               fb_rotate_logo_ud(image->data, dst, image->width,
+                                 image->height);
+       } else if (rotate == FB_ROTATE_CW) {
+               tmp = image->width;
+               image->width = image->height;
+               image->height = tmp;
+               image->dx = info->var.xres - image->height;
+               fb_rotate_logo_cw(image->data, dst, image->width,
+                                 image->height);
+       } else if (rotate == FB_ROTATE_CCW) {
+               tmp = image->width;
+               image->width = image->height;
+               image->height = tmp;
+               image->dy = info->var.yres - image->width;
+               fb_rotate_logo_ccw(image->data, dst, image->width,
+                                  image->height);
+       }
+
+       image->data = dst;
+}
+
+static void fb_do_show_logo(struct fb_info *info, struct fb_image *image,
+                           int rotate)
+{
+       int x;
+
+       if (rotate == FB_ROTATE_UR) {
+               for (x = 0; x < num_online_cpus() &&
+                            x * (fb_logo.logo->width + 8) <=
+                            info->var.xres - fb_logo.logo->width; x++) {
+                       info->fbops->fb_imageblit(info, image);
+                       image->dx += fb_logo.logo->width + 8;
+               }
+       } else if (rotate == FB_ROTATE_UD) {
+               for (x = 0; x < num_online_cpus() &&
+                            x * (fb_logo.logo->width + 8) <=
+                            info->var.xres - fb_logo.logo->width; x++) {
+                       info->fbops->fb_imageblit(info, image);
+                       image->dx -= fb_logo.logo->width + 8;
+               }
+       } else if (rotate == FB_ROTATE_CW) {
+               for (x = 0; x < num_online_cpus() &&
+                            x * (fb_logo.logo->width + 8) <=
+                            info->var.yres - fb_logo.logo->width; x++) {
+                       info->fbops->fb_imageblit(info, image);
+                       image->dy += fb_logo.logo->width + 8;
+               }
+       } else if (rotate == FB_ROTATE_CCW) {
+               for (x = 0; x < num_online_cpus() &&
+                            x * (fb_logo.logo->width + 8) <=
+                            info->var.yres - fb_logo.logo->width; x++) {
+                       info->fbops->fb_imageblit(info, image);
+                       image->dy -= fb_logo.logo->width + 8;
+               }
+       }
+}
+
+int fb_prepare_logo(struct fb_info *info, int rotate)
 {
        int depth = fb_get_color_depth(&info->var, &info->fix);
+       int yres;
 
        memset(&fb_logo, 0, sizeof(struct logo_data));
 
@@ -358,10 +453,16 @@ int fb_prepare_logo(struct fb_info *info)
        /* Return if no suitable logo was found */
        fb_logo.logo = fb_find_logo(depth);
        
-       if (!fb_logo.logo || fb_logo.logo->height > info->var.yres) {
+       if (rotate == FB_ROTATE_UR || rotate == FB_ROTATE_UD)
+               yres = info->var.yres;
+       else
+               yres = info->var.xres;
+
+       if (fb_logo.logo && fb_logo.logo->height > yres) {
                fb_logo.logo = NULL;
                return 0;
        }
+
        /* What depth we asked for might be different from what we get */
        if (fb_logo.logo->type == LINUX_LOGO_CLUT224)
                fb_logo.depth = 8;
@@ -372,12 +473,11 @@ int fb_prepare_logo(struct fb_info *info)
        return fb_logo.logo->height;
 }
 
-int fb_show_logo(struct fb_info *info)
+int fb_show_logo(struct fb_info *info, int rotate)
 {
        u32 *palette = NULL, *saved_pseudo_palette = NULL;
-       unsigned char *logo_new = NULL;
+       unsigned char *logo_new = NULL, *logo_rotate = NULL;
        struct fb_image image;
-       int x;
 
        /* Return if the frame buffer is not mapped or suspended */
        if (fb_logo.logo == NULL || info->state != FBINFO_STATE_RUNNING)
@@ -417,25 +517,30 @@ int fb_show_logo(struct fb_info *info)
                fb_set_logo(info, fb_logo.logo, logo_new, fb_logo.depth);
        }
 
+       image.dx = 0;
+       image.dy = 0;
        image.width = fb_logo.logo->width;
        image.height = fb_logo.logo->height;
-       image.dy = 0;
 
-       for (x = 0; x < num_online_cpus() * (fb_logo.logo->width + 8) &&
-            x <= info->var.xres-fb_logo.logo->width; x += (fb_logo.logo->width + 8)) {
-               image.dx = x;
-               info->fbops->fb_imageblit(info, &image);
+       if (rotate) {
+               logo_rotate = kmalloc(fb_logo.logo->width *
+                                     fb_logo.logo->height, GFP_KERNEL);
+               if (logo_rotate)
+                       fb_rotate_logo(info, logo_rotate, &image, rotate);
        }
-       
+
+       fb_do_show_logo(info, &image, rotate);
+
        kfree(palette);
        if (saved_pseudo_palette != NULL)
                info->pseudo_palette = saved_pseudo_palette;
        kfree(logo_new);
+       kfree(logo_rotate);
        return fb_logo.logo->height;
 }
 #else
-int fb_prepare_logo(struct fb_info *info) { return 0; }
-int fb_show_logo(struct fb_info *info) { return 0; }
+int fb_prepare_logo(struct fb_info *info, int rotate) { return 0; }
+int fb_show_logo(struct fb_info *info, int rotate) { return 0; }
 #endif /* CONFIG_LOGO */
 
 static int fbmem_read_proc(char *buf, char **start, off_t offset,
@@ -829,18 +934,154 @@ fb_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
 }
 
 #ifdef CONFIG_COMPAT
+struct fb_fix_screeninfo32 {
+       char                    id[16];
+       compat_caddr_t          smem_start;
+       u32                     smem_len;
+       u32                     type;
+       u32                     type_aux;
+       u32                     visual;
+       u16                     xpanstep;
+       u16                     ypanstep;
+       u16                     ywrapstep;
+       u32                     line_length;
+       compat_caddr_t          mmio_start;
+       u32                     mmio_len;
+       u32                     accel;
+       u16                     reserved[3];
+};
+
+struct fb_cmap32 {
+       u32                     start;
+       u32                     len;
+       compat_caddr_t  red;
+       compat_caddr_t  green;
+       compat_caddr_t  blue;
+       compat_caddr_t  transp;
+};
+
+static int fb_getput_cmap(struct inode *inode, struct file *file,
+                       unsigned int cmd, unsigned long arg)
+{
+       struct fb_cmap_user __user *cmap;
+       struct fb_cmap32 __user *cmap32;
+       __u32 data;
+       int err;
+
+       cmap = compat_alloc_user_space(sizeof(*cmap));
+       cmap32 = compat_ptr(arg);
+
+       if (copy_in_user(&cmap->start, &cmap32->start, 2 * sizeof(__u32)))
+               return -EFAULT;
+
+       if (get_user(data, &cmap32->red) ||
+           put_user(compat_ptr(data), &cmap->red) ||
+           get_user(data, &cmap32->green) ||
+           put_user(compat_ptr(data), &cmap->green) ||
+           get_user(data, &cmap32->blue) ||
+           put_user(compat_ptr(data), &cmap->blue) ||
+           get_user(data, &cmap32->transp) ||
+           put_user(compat_ptr(data), &cmap->transp))
+               return -EFAULT;
+
+       err = fb_ioctl(inode, file, cmd, (unsigned long) cmap);
+
+       if (!err) {
+               if (copy_in_user(&cmap32->start,
+                                &cmap->start,
+                                2 * sizeof(__u32)))
+                       err = -EFAULT;
+       }
+       return err;
+}
+
+static int do_fscreeninfo_to_user(struct fb_fix_screeninfo *fix,
+                                 struct fb_fix_screeninfo32 __user *fix32)
+{
+       __u32 data;
+       int err;
+
+       err = copy_to_user(&fix32->id, &fix->id, sizeof(fix32->id));
+
+       data = (__u32) (unsigned long) fix->smem_start;
+       err |= put_user(data, &fix32->smem_start);
+
+       err |= put_user(fix->smem_len, &fix32->smem_len);
+       err |= put_user(fix->type, &fix32->type);
+       err |= put_user(fix->type_aux, &fix32->type_aux);
+       err |= put_user(fix->visual, &fix32->visual);
+       err |= put_user(fix->xpanstep, &fix32->xpanstep);
+       err |= put_user(fix->ypanstep, &fix32->ypanstep);
+       err |= put_user(fix->ywrapstep, &fix32->ywrapstep);
+       err |= put_user(fix->line_length, &fix32->line_length);
+
+       data = (__u32) (unsigned long) fix->mmio_start;
+       err |= put_user(data, &fix32->mmio_start);
+
+       err |= put_user(fix->mmio_len, &fix32->mmio_len);
+       err |= put_user(fix->accel, &fix32->accel);
+       err |= copy_to_user(fix32->reserved, fix->reserved,
+                           sizeof(fix->reserved));
+
+       return err;
+}
+
+static int fb_get_fscreeninfo(struct inode *inode, struct file *file,
+                               unsigned int cmd, unsigned long arg)
+{
+       mm_segment_t old_fs;
+       struct fb_fix_screeninfo fix;
+       struct fb_fix_screeninfo32 __user *fix32;
+       int err;
+
+       fix32 = compat_ptr(arg);
+
+       old_fs = get_fs();
+       set_fs(KERNEL_DS);
+       err = fb_ioctl(inode, file, cmd, (unsigned long) &fix);
+       set_fs(old_fs);
+
+       if (!err)
+               err = do_fscreeninfo_to_user(&fix, fix32);
+
+       return err;
+}
+
 static long
 fb_compat_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
 {
-       int fbidx = iminor(file->f_dentry->d_inode);
+       struct inode *inode = file->f_dentry->d_inode;
+       int fbidx = iminor(inode);
        struct fb_info *info = registered_fb[fbidx];
        struct fb_ops *fb = info->fbops;
-       long ret;
+       long ret = -ENOIOCTLCMD;
 
-       if (fb->fb_compat_ioctl == NULL)
-               return -ENOIOCTLCMD;
        lock_kernel();
-       ret = fb->fb_compat_ioctl(file, cmd, arg, info);
+       switch(cmd) {
+       case FBIOGET_VSCREENINFO:
+       case FBIOPUT_VSCREENINFO:
+       case FBIOPAN_DISPLAY:
+       case FBIOGET_CON2FBMAP:
+       case FBIOPUT_CON2FBMAP:
+               arg = (unsigned long) compat_ptr(arg);
+       case FBIOBLANK:
+               ret = fb_ioctl(inode, file, cmd, arg);
+               break;
+
+       case FBIOGET_FSCREENINFO:
+               ret = fb_get_fscreeninfo(inode, file, cmd, arg);
+               break;
+
+       case FBIOGETCMAP:
+       case FBIOPUTCMAP:
+               ret = fb_getput_cmap(inode, file, cmd, arg);
+               break;
+
+       default:
+               if (fb->fb_compat_ioctl)
+                       ret = fb->fb_compat_ioctl(file, cmd, arg, info);
+               break;
+       }
        unlock_kernel();
        return ret;
 }
@@ -1215,6 +1456,28 @@ int fb_new_modelist(struct fb_info *info)
        return err;
 }
 
+/**
+ * fb_con_duit - user<->fbcon passthrough
+ * @info: struct fb_info
+ * @event: notification event to be passed to fbcon
+ * @data: private data
+ *
+ * DESCRIPTION
+ * This function is an fbcon-user event passing channel
+ * which bypasses fbdev.  This is hopefully temporary
+ * until a user interface for fbcon is created
+ */
+int fb_con_duit(struct fb_info *info, int event, void *data)
+{
+       struct fb_event evnt;
+
+       evnt.info = info;
+       evnt.data = data;
+
+       return notifier_call_chain(&fb_notifier_list, event, &evnt);
+}
+EXPORT_SYMBOL(fb_con_duit);
+
 static char *video_options[FB_MAX];
 static int ofonly;
 
index 007c8e9b2b3974db3df79df602d1a6399015cf2c..08dac9580d15440728d5c6374ec7c2de20a8e86c 100644 (file)
@@ -213,6 +213,70 @@ static ssize_t show_bpp(struct class_device *class_device, char *buf)
        return snprintf(buf, PAGE_SIZE, "%d\n", fb_info->var.bits_per_pixel);
 }
 
+static ssize_t store_rotate(struct class_device *class_device, const char *buf,
+                           size_t count)
+{
+       struct fb_info *fb_info = class_get_devdata(class_device);
+       struct fb_var_screeninfo var;
+       char **last = NULL;
+       int err;
+
+       var = fb_info->var;
+       var.rotate = simple_strtoul(buf, last, 0);
+
+       if ((err = activate(fb_info, &var)))
+               return err;
+
+       return count;
+}
+
+
+static ssize_t show_rotate(struct class_device *class_device, char *buf)
+{
+       struct fb_info *fb_info = class_get_devdata(class_device);
+
+       return snprintf(buf, PAGE_SIZE, "%d\n", fb_info->var.rotate);
+}
+
+static ssize_t store_con_rotate(struct class_device *class_device,
+                               const char *buf, size_t count)
+{
+       struct fb_info *fb_info = class_get_devdata(class_device);
+       int rotate;
+       char **last = NULL;
+
+       acquire_console_sem();
+       rotate = simple_strtoul(buf, last, 0);
+       fb_con_duit(fb_info, FB_EVENT_SET_CON_ROTATE, &rotate);
+       release_console_sem();
+       return count;
+}
+
+static ssize_t store_con_rotate_all(struct class_device *class_device,
+                               const char *buf, size_t count)
+{
+       struct fb_info *fb_info = class_get_devdata(class_device);
+       int rotate;
+       char **last = NULL;
+
+       acquire_console_sem();
+       rotate = simple_strtoul(buf, last, 0);
+       fb_con_duit(fb_info, FB_EVENT_SET_CON_ROTATE_ALL, &rotate);
+       release_console_sem();
+       return count;
+}
+
+static ssize_t show_con_rotate(struct class_device *class_device, char *buf)
+{
+       struct fb_info *fb_info = class_get_devdata(class_device);
+       int rotate;
+
+       acquire_console_sem();
+       rotate = fb_con_duit(fb_info, FB_EVENT_GET_CON_ROTATE, NULL);
+       release_console_sem();
+       return snprintf(buf, PAGE_SIZE, "%d\n", rotate);
+}
+
 static ssize_t store_virtual(struct class_device *class_device,
                             const char * buf, size_t count)
 {
@@ -440,6 +504,9 @@ static struct class_device_attribute class_device_attrs[] = {
        __ATTR(virtual_size, S_IRUGO|S_IWUSR, show_virtual, store_virtual),
        __ATTR(name, S_IRUGO, show_name, NULL),
        __ATTR(stride, S_IRUGO, show_stride, NULL),
+       __ATTR(rotate, S_IRUGO|S_IWUSR, show_rotate, store_rotate),
+       __ATTR(con_rotate, S_IRUGO|S_IWUSR, show_con_rotate, store_con_rotate),
+       __ATTR(con_rotate_all, S_IWUSR, NULL, store_con_rotate_all),
 };
 
 int fb_init_class_device(struct fb_info *fb_info)
index 0799b999b3143e361aef7cf39e0a211137ec50de..427689e584da4745efd130960fd5ff2ae62ecc46 100644 (file)
 #include <linux/pci.h>
 #include <linux/vmalloc.h>
 #include <linux/pagemap.h>
-#include <linux/version.h>
 
 #include <asm/io.h>
 
index ac94c2e5ff857720161b9e7291fe10ecb54f2721..624c4bc96f0d2a904447d588c88e34344845c7b4 100644 (file)
@@ -34,7 +34,6 @@
 #include <linux/pci.h>
 #include <linux/vmalloc.h>
 #include <linux/pagemap.h>
-#include <linux/version.h>
 
 #include <asm/io.h>
 
index 1789a52d776a984ba9bec98371f7fd974157eead..1da2f84bdc254d6bcc081afbc772dfab1ec1b526 100644 (file)
@@ -251,6 +251,10 @@ static const struct fb_videomode modedb[] = {
        NULL, 60, 1920, 1200, 5177, 128, 336, 1, 38, 208, 3,
        FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
        FB_VMODE_NONINTERLACED
+    }, {
+       /* 1152x768, 60 Hz, PowerBook G4 Titanium I and II */
+       NULL, 60, 1152, 768, 15386, 158, 26, 29, 3, 136, 6,
+       FB_SYNC_HOR_HIGH_ACT|FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED
     },
 };
 
index f0dfb35e3191b4637e76d085927f3e41dd76e5d0..09e2f28419015559b0cd57a8b163acd65d45c36f 100644 (file)
@@ -1315,10 +1315,14 @@ static void savagefb_set_fix(struct fb_info *info)
        info->fix.line_length = info->var.xres_virtual *
                info->var.bits_per_pixel / 8;
 
-       if (info->var.bits_per_pixel == 8)
+       if (info->var.bits_per_pixel == 8) {
                info->fix.visual      = FB_VISUAL_PSEUDOCOLOR;
-       else
+               info->fix.xpanstep    = 4;
+       } else {
                info->fix.visual      = FB_VISUAL_TRUECOLOR;
+               info->fix.xpanstep    = 2;
+       }
+
 }
 
 #if defined(CONFIG_FB_SAVAGE_ACCEL)
@@ -1363,7 +1367,6 @@ static int savagefb_set_par (struct fb_info *info)
        par->minClock = 10000;
 
        savagefb_set_par_int (par);
-       savagefb_update_start (par, var);
        fb_set_cmap (&info->cmap, info);
        savagefb_set_fix(info);
        savagefb_set_clip(info);
@@ -1873,7 +1876,6 @@ static int __devinit savage_init_fb_info (struct fb_info *info,
 
        info->fix.type     = FB_TYPE_PACKED_PIXELS;
        info->fix.type_aux         = 0;
-       info->fix.xpanstep         = 2;
        info->fix.ypanstep         = 1;
        info->fix.ywrapstep   = 0;
        info->fix.accel       = id->driver_data;
index 690bb6fe82812082d00dc04a410531aa1e7abaef..226ae8a8848202cdb1e09abc82b5dc608f27dc47 100644 (file)
@@ -21,6 +21,7 @@
 #include <linux/fb.h>
 #include <linux/ioport.h>
 #include <linux/init.h>
+#include <linux/platform_device.h>
 
 #include <asm/io.h>
 #include <video/vga.h>
  * card parameters
  */
 
-static struct fb_info vga16fb; 
-
-static struct vga16fb_par {
+struct vga16fb_par {
        /* structure holding original VGA register settings when the
            screen is blanked */
        struct {
-               unsigned char   SeqCtrlIndex;           /* Sequencer Index reg.   */
-               unsigned char   CrtCtrlIndex;           /* CRT-Contr. Index reg.  */
-               unsigned char   CrtMiscIO;              /* Miscellaneous register */
-               unsigned char   HorizontalTotal;        /* CRT-Controller:00h */
-               unsigned char   HorizDisplayEnd;        /* CRT-Controller:01h */
-               unsigned char   StartHorizRetrace;      /* CRT-Controller:04h */
-               unsigned char   EndHorizRetrace;        /* CRT-Controller:05h */
-               unsigned char   Overflow;               /* CRT-Controller:07h */
-               unsigned char   StartVertRetrace;       /* CRT-Controller:10h */
-               unsigned char   EndVertRetrace;         /* CRT-Controller:11h */
-               unsigned char   ModeControl;            /* CRT-Controller:17h */
-               unsigned char   ClockingMode;           /* Seq-Controller:01h */
+               unsigned char   SeqCtrlIndex;     /* Sequencer Index reg.   */
+               unsigned char   CrtCtrlIndex;     /* CRT-Contr. Index reg.  */
+               unsigned char   CrtMiscIO;        /* Miscellaneous register */
+               unsigned char   HorizontalTotal;  /* CRT-Controller:00h */
+               unsigned char   HorizDisplayEnd;  /* CRT-Controller:01h */
+               unsigned char   StartHorizRetrace;/* CRT-Controller:04h */
+               unsigned char   EndHorizRetrace;  /* CRT-Controller:05h */
+               unsigned char   Overflow;         /* CRT-Controller:07h */
+               unsigned char   StartVertRetrace; /* CRT-Controller:10h */
+               unsigned char   EndVertRetrace;   /* CRT-Controller:11h */
+               unsigned char   ModeControl;      /* CRT-Controller:17h */
+               unsigned char   ClockingMode;     /* Seq-Controller:01h */
        } vga_state;
        struct vgastate state;
        atomic_t ref_count;
        int palette_blanked, vesa_blanked, mode, isVGA;
        u8 misc, pel_msk, vss, clkdiv;
        u8 crtc[VGA_CRT_C];
-} vga16_par;
+};
 
 /* --------------------------------------------------------------------- */
 
-static struct fb_var_screeninfo vga16fb_defined = {
+static struct fb_var_screeninfo vga16fb_defined __initdata = {
        .xres           = 640,
        .yres           = 480,
        .xres_virtual   = 640,
@@ -205,7 +204,7 @@ static inline void setindex(int index)
 static void vga16fb_pan_var(struct fb_info *info, 
                            struct fb_var_screeninfo *var)
 {
-       struct vga16fb_par *par = (struct vga16fb_par *) info->par;
+       struct vga16fb_par *par = info->par;
        u32 xoffset, pos;
 
        xoffset = var->xoffset;
@@ -300,7 +299,7 @@ static void vga16fb_clock_chip(struct vga16fb_par *par,
 
 static int vga16fb_open(struct fb_info *info, int user)
 {
-       struct vga16fb_par *par = (struct vga16fb_par *) info->par;
+       struct vga16fb_par *par = info->par;
        int cnt = atomic_read(&par->ref_count);
 
        if (!cnt) {
@@ -315,7 +314,7 @@ static int vga16fb_open(struct fb_info *info, int user)
 
 static int vga16fb_release(struct fb_info *info, int user)
 {
-       struct vga16fb_par *par = (struct vga16fb_par *) info->par;
+       struct vga16fb_par *par = info->par;
        int cnt = atomic_read(&par->ref_count);
 
        if (!cnt)
@@ -330,7 +329,7 @@ static int vga16fb_release(struct fb_info *info, int user)
 static int vga16fb_check_var(struct fb_var_screeninfo *var,
                             struct fb_info *info)
 {
-       struct vga16fb_par *par = (struct vga16fb_par *) info->par;
+       struct vga16fb_par *par = info->par;
        u32 xres, right, hslen, left, xtotal;
        u32 yres, lower, vslen, upper, ytotal;
        u32 vxres, xoffset, vyres, yoffset;
@@ -535,7 +534,7 @@ static int vga16fb_check_var(struct fb_var_screeninfo *var,
 
 static int vga16fb_set_par(struct fb_info *info)
 {
-       struct vga16fb_par *par = (struct vga16fb_par *) info->par;
+       struct vga16fb_par *par = info->par;
        u8 gdc[VGA_GFX_C];
        u8 seq[VGA_SEQ_C];
        u8 atc[VGA_ATT_C];
@@ -677,7 +676,7 @@ static int vga16fb_setcolreg(unsigned regno, unsigned red, unsigned green,
                             unsigned blue, unsigned transp,
                             struct fb_info *info)
 {
-       struct vga16fb_par *par = (struct vga16fb_par *) info->par;
+       struct vga16fb_par *par = info->par;
        int gray;
 
        /*
@@ -850,7 +849,7 @@ static void vga_pal_blank(void)
 /* 0 unblank, 1 blank, 2 no vsync, 3 no hsync, 4 off */
 static int vga16fb_blank(int blank, struct fb_info *info)
 {
-       struct vga16fb_par *par = (struct vga16fb_par *) info->par;
+       struct vga16fb_par *par = info->par;
 
        switch (blank) {
        case FB_BLANK_UNBLANK:                          /* Unblank */
@@ -1201,7 +1200,7 @@ static void vga_imageblit_expand(struct fb_info *info, const struct fb_image *im
 {
        char __iomem *where = info->screen_base + (image->dx/8) +
                image->dy * info->fix.line_length;
-       struct vga16fb_par *par = (struct vga16fb_par *) info->par;
+       struct vga16fb_par *par = info->par;
        char *cdat = (char *) image->data;
        char __iomem *dst;
        int x, y;
@@ -1266,7 +1265,7 @@ static void vga_imageblit_color(struct fb_info *info, const struct fb_image *ima
        /*
         * Draw logo 
         */
-       struct vga16fb_par *par = (struct vga16fb_par *) info->par;
+       struct vga16fb_par *par = info->par;
        char __iomem *where =
                info->screen_base + image->dy * info->fix.line_length +
                image->dx/8;
@@ -1343,89 +1342,141 @@ static int vga16fb_setup(char *options)
 }
 #endif
 
-static int __init vga16fb_init(void)
+static int __init vga16fb_probe(struct device *device)
 {
+       struct platform_device *dev = to_platform_device(device);
+       struct fb_info *info;
+       struct vga16fb_par *par;
        int i;
-       int ret;
-#ifndef MODULE
-       char *option = NULL;
+       int ret = 0;
 
-       if (fb_get_options("vga16fb", &option))
-               return -ENODEV;
-
-       vga16fb_setup(option);
-#endif
        printk(KERN_DEBUG "vga16fb: initializing\n");
+       info = framebuffer_alloc(sizeof(struct vga16fb_par), &dev->dev);
+
+       if (!info) {
+               ret = -ENOMEM;
+               goto err_fb_alloc;
+       }
 
        /* XXX share VGA_FB_PHYS and I/O region with vgacon and others */
+       info->screen_base = (void __iomem *)VGA_MAP_MEM(VGA_FB_PHYS);
 
-       vga16fb.screen_base = (void __iomem *)VGA_MAP_MEM(VGA_FB_PHYS);
-       if (!vga16fb.screen_base) {
+       if (!info->screen_base) {
                printk(KERN_ERR "vga16fb: unable to map device\n");
                ret = -ENOMEM;
                goto err_ioremap;
        }
-       printk(KERN_INFO "vga16fb: mapped to 0x%p\n", vga16fb.screen_base);
 
-       vga16_par.isVGA = ORIG_VIDEO_ISVGA;
-       vga16_par.palette_blanked = 0;
-       vga16_par.vesa_blanked = 0;
+       printk(KERN_INFO "vga16fb: mapped to 0x%p\n", info->screen_base);
+       par = info->par;
 
-       i = vga16_par.isVGA? 6 : 2;
+       par->isVGA = ORIG_VIDEO_ISVGA;
+       par->palette_blanked = 0;
+       par->vesa_blanked = 0;
+
+       i = par->isVGA? 6 : 2;
        
        vga16fb_defined.red.length   = i;
        vga16fb_defined.green.length = i;
        vga16fb_defined.blue.length  = i;       
 
        /* name should not depend on EGA/VGA */
-       vga16fb.fbops = &vga16fb_ops;
-       vga16fb.var = vga16fb_defined;
-       vga16fb.fix = vga16fb_fix;
-       vga16fb.par = &vga16_par;
-       vga16fb.flags = FBINFO_FLAG_DEFAULT |
+       info->fbops = &vga16fb_ops;
+       info->var = vga16fb_defined;
+       info->fix = vga16fb_fix;
+       info->flags = FBINFO_FLAG_DEFAULT |
                FBINFO_HWACCEL_YPAN;
 
-       i = (vga16fb_defined.bits_per_pixel == 8) ? 256 : 16;
-       ret = fb_alloc_cmap(&vga16fb.cmap, i, 0);
+       i = (info->var.bits_per_pixel == 8) ? 256 : 16;
+       ret = fb_alloc_cmap(&info->cmap, i, 0);
        if (ret) {
                printk(KERN_ERR "vga16fb: unable to allocate colormap\n");
                ret = -ENOMEM;
                goto err_alloc_cmap;
        }
 
-       if (vga16fb_check_var(&vga16fb.var, &vga16fb)) {
+       if (vga16fb_check_var(&info->var, info)) {
                printk(KERN_ERR "vga16fb: unable to validate variable\n");
                ret = -EINVAL;
                goto err_check_var;
        }
 
-       vga16fb_update_fix(&vga16fb);
+       vga16fb_update_fix(info);
 
-       if (register_framebuffer(&vga16fb) < 0) {
+       if (register_framebuffer(info) < 0) {
                printk(KERN_ERR "vga16fb: unable to register framebuffer\n");
                ret = -EINVAL;
                goto err_check_var;
        }
 
        printk(KERN_INFO "fb%d: %s frame buffer device\n",
-              vga16fb.node, vga16fb.fix.id);
+              info->node, info->fix.id);
+       dev_set_drvdata(device, info);
 
        return 0;
 
  err_check_var:
-       fb_dealloc_cmap(&vga16fb.cmap);
+       fb_dealloc_cmap(&info->cmap);
  err_alloc_cmap:
-       iounmap(vga16fb.screen_base);
+       iounmap(info->screen_base);
  err_ioremap:
+       framebuffer_release(info);
+ err_fb_alloc:
+       return ret;
+}
+
+static int vga16fb_remove(struct device *device)
+{
+       struct fb_info *info = dev_get_drvdata(device);
+
+       if (info) {
+               unregister_framebuffer(info);
+               iounmap(info->screen_base);
+               fb_dealloc_cmap(&info->cmap);
+       /* XXX unshare VGA regions */
+               framebuffer_release(info);
+       }
+
+       return 0;
+}
+
+static struct device_driver vga16fb_driver = {
+       .name = "vga16fb",
+       .bus  = &platform_bus_type,
+       .probe = vga16fb_probe,
+       .remove = vga16fb_remove,
+};
+
+static struct platform_device vga16fb_device = {
+       .name = "vga16fb",
+};
+
+static int __init vga16fb_init(void)
+{
+       int ret;
+#ifndef MODULE
+       char *option = NULL;
+
+       if (fb_get_options("vga16fb", &option))
+               return -ENODEV;
+
+       vga16fb_setup(option);
+#endif
+       ret = driver_register(&vga16fb_driver);
+
+       if (!ret) {
+               ret = platform_device_register(&vga16fb_device);
+               if (ret)
+                       driver_unregister(&vga16fb_driver);
+       }
+
        return ret;
 }
 
 static void __exit vga16fb_exit(void)
 {
-    unregister_framebuffer(&vga16fb);
-    iounmap(vga16fb.screen_base);
-    fb_dealloc_cmap(&vga16fb.cmap);
-    /* XXX unshare VGA regions */
+       platform_device_unregister(&vga16fb_device);
+       driver_unregister(&vga16fb_driver);
 }
 
 MODULE_LICENSE("GPL");
index ca92940f39438d9d7b4bffe0456815a2421b6b58..d9e01daee630dae2283c27bdf559dd93597b5c1a 100644 (file)
@@ -485,11 +485,6 @@ int restore_vga (struct vgastate *state)
        return 0;
 }
 
-#ifdef MODULE
-int init_module(void) { return 0; };
-void cleanup_module(void) {};
-#endif
-
 EXPORT_SYMBOL(save_vga);
 EXPORT_SYMBOL(restore_vga);
 
index bbc3cc63854f74ea49a43b3994cca7d3bf4e02f2..89c849da85040edeb0794a93a2a0ad5ba5352387 100644 (file)
@@ -32,7 +32,6 @@
 #include <linux/string.h>
 #include <linux/smp_lock.h>
 #include <linux/inet.h>
-#include <linux/version.h>
 #include <linux/list.h>
 #include <asm/uaccess.h>
 #include <linux/idr.h>
index fd528433de43d1faeff397551081ac4ea48320b5..f6cd01352cc87753f4ee717c70197bc146e68ed3 100644 (file)
@@ -12,7 +12,6 @@
 #define ADFS_NDA_PUBLIC_READ   (1 << 5)
 #define ADFS_NDA_PUBLIC_WRITE  (1 << 6)
 
-#include <linux/version.h>
 #include "dir_f.h"
 
 struct buffer_head;
index 8ae0db6cd69c5772daa86e0dd36aa3df1d3c2333..2568eb41cb3a248fece5a8b498924a3dc6defe43 100644 (file)
@@ -150,7 +150,7 @@ static int load_misc_binary(struct linux_binprm *bprm, struct pt_regs *regs)
 
                /* if the binary is not readable than enforce mm->dumpable=0
                   regardless of the interpreter's permissions */
-               if (permission(bprm->file->f_dentry->d_inode, MAY_READ, NULL))
+               if (file_permission(bprm->file, MAY_READ))
                        bprm->interp_flags |= BINPRM_FLAGS_ENFORCE_NONDUMP;
 
                allow_write_access(bprm->file);
index 4909754ea84a9873d931280c0af377d3d6abe15e..26300fccb4fc6a824eb70f8622e04123fc8e2b18 100644 (file)
@@ -840,146 +840,6 @@ static int hdio_getgeo(unsigned int fd, unsigned int cmd, unsigned long arg)
        return err ? -EFAULT : 0;
 }
 
-struct fb_fix_screeninfo32 {
-       char                    id[16];
-        compat_caddr_t smem_start;
-       u32                     smem_len;
-       u32                     type;
-       u32                     type_aux;
-       u32                     visual;
-       u16                     xpanstep;
-       u16                     ypanstep;
-       u16                     ywrapstep;
-       u32                     line_length;
-        compat_caddr_t mmio_start;
-       u32                     mmio_len;
-       u32                     accel;
-       u16                     reserved[3];
-};
-
-struct fb_cmap32 {
-       u32                     start;
-       u32                     len;
-       compat_caddr_t  red;
-       compat_caddr_t  green;
-       compat_caddr_t  blue;
-       compat_caddr_t  transp;
-};
-
-static int fb_getput_cmap(unsigned int fd, unsigned int cmd, unsigned long arg)
-{
-       struct fb_cmap_user __user *cmap;
-       struct fb_cmap32 __user *cmap32;
-       __u32 data;
-       int err;
-
-       cmap = compat_alloc_user_space(sizeof(*cmap));
-       cmap32 = compat_ptr(arg);
-
-       if (copy_in_user(&cmap->start, &cmap32->start, 2 * sizeof(__u32)))
-               return -EFAULT;
-
-       if (get_user(data, &cmap32->red) ||
-           put_user(compat_ptr(data), &cmap->red) ||
-           get_user(data, &cmap32->green) ||
-           put_user(compat_ptr(data), &cmap->green) ||
-           get_user(data, &cmap32->blue) ||
-           put_user(compat_ptr(data), &cmap->blue) ||
-           get_user(data, &cmap32->transp) ||
-           put_user(compat_ptr(data), &cmap->transp))
-               return -EFAULT;
-
-       err = sys_ioctl(fd, cmd, (unsigned long) cmap);
-
-       if (!err) {
-               if (copy_in_user(&cmap32->start,
-                                &cmap->start,
-                                2 * sizeof(__u32)))
-                       err = -EFAULT;
-       }
-       return err;
-}
-
-static int do_fscreeninfo_to_user(struct fb_fix_screeninfo *fix,
-                                 struct fb_fix_screeninfo32 __user *fix32)
-{
-       __u32 data;
-       int err;
-
-       err = copy_to_user(&fix32->id, &fix->id, sizeof(fix32->id));
-
-       data = (__u32) (unsigned long) fix->smem_start;
-       err |= put_user(data, &fix32->smem_start);
-
-       err |= put_user(fix->smem_len, &fix32->smem_len);
-       err |= put_user(fix->type, &fix32->type);
-       err |= put_user(fix->type_aux, &fix32->type_aux);
-       err |= put_user(fix->visual, &fix32->visual);
-       err |= put_user(fix->xpanstep, &fix32->xpanstep);
-       err |= put_user(fix->ypanstep, &fix32->ypanstep);
-       err |= put_user(fix->ywrapstep, &fix32->ywrapstep);
-       err |= put_user(fix->line_length, &fix32->line_length);
-
-       data = (__u32) (unsigned long) fix->mmio_start;
-       err |= put_user(data, &fix32->mmio_start);
-
-       err |= put_user(fix->mmio_len, &fix32->mmio_len);
-       err |= put_user(fix->accel, &fix32->accel);
-       err |= copy_to_user(fix32->reserved, fix->reserved,
-                           sizeof(fix->reserved));
-
-       return err;
-}
-
-static int fb_get_fscreeninfo(unsigned int fd, unsigned int cmd, unsigned long arg)
-{
-       mm_segment_t old_fs;
-       struct fb_fix_screeninfo fix;
-       struct fb_fix_screeninfo32 __user *fix32;
-       int err;
-
-       fix32 = compat_ptr(arg);
-
-       old_fs = get_fs();
-       set_fs(KERNEL_DS);
-       err = sys_ioctl(fd, cmd, (unsigned long) &fix);
-       set_fs(old_fs);
-
-       if (!err)
-               err = do_fscreeninfo_to_user(&fix, fix32);
-
-       return err;
-}
-
-static int fb_ioctl_trans(unsigned int fd, unsigned int cmd, unsigned long arg)
-{
-       int err;
-
-       switch (cmd) {
-       case FBIOGET_FSCREENINFO:
-               err = fb_get_fscreeninfo(fd,cmd, arg);
-               break;
-
-       case FBIOGETCMAP:
-       case FBIOPUTCMAP:
-               err = fb_getput_cmap(fd, cmd, arg);
-               break;
-
-       default:
-               do {
-                       static int count;
-                       if (++count <= 20)
-                               printk("%s: Unknown fb ioctl cmd fd(%d) "
-                                      "cmd(%08x) arg(%08lx)\n",
-                                      __FUNCTION__, fd, cmd, arg);
-               } while(0);
-               err = -ENOSYS;
-               break;
-       };
-
-       return err;
-}
-
 static int hdio_ioctl_trans(unsigned int fd, unsigned int cmd, unsigned long arg)
 {
        mm_segment_t old_fs = get_fs();
@@ -2953,10 +2813,7 @@ HANDLE_IOCTL(BLKGETSIZE, w_long)
 HANDLE_IOCTL(0x1260, broken_blkgetsize)
 HANDLE_IOCTL(BLKFRAGET, w_long)
 HANDLE_IOCTL(BLKSECTGET, w_long)
-HANDLE_IOCTL(FBIOGET_FSCREENINFO, fb_ioctl_trans)
 HANDLE_IOCTL(BLKPG, blkpg_ioctl_trans)
-HANDLE_IOCTL(FBIOGETCMAP, fb_ioctl_trans)
-HANDLE_IOCTL(FBIOPUTCMAP, fb_ioctl_trans)
 HANDLE_IOCTL(HDIO_GET_KEEPSETTINGS, hdio_ioctl_trans)
 HANDLE_IOCTL(HDIO_GET_UNMASKINTR, hdio_ioctl_trans)
 HANDLE_IOCTL(HDIO_GET_DMA, hdio_ioctl_trans)
@@ -3051,6 +2908,16 @@ HANDLE_IOCTL(TIOCSSERIAL, serial_struct_ioctl)
 COMPATIBLE_IOCTL(TIOCGLTC)
 COMPATIBLE_IOCTL(TIOCSLTC)
 #endif
+#ifdef TIOCSTART
+/*
+ * For these two we have defintions in ioctls.h and/or termios.h on
+ * some architectures but no actual implemention.  Some applications
+ * like bash call them if they are defined in the headers, so we provide
+ * entries here to avoid syslog message spew.
+ */
+COMPATIBLE_IOCTL(TIOCSTART)
+COMPATIBLE_IOCTL(TIOCSTOP)
+#endif
 /* Usbdevfs */
 HANDLE_IOCTL(USBDEVFS_CONTROL32, do_usbdevfs_control)
 HANDLE_IOCTL(USBDEVFS_BULK32, do_usbdevfs_bulk)
index cd6c574557dc19a0b405d7fac06bc166db72a830..c466fec5de2005cee77acfc7a2f120afefcd33f8 100644 (file)
--- a/fs/exec.c
+++ b/fs/exec.c
@@ -135,7 +135,7 @@ asmlinkage long sys_uselib(const char __user * library)
        if (!S_ISREG(nd.dentry->d_inode->i_mode))
                goto exit;
 
-       error = permission(nd.dentry->d_inode, MAY_READ | MAY_EXEC, &nd);
+       error = vfs_permission(&nd, MAY_READ | MAY_EXEC);
        if (error)
                goto exit;
 
@@ -495,7 +495,7 @@ struct file *open_exec(const char *name)
                file = ERR_PTR(-EACCES);
                if (!(nd.mnt->mnt_flags & MNT_NOEXEC) &&
                    S_ISREG(inode->i_mode)) {
-                       int err = permission(inode, MAY_EXEC, &nd);
+                       int err = vfs_permission(&nd, MAY_EXEC);
                        if (!err && !(inode->i_mode & 0111))
                                err = -EACCES;
                        file = ERR_PTR(err);
@@ -590,6 +590,7 @@ static inline int de_thread(struct task_struct *tsk)
        struct signal_struct *sig = tsk->signal;
        struct sighand_struct *newsighand, *oldsighand = tsk->sighand;
        spinlock_t *lock = &oldsighand->siglock;
+       struct task_struct *leader = NULL;
        int count;
 
        /*
@@ -665,7 +666,7 @@ static inline int de_thread(struct task_struct *tsk)
         * and to assume its PID:
         */
        if (!thread_group_leader(current)) {
-               struct task_struct *leader = current->group_leader, *parent;
+               struct task_struct *parent;
                struct dentry *proc_dentry1, *proc_dentry2;
                unsigned long exit_state, ptrace;
 
@@ -674,6 +675,7 @@ static inline int de_thread(struct task_struct *tsk)
                 * It should already be zombie at this point, most
                 * of the time.
                 */
+               leader = current->group_leader;
                while (leader->exit_state != EXIT_ZOMBIE)
                        yield();
 
@@ -733,7 +735,6 @@ static inline int de_thread(struct task_struct *tsk)
                proc_pid_flush(proc_dentry2);
 
                BUG_ON(exit_state != EXIT_ZOMBIE);
-               release_task(leader);
         }
 
        /*
@@ -743,8 +744,11 @@ static inline int de_thread(struct task_struct *tsk)
        sig->flags = 0;
 
 no_thread_group:
-       BUG_ON(atomic_read(&sig->count) != 1);
        exit_itimers(sig);
+       if (leader)
+               release_task(leader);
+
+       BUG_ON(atomic_read(&sig->count) != 1);
 
        if (atomic_read(&oldsighand->count) == 1) {
                /*
@@ -892,7 +896,7 @@ int flush_old_exec(struct linux_binprm * bprm)
        flush_thread();
 
        if (bprm->e_uid != current->euid || bprm->e_gid != current->egid || 
-           permission(bprm->file->f_dentry->d_inode,MAY_READ, NULL) ||
+           file_permission(bprm->file, MAY_READ) ||
            (bprm->interp_flags & BINPRM_FLAGS_ENFORCE_NONDUMP)) {
                suid_keys(current);
                current->mm->dumpable = suid_dumpable;
diff --git a/fs/ext2/CHANGES b/fs/ext2/CHANGES
deleted file mode 100644 (file)
index aa5aaf0..0000000
+++ /dev/null
@@ -1,157 +0,0 @@
-Changes from version 0.5a to version 0.5b
-=========================================
-       - Now that we have sysctl(), the immutable flag cannot be changed when
-         the system is running at security level > 0.
-       - Some cleanups in the code.
-       - More consistency checks on directories.
-       - The ext2.diff patch from Tom May <ftom@netcom.com> has been
-         integrated.  This patch replaces expensive "/" and "%" with
-         cheap ">>" and "&" where possible.
-
-Changes from version 0.5 to version 0.5a
-========================================
-       - Zero the partial block following the end of the file when a file
-         is truncated.
-       - Dates updated in the copyright.
-       - More checks when the filesystem is mounted: the count of blocks,
-         fragments, and inodes per group is checked against the block size.
-       - The buffers used by the error routines are now static variables, to
-         avoid using space on the kernel stack, as requested by Linus.
-       - Some cleanups in the error messages (some versions of syslog contain
-         a bug which truncates an error message if it contains '\n').
-       - Check that no data can be written to a file past the 2GB limit.
-       - The famous readdir() bug has been fixed by Stephen Tweedie.
-       - Added a revision level in the superblock.
-       - Full support for O_SYNC flag of the open system call.
-       - New mount options: `resuid=#uid' and `resgid=#gid'.  `resuid' causes
-         ext2fs to consider user #uid like root for the reserved blocks.
-         `resgid' acts the same way with group #gid.  New fields in the
-         superblock contain default values for resuid and resgid and can
-         be modified by tune2fs.
-         Idea comes from Rene Cougnenc <cougnenc@renux.frmug.fr.net>.
-       - New mount options: `bsddf' and `minixdf'.  `bsddf' causes ext2fs
-         to remove the blocks used for FS structures from the total block
-         count in statfs.  With `minixdf', ext2fs mimics Minix behavior
-         in statfs (i.e. it returns the total number of blocks on the
-         partition).  This is intended to make bde happy :-)
-       - New file attributes:
-         - Immutable files cannot be modified.  Data cannot be written to
-           these files.  They cannot be removed, renamed and new links cannot
-           be created.  Even root cannot modify the files.  He has to remove
-           the immutable attribute first.
-         - Append-only files: can only be written in append-mode when writing.
-           They cannot be removed, renamed and new links cannot be created.
-           Note: files may only be added to an append-only directory.
-         - No-dump files: the attribute is not used by the kernel.  My port
-           of dump uses it to avoid backing up files which are not important.
-       - New check in ext2_check_dir_entry: the inode number is checked.
-       - Support for big file systems: the copy of the FS descriptor is now
-         dynamically allocated (previous versions used a fixed size array).
-         This allows to mount 2GB+ FS.
-       - Reorganization of the ext2_inode structure to allow other operating
-         systems to create specific fields if they use ext2fs as their native
-         file system.  Currently, ext2fs is only implemented in Linux but
-         will soon be part of Gnu Hurd and of Masix.
-
-Changes from version 0.4b to version 0.5
-========================================
-       - New superblock fields: s_lastcheck and s_checkinterval added
-         by Uwe Ohse <uwe@tirka.gun.de> to implement timedependent checks
-         of the file system
-       - Real random numbers for secure rm added by Pierre del Perugia
-         <delperug@gla.ecoledoc.ibp.fr>
-       - The mount warnings related to the state of a fs are not printed
-         if the fs is mounted read-only, idea by Nick Holloway
-         <alfie@dcs.warwick.ac.uk>
-
-Changes from version 0.4a to version 0.4b
-=========================================
-       - Copyrights changed to include the name of my laboratory.
-       - Clean up of balloc.c and ialloc.c.
-       - More consistency checks.
-       - Block preallocation added by Stephen Tweedie.
-       - Direct reads of directories disallowed.
-       - Readahead implemented in readdir by Stephen Tweedie.
-       - Bugs in block and inodes allocation fixed.
-       - Readahead implemented in ext2_find_entry by Chip Salzenberg.
-       - New mount options:
-         `check=none|normal|strict'
-         `debug'
-         `errors=continue|remount-ro|panic'
-         `grpid', `bsdgroups'
-         `nocheck'
-         `nogrpid', `sysvgroups'
-       - truncate() now tries to deallocate contiguous blocks in a single call
-         to ext2_free_blocks().
-       - lots of cosmetic changes.
-
-Changes from version 0.4 to version 0.4a
-========================================
-        - the `sync' option support is now complete.  Version 0.4 was not
-          supporting it when truncating a file.  I have tested the synchronous
-          writes and they work but they make the system very slow :-(  I have
-          to work again on this to make it faster.
-        - when detecting an error on a mounted filesystem, version 0.4 used
-          to try to write a flag in the super block even if the filesystem had
-          been mounted read-only.  This is fixed.
-        - the `sb=#' option now causes the kernel code to use the filesystem
-          descriptors located at block #+1.  Version 0.4 used the superblock
-          backup located at block # but used the main copy of the descriptors.
-        - a new file attribute `S' is supported.  This attribute causes
-          synchronous writes but is applied to a file not to the entire file
-          system (thanks to Michael Kraehe <kraehe@bakunin.north.de> for
-          suggesting it).
-        - the directory cache is inhibited by default.  The cache management
-          code seems to be buggy and I have to look at it carefully before
-          using it again.
-        - deleting a file with the `s' attribute (secure deletion) causes its
-          blocks to be overwritten with random values not with zeros (thanks to
-          Michael A. Griffith <grif@cs.ucr.edu> for suggesting it).
-        - lots of cosmetic changes have been made.
-
-Changes from version 0.3 to version 0.4
-=======================================
-        - Three new mount options are supported: `check', `sync' and `sb=#'.
-          `check' tells the kernel code to make more consistency checks
-          when the file system is mounted.  Currently, the kernel code checks
-          that the blocks and inodes bitmaps are consistent with the free
-          blocks and inodes counts.  More checks will be added in future
-          releases.
-          `sync' tells the kernel code to use synchronous writes when updating
-          an inode, a bitmap, a directory entry or an indirect block.  This
-          can make the file system much slower but can be a big win for files
-          recovery in case of a crash (and we can now say to the BSD folks
-          that Linux also supports synchronous updates :-).
-          `sb=#' tells the kernel code to use an alternate super block instead
-          of its master copy.  `#' is the number of the block (counted in
-          1024 bytes blocks) which contains the alternate super block.
-          An ext2 file system typically contains backups of the super block
-          at blocks 8193, 16385, and so on.
-        - I have change the meaning of the valid flag used by e2fsck.  it
-          now contains the state of the file system.  If the kernel code
-          detects an inconsistency while the file system is mounted, it flags
-          it as erroneous and e2fsck will detect that on next run.
-        - The super block now contains a mount counter.  This counter is
-          incremented each time the file system is mounted read/write.   When
-          this counter becomes bigger than a maximal mount counts (also stored
-          in the super block), e2fsck checks the file system, even if it had
-          been unmounted cleanly, and resets this counter to 0.
-        - File attributes are now supported.  One can associate a set of
-          attributes to a file.  Three attributes are defined:
-          `c': the file is marked for automatic compression,
-          `s': the file is marked for secure deletion: when the file is
-          deleted, its blocks are zeroed and written back to the disk,
-          `u': the file is marked for undeletion: when the file is deleted,
-          its contents are saved to allow a future undeletion.
-          Currently, only the `s' attribute is implemented in the kernel
-          code.  Support for the other attributes will be added in a future
-          release.
-        - a few bugs related to times updates have been fixed by Bruce
-          Evans and me.
-        - a bug related to the links count of deleted inodes has been fixed.
-          Previous versions used to keep the links count set to 1 when a file
-          was deleted.  The new version now sets links_count to 0 when deleting
-          the last link.
-        - a race condition when deallocating an inode has been fixed by
-          Stephen Tweedie.
-
index 6591abef64d01e63769b18481a7319835f448db3..bb6908066494e5dd158894b15232700f062fc8c4 100644 (file)
@@ -624,76 +624,3 @@ unsigned long ext2_bg_num_gdb(struct super_block *sb, int group)
        return EXT2_SB(sb)->s_gdb_count;
 }
 
-#ifdef CONFIG_EXT2_CHECK
-/* Called at mount-time, super-block is locked */
-void ext2_check_blocks_bitmap (struct super_block * sb)
-{
-       struct buffer_head *bitmap_bh = NULL;
-       struct ext2_super_block * es;
-       unsigned long desc_count, bitmap_count, x, j;
-       unsigned long desc_blocks;
-       struct ext2_group_desc * desc;
-       int i;
-
-       es = EXT2_SB(sb)->s_es;
-       desc_count = 0;
-       bitmap_count = 0;
-       desc = NULL;
-       for (i = 0; i < EXT2_SB(sb)->s_groups_count; i++) {
-               desc = ext2_get_group_desc (sb, i, NULL);
-               if (!desc)
-                       continue;
-               desc_count += le16_to_cpu(desc->bg_free_blocks_count);
-               brelse(bitmap_bh);
-               bitmap_bh = read_block_bitmap(sb, i);
-               if (!bitmap_bh)
-                       continue;
-
-               if (ext2_bg_has_super(sb, i) &&
-                               !ext2_test_bit(0, bitmap_bh->b_data))
-                       ext2_error(sb, __FUNCTION__,
-                                  "Superblock in group %d is marked free", i);
-
-               desc_blocks = ext2_bg_num_gdb(sb, i);
-               for (j = 0; j < desc_blocks; j++)
-                       if (!ext2_test_bit(j + 1, bitmap_bh->b_data))
-                               ext2_error(sb, __FUNCTION__,
-                                          "Descriptor block #%ld in group "
-                                          "%d is marked free", j, i);
-
-               if (!block_in_use(le32_to_cpu(desc->bg_block_bitmap),
-                                       sb, bitmap_bh->b_data))
-                       ext2_error(sb, "ext2_check_blocks_bitmap",
-                                   "Block bitmap for group %d is marked free",
-                                   i);
-
-               if (!block_in_use(le32_to_cpu(desc->bg_inode_bitmap),
-                                       sb, bitmap_bh->b_data))
-                       ext2_error(sb, "ext2_check_blocks_bitmap",
-                                   "Inode bitmap for group %d is marked free",
-                                   i);
-
-               for (j = 0; j < EXT2_SB(sb)->s_itb_per_group; j++)
-                       if (!block_in_use(le32_to_cpu(desc->bg_inode_table) + j,
-                                               sb, bitmap_bh->b_data))
-                               ext2_error (sb, "ext2_check_blocks_bitmap",
-                                           "Block #%ld of the inode table in "
-                                           "group %d is marked free", j, i);
-
-               x = ext2_count_free(bitmap_bh, sb->s_blocksize);
-               if (le16_to_cpu(desc->bg_free_blocks_count) != x)
-                       ext2_error (sb, "ext2_check_blocks_bitmap",
-                                   "Wrong free blocks count for group %d, "
-                                   "stored = %d, counted = %lu", i,
-                                   le16_to_cpu(desc->bg_free_blocks_count), x);
-               bitmap_count += x;
-       }
-       if (le32_to_cpu(es->s_free_blocks_count) != bitmap_count)
-               ext2_error (sb, "ext2_check_blocks_bitmap",
-                       "Wrong free blocks count in super block, "
-                       "stored = %lu, counted = %lu",
-                       (unsigned long)le32_to_cpu(es->s_free_blocks_count),
-                       bitmap_count);
-       brelse(bitmap_bh);
-}
-#endif
index e2d6208633a737eea56ea50083c8f1e4c3559695..74714af4ae6979acf4516ff614e77b79155d3a80 100644 (file)
@@ -700,43 +700,3 @@ unsigned long ext2_count_dirs (struct super_block * sb)
        return count;
 }
 
-#ifdef CONFIG_EXT2_CHECK
-/* Called at mount-time, super-block is locked */
-void ext2_check_inodes_bitmap (struct super_block * sb)
-{
-       struct ext2_super_block * es = EXT2_SB(sb)->s_es;
-       unsigned long desc_count = 0, bitmap_count = 0;
-       struct buffer_head *bitmap_bh = NULL;
-       int i;
-
-       for (i = 0; i < EXT2_SB(sb)->s_groups_count; i++) {
-               struct ext2_group_desc *desc;
-               unsigned x;
-
-               desc = ext2_get_group_desc(sb, i, NULL);
-               if (!desc)
-                       continue;
-               desc_count += le16_to_cpu(desc->bg_free_inodes_count);
-               brelse(bitmap_bh);
-               bitmap_bh = read_inode_bitmap(sb, i);
-               if (!bitmap_bh)
-                       continue;
-               
-               x = ext2_count_free(bitmap_bh, EXT2_INODES_PER_GROUP(sb) / 8);
-               if (le16_to_cpu(desc->bg_free_inodes_count) != x)
-                       ext2_error (sb, "ext2_check_inodes_bitmap",
-                                   "Wrong free inodes count in group %d, "
-                                   "stored = %d, counted = %lu", i,
-                                   le16_to_cpu(desc->bg_free_inodes_count), x);
-               bitmap_count += x;
-       }
-       brelse(bitmap_bh);
-       if (percpu_counter_read(&EXT2_SB(sb)->s_freeinodes_counter) !=
-                               bitmap_count)
-               ext2_error(sb, "ext2_check_inodes_bitmap",
-                           "Wrong free inodes count in super block, "
-                           "stored = %lu, counted = %lu",
-                           (unsigned long)le32_to_cpu(es->s_free_inodes_count),
-                           bitmap_count);
-}
-#endif
index 3c0c7c6a5b44004cd02de7dae02343b6674ed672..e4ed4b31a4333d47472936bfcc7b061e298e8496 100644 (file)
@@ -281,7 +281,7 @@ static unsigned long get_sb_block(void **data)
 enum {
        Opt_bsd_df, Opt_minix_df, Opt_grpid, Opt_nogrpid,
        Opt_resgid, Opt_resuid, Opt_sb, Opt_err_cont, Opt_err_panic,
-       Opt_err_ro, Opt_nouid32, Opt_check, Opt_nocheck, Opt_debug,
+       Opt_err_ro, Opt_nouid32, Opt_nocheck, Opt_debug,
        Opt_oldalloc, Opt_orlov, Opt_nobh, Opt_user_xattr, Opt_nouser_xattr,
        Opt_acl, Opt_noacl, Opt_xip, Opt_ignore, Opt_err, Opt_quota,
        Opt_usrquota, Opt_grpquota
@@ -303,7 +303,6 @@ static match_table_t tokens = {
        {Opt_nouid32, "nouid32"},
        {Opt_nocheck, "check=none"},
        {Opt_nocheck, "nocheck"},
-       {Opt_check, "check"},
        {Opt_debug, "debug"},
        {Opt_oldalloc, "oldalloc"},
        {Opt_orlov, "orlov"},
@@ -376,13 +375,6 @@ static int parse_options (char * options,
                case Opt_nouid32:
                        set_opt (sbi->s_mount_opt, NO_UID32);
                        break;
-               case Opt_check:
-#ifdef CONFIG_EXT2_CHECK
-                       set_opt (sbi->s_mount_opt, CHECK);
-#else
-                       printk("EXT2 Check option not supported\n");
-#endif
-                       break;
                case Opt_nocheck:
                        clear_opt (sbi->s_mount_opt, CHECK);
                        break;
@@ -503,12 +495,6 @@ static int ext2_setup_super (struct super_block * sb,
                        EXT2_BLOCKS_PER_GROUP(sb),
                        EXT2_INODES_PER_GROUP(sb),
                        sbi->s_mount_opt);
-#ifdef CONFIG_EXT2_CHECK
-       if (test_opt (sb, CHECK)) {
-               ext2_check_blocks_bitmap (sb);
-               ext2_check_inodes_bitmap (sb);
-       }
-#endif
        return res;
 }
 
index 7992d21e0e09d96c14413a332b4478b5ed117525..ae1148c24c53333fd13e7d18e3cd0fc306886db9 100644 (file)
@@ -1517,76 +1517,3 @@ unsigned long ext3_bg_num_gdb(struct super_block *sb, int group)
        return EXT3_SB(sb)->s_gdb_count;
 }
 
-#ifdef CONFIG_EXT3_CHECK
-/* Called at mount-time, super-block is locked */
-void ext3_check_blocks_bitmap (struct super_block * sb)
-{
-       struct ext3_super_block *es;
-       unsigned long desc_count, bitmap_count, x, j;
-       unsigned long desc_blocks;
-       struct buffer_head *bitmap_bh = NULL;
-       struct ext3_group_desc *gdp;
-       int i;
-
-       es = EXT3_SB(sb)->s_es;
-       desc_count = 0;
-       bitmap_count = 0;
-       gdp = NULL;
-       for (i = 0; i < EXT3_SB(sb)->s_groups_count; i++) {
-               gdp = ext3_get_group_desc (sb, i, NULL);
-               if (!gdp)
-                       continue;
-               desc_count += le16_to_cpu(gdp->bg_free_blocks_count);
-               brelse(bitmap_bh);
-               bitmap_bh = read_block_bitmap(sb, i);
-               if (bitmap_bh == NULL)
-                       continue;
-
-               if (ext3_bg_has_super(sb, i) &&
-                               !ext3_test_bit(0, bitmap_bh->b_data))
-                       ext3_error(sb, __FUNCTION__,
-                                  "Superblock in group %d is marked free", i);
-
-               desc_blocks = ext3_bg_num_gdb(sb, i);
-               for (j = 0; j < desc_blocks; j++)
-                       if (!ext3_test_bit(j + 1, bitmap_bh->b_data))
-                               ext3_error(sb, __FUNCTION__,
-                                          "Descriptor block #%ld in group "
-                                          "%d is marked free", j, i);
-
-               if (!block_in_use (le32_to_cpu(gdp->bg_block_bitmap),
-                                               sb, bitmap_bh->b_data))
-                       ext3_error (sb, "ext3_check_blocks_bitmap",
-                                   "Block bitmap for group %d is marked free",
-                                   i);
-
-               if (!block_in_use (le32_to_cpu(gdp->bg_inode_bitmap),
-                                               sb, bitmap_bh->b_data))
-                       ext3_error (sb, "ext3_check_blocks_bitmap",
-                                   "Inode bitmap for group %d is marked free",
-                                   i);
-
-               for (j = 0; j < EXT3_SB(sb)->s_itb_per_group; j++)
-                       if (!block_in_use (le32_to_cpu(gdp->bg_inode_table) + j,
-                                                       sb, bitmap_bh->b_data))
-                               ext3_error (sb, "ext3_check_blocks_bitmap",
-                                           "Block #%d of the inode table in "
-                                           "group %d is marked free", j, i);
-
-               x = ext3_count_free(bitmap_bh, sb->s_blocksize);
-               if (le16_to_cpu(gdp->bg_free_blocks_count) != x)
-                       ext3_error (sb, "ext3_check_blocks_bitmap",
-                                   "Wrong free blocks count for group %d, "
-                                   "stored = %d, counted = %lu", i,
-                                   le16_to_cpu(gdp->bg_free_blocks_count), x);
-               bitmap_count += x;
-       }
-       brelse(bitmap_bh);
-       if (le32_to_cpu(es->s_free_blocks_count) != bitmap_count)
-               ext3_error (sb, "ext3_check_blocks_bitmap",
-                       "Wrong free blocks count in super block, "
-                       "stored = %lu, counted = %lu",
-                       (unsigned long)le32_to_cpu(es->s_free_blocks_count),
-                       bitmap_count);
-}
-#endif
index df3f517c54aca4b9bc3b41e9286cab7166ecd3e6..9e4a243762109a193106024133b1a28ab55c1b18 100644 (file)
@@ -756,44 +756,3 @@ unsigned long ext3_count_dirs (struct super_block * sb)
        return count;
 }
 
-#ifdef CONFIG_EXT3_CHECK
-/* Called at mount-time, super-block is locked */
-void ext3_check_inodes_bitmap (struct super_block * sb)
-{
-       struct ext3_super_block * es;
-       unsigned long desc_count, bitmap_count, x;
-       struct buffer_head *bitmap_bh = NULL;
-       struct ext3_group_desc * gdp;
-       int i;
-
-       es = EXT3_SB(sb)->s_es;
-       desc_count = 0;
-       bitmap_count = 0;
-       gdp = NULL;
-       for (i = 0; i < EXT3_SB(sb)->s_groups_count; i++) {
-               gdp = ext3_get_group_desc (sb, i, NULL);
-               if (!gdp)
-                       continue;
-               desc_count += le16_to_cpu(gdp->bg_free_inodes_count);
-               brelse(bitmap_bh);
-               bitmap_bh = read_inode_bitmap(sb, i);
-               if (!bitmap_bh)
-                       continue;
-
-               x = ext3_count_free(bitmap_bh, EXT3_INODES_PER_GROUP(sb) / 8);
-               if (le16_to_cpu(gdp->bg_free_inodes_count) != x)
-                       ext3_error (sb, "ext3_check_inodes_bitmap",
-                                   "Wrong free inodes count in group %d, "
-                                   "stored = %d, counted = %lu", i,
-                                   le16_to_cpu(gdp->bg_free_inodes_count), x);
-               bitmap_count += x;
-       }
-       brelse(bitmap_bh);
-       if (le32_to_cpu(es->s_free_inodes_count) != bitmap_count)
-               ext3_error (sb, "ext3_check_inodes_bitmap",
-                           "Wrong free inodes count in super block, "
-                           "stored = %lu, counted = %lu",
-                           (unsigned long)le32_to_cpu(es->s_free_inodes_count),
-                           bitmap_count);
-}
-#endif
index f594989ccb7a248c77be35ab072f3574663524d1..4e6730622d90526f67eab59f13852f124166a1c2 100644 (file)
@@ -625,7 +625,7 @@ static struct export_operations ext3_export_ops = {
 enum {
        Opt_bsd_df, Opt_minix_df, Opt_grpid, Opt_nogrpid,
        Opt_resgid, Opt_resuid, Opt_sb, Opt_err_cont, Opt_err_panic, Opt_err_ro,
-       Opt_nouid32, Opt_check, Opt_nocheck, Opt_debug, Opt_oldalloc, Opt_orlov,
+       Opt_nouid32, Opt_nocheck, Opt_debug, Opt_oldalloc, Opt_orlov,
        Opt_user_xattr, Opt_nouser_xattr, Opt_acl, Opt_noacl,
        Opt_reservation, Opt_noreservation, Opt_noload, Opt_nobh,
        Opt_commit, Opt_journal_update, Opt_journal_inum,
@@ -652,7 +652,6 @@ static match_table_t tokens = {
        {Opt_nouid32, "nouid32"},
        {Opt_nocheck, "nocheck"},
        {Opt_nocheck, "check=none"},
-       {Opt_check, "check"},
        {Opt_debug, "debug"},
        {Opt_oldalloc, "oldalloc"},
        {Opt_orlov, "orlov"},
@@ -773,14 +772,6 @@ static int parse_options (char * options, struct super_block *sb,
                case Opt_nouid32:
                        set_opt (sbi->s_mount_opt, NO_UID32);
                        break;
-               case Opt_check:
-#ifdef CONFIG_EXT3_CHECK
-                       set_opt (sbi->s_mount_opt, CHECK);
-#else
-                       printk(KERN_ERR
-                              "EXT3 Check option not supported\n");
-#endif
-                       break;
                case Opt_nocheck:
                        clear_opt (sbi->s_mount_opt, CHECK);
                        break;
@@ -1115,12 +1106,6 @@ static int ext3_setup_super(struct super_block *sb, struct ext3_super_block *es,
        } else {
                printk("internal journal\n");
        }
-#ifdef CONFIG_EXT3_CHECK
-       if (test_opt (sb, CHECK)) {
-               ext3_check_blocks_bitmap (sb);
-               ext3_check_inodes_bitmap (sb);
-       }
-#endif
        return res;
 }
 
index e2effe2dc9b2c44a7e2c07a2b6fe9b97bfbd7c2a..a0f9b9fe1307addd7ba1bef750ab1fac49abfea7 100644 (file)
@@ -846,7 +846,7 @@ static match_table_t vfat_tokens = {
        {Opt_err, NULL}
 };
 
-static int parse_options(char *options, int is_vfat, int *debug,
+static int parse_options(char *options, int is_vfat, int silent, int *debug,
                         struct fat_mount_options *opts)
 {
        char *p;
@@ -1008,8 +1008,11 @@ static int parse_options(char *options, int is_vfat, int *debug,
                        break;
                /* unknown option */
                default:
-                       printk(KERN_ERR "FAT: Unrecognized mount option \"%s\" "
-                              "or missing value\n", p);
+                       if (!silent) {
+                               printk(KERN_ERR
+                                      "FAT: Unrecognized mount option \"%s\" "
+                                      "or missing value\n", p);
+                       }
                        return -EINVAL;
                }
        }
@@ -1091,7 +1094,7 @@ int fat_fill_super(struct super_block *sb, void *data, int silent,
        sb->s_export_op = &fat_export_ops;
        sbi->dir_ops = fs_dir_inode_ops;
 
-       error = parse_options(data, isvfat, &debug, &sbi->options);
+       error = parse_options(data, isvfat, silent, &debug, &sbi->options);
        if (error)
                goto out_fail;
 
index aae019aadf8865728c2039deb5b2aba09b4a3517..cc5dcd52e23dc7d1de6a1f6c508b23eeffcd4e66 100644 (file)
@@ -9,7 +9,6 @@
 #ifndef _LINUX_HFS_FS_H
 #define _LINUX_HFS_FS_H
 
-#include <linux/version.h>
 #include <linux/slab.h>
 #include <linux/types.h>
 #include <linux/buffer_head.h>
index 3f680c5675bf5c7e45a9805b6102752e8d0f0b1e..d499393a8ae72a6afcff38d102305c4c9c516522 100644 (file)
@@ -12,7 +12,6 @@
  */
 
 #include <linux/pagemap.h>
-#include <linux/version.h>
 #include <linux/mpage.h>
 
 #include "hfs_fs.h"
index b85abc6e6f83b3c3344ac102521521f7655d5134..930cd9212de84ada01b426f0acaee32a564f6773 100644 (file)
@@ -13,7 +13,6 @@
 #include <linux/pagemap.h>
 #include <linux/fs.h>
 #include <linux/swap.h>
-#include <linux/version.h>
 
 #include "hfsplus_fs.h"
 #include "hfsplus_raw.h"
index 7bda76667a4af0a71a3570bd7dca8e14e2861218..50c8f44b6c665f6e605957346515b9ea6e524af5 100644 (file)
@@ -13,7 +13,6 @@
 #include <linux/sched.h>
 #include <linux/slab.h>
 #include <linux/random.h>
-#include <linux/version.h>
 
 #include "hfsplus_fs.h"
 #include "hfsplus_raw.h"
index e7235ca79a95285a1ddb0cdb79e2cadaa9895705..e3ff56a030117325cecc46982258829390d64671 100644 (file)
@@ -11,7 +11,6 @@
 #include <linux/errno.h>
 #include <linux/fs.h>
 #include <linux/pagemap.h>
-#include <linux/version.h>
 
 #include "hfsplus_fs.h"
 #include "hfsplus_raw.h"
index 2bc0cdd30e5656f3325be27d84b6369f345e6a40..c60e5635498dd8936a2e6f43ba0a8b2557360f28 100644 (file)
@@ -11,7 +11,6 @@
 #define _LINUX_HFSPLUS_FS_H
 
 #include <linux/fs.h>
-#include <linux/version.h>
 #include <linux/buffer_head.h>
 #include "hfsplus_raw.h"
 
index f205773ddfbebc661fce1278306234cfd1538945..fc98583cf0458225348141e35b687a0fb14a5253 100644 (file)
@@ -11,7 +11,6 @@
 #include <linux/mm.h>
 #include <linux/fs.h>
 #include <linux/pagemap.h>
-#include <linux/version.h>
 #include <linux/mpage.h>
 
 #include "hfsplus_fs.h"
index 452fc1fdbd32b9d3342c5e1c4f02e7b56664a718..0ce1c455ae555f2d8f73262be6089063608e9ffd 100644 (file)
@@ -14,7 +14,6 @@
 #include <linux/fs.h>
 #include <linux/sched.h>
 #include <linux/slab.h>
-#include <linux/version.h>
 #include <linux/vfs.h>
 #include <linux/nls.h>
 
index 0c51d6338b0b78bd6ea8b611ffa26c20d2096a8a..95455e839231ee33a186485204ffc91fa193efeb 100644 (file)
@@ -12,7 +12,6 @@
 #include <linux/blkdev.h>
 #include <linux/cdrom.h>
 #include <linux/genhd.h>
-#include <linux/version.h>
 #include <asm/unaligned.h>
 
 #include "hfsplus_fs.h"
index a33fb1d91373f873d559a26e1a8494e363ecc86c..4684eb7d48c6ff15338083b4797558094b61be30 100644 (file)
@@ -8,7 +8,6 @@
 
 #include <linux/stddef.h>
 #include <linux/fs.h>
-#include <linux/version.h>
 #include <linux/module.h>
 #include <linux/init.h>
 #include <linux/slab.h>
index ab144dabd870caf4d50732d3153cd0f193c564ff..7c995ac4081bcbbbf1c1b0cf0eec5c0a3691413a 100644 (file)
@@ -114,11 +114,8 @@ static ssize_t hpfs_file_write(struct file *file, const char __user *buf,
        ssize_t retval;
 
        retval = generic_file_write(file, buf, count, ppos);
-       if (retval > 0) {
-               struct inode *inode = file->f_dentry->d_inode;
-               inode->i_mtime = CURRENT_TIME_SEC;
-               hpfs_i(inode)->i_dirty = 1;
-       }
+       if (retval > 0)
+               hpfs_i(file->f_dentry->d_inode)->i_dirty = 1;
        return retval;
 }
 
index e026c807e6b376fe57deb2dc2050d1d58d7c917a..64983ab55586856ae06a93393d1ea38c907853e9 100644 (file)
@@ -63,7 +63,7 @@ static void huge_pagevec_release(struct pagevec *pvec)
  *
  * Result is in bytes to be compatible with is_hugepage_mem_enough()
  */
-unsigned long
+static unsigned long
 huge_pages_needed(struct address_space *mapping, struct vm_area_struct *vma)
 {
        int i;
index 9fbaebfdf40bef99428d0feaa50d9b69cba234d0..bf7ce1d2412bb43928b908527287668eb59fb90d 100644 (file)
@@ -372,7 +372,7 @@ static int find_inode(const char __user *dirname, struct nameidata *nd)
        if (error)
                return error;
        /* you can only watch an inode if you have read permissions on it */
-       error = permission(nd->dentry->d_inode, MAY_READ, NULL);
+       error = vfs_permission(nd, MAY_READ);
        if (error) 
                path_release(nd);
        return error;
index b3f8a1966c9cafe0113370bb5843a9b91b96758f..6dbbd42d8b95fb933ed7a4f3e0183baff73fe3fb 100644 (file)
@@ -256,6 +256,38 @@ int permission(struct inode *inode, int mask, struct nameidata *nd)
        return security_inode_permission(inode, mask, nd);
 }
 
+/**
+ * vfs_permission  -  check for access rights to a given path
+ * @nd:                lookup result that describes the path
+ * @mask:      right to check for (%MAY_READ, %MAY_WRITE, %MAY_EXEC)
+ *
+ * Used to check for read/write/execute permissions on a path.
+ * We use "fsuid" for this, letting us set arbitrary permissions
+ * for filesystem access without changing the "normal" uids which
+ * are used for other things.
+ */
+int vfs_permission(struct nameidata *nd, int mask)
+{
+       return permission(nd->dentry->d_inode, mask, nd);
+}
+
+/**
+ * file_permission  -  check for additional access rights to a given file
+ * @file:      file to check access rights for
+ * @mask:      right to check for (%MAY_READ, %MAY_WRITE, %MAY_EXEC)
+ *
+ * Used to check for read/write/execute permissions on an already opened
+ * file.
+ *
+ * Note:
+ *     Do not use this function in new code.  All access checks should
+ *     be done using vfs_permission().
+ */
+int file_permission(struct file *file, int mask)
+{
+       return permission(file->f_dentry->d_inode, mask, NULL);
+}
+
 /*
  * get_write_access() gets write permission for a file.
  * put_write_access() releases this write permission.
@@ -765,9 +797,8 @@ static fastcall int __link_path_walk(const char * name, struct nameidata *nd)
 
                nd->flags |= LOOKUP_CONTINUE;
                err = exec_permission_lite(inode, nd);
-               if (err == -EAGAIN) { 
-                       err = permission(inode, MAY_EXEC, nd);
-               }
+               if (err == -EAGAIN)
+                       err = vfs_permission(nd, MAY_EXEC);
                if (err)
                        break;
 
@@ -1109,8 +1140,9 @@ int path_lookup_open(const char *name, unsigned int lookup_flags,
  * @open_flags: open intent flags
  * @create_mode: create intent flags
  */
-int path_lookup_create(const char *name, unsigned int lookup_flags,
-               struct nameidata *nd, int open_flags, int create_mode)
+static int path_lookup_create(const char *name, unsigned int lookup_flags,
+                             struct nameidata *nd, int open_flags,
+                             int create_mode)
 {
        return __path_lookup_intent_open(name, lookup_flags|LOOKUP_CREATE, nd,
                        open_flags, create_mode);
@@ -1173,9 +1205,9 @@ out:
        return dentry;
 }
 
-struct dentry * lookup_hash(struct qstr *name, struct dentry * base)
+struct dentry * lookup_hash(struct nameidata *nd)
 {
-       return __lookup_hash(name, base, NULL);
+       return __lookup_hash(&nd->last, nd->dentry, nd);
 }
 
 /* SMP-safe */
@@ -1199,7 +1231,7 @@ struct dentry * lookup_one_len(const char * name, struct dentry * base, int len)
        }
        this.hash = end_name_hash(hash);
 
-       return lookup_hash(&this, base);
+       return __lookup_hash(&this, base, NULL);
 access:
        return ERR_PTR(-EACCES);
 }
@@ -1407,7 +1439,7 @@ int may_open(struct nameidata *nd, int acc_mode, int flag)
        if (S_ISDIR(inode->i_mode) && (flag & FMODE_WRITE))
                return -EISDIR;
 
-       error = permission(inode, acc_mode, nd);
+       error = vfs_permission(nd, acc_mode);
        if (error)
                return error;
 
@@ -1532,7 +1564,7 @@ int open_namei(const char * pathname, int flag, int mode, struct nameidata *nd)
        dir = nd->dentry;
        nd->flags &= ~LOOKUP_PARENT;
        down(&dir->d_inode->i_sem);
-       path.dentry = __lookup_hash(&nd->last, nd->dentry, nd);
+       path.dentry = lookup_hash(nd);
        path.mnt = nd->mnt;
 
 do_last:
@@ -1634,7 +1666,7 @@ do_link:
        }
        dir = nd->dentry;
        down(&dir->d_inode->i_sem);
-       path.dentry = __lookup_hash(&nd->last, nd->dentry, nd);
+       path.dentry = lookup_hash(nd);
        path.mnt = nd->mnt;
        __putname(nd->last.name);
        goto do_last;
@@ -1666,7 +1698,7 @@ struct dentry *lookup_create(struct nameidata *nd, int is_dir)
        /*
         * Do the final lookup.
         */
-       dentry = lookup_hash(&nd->last, nd->dentry);
+       dentry = lookup_hash(nd);
        if (IS_ERR(dentry))
                goto fail;
 
@@ -1901,7 +1933,7 @@ asmlinkage long sys_rmdir(const char __user * pathname)
                        goto exit1;
        }
        down(&nd.dentry->d_inode->i_sem);
-       dentry = lookup_hash(&nd.last, nd.dentry);
+       dentry = lookup_hash(&nd);
        error = PTR_ERR(dentry);
        if (!IS_ERR(dentry)) {
                error = vfs_rmdir(nd.dentry->d_inode, dentry);
@@ -1970,7 +2002,7 @@ asmlinkage long sys_unlink(const char __user * pathname)
        if (nd.last_type != LAST_NORM)
                goto exit1;
        down(&nd.dentry->d_inode->i_sem);
-       dentry = lookup_hash(&nd.last, nd.dentry);
+       dentry = lookup_hash(&nd);
        error = PTR_ERR(dentry);
        if (!IS_ERR(dentry)) {
                /* Why not before? Because we want correct error value */
@@ -2313,7 +2345,7 @@ static inline int do_rename(const char * oldname, const char * newname)
 
        trap = lock_rename(new_dir, old_dir);
 
-       old_dentry = lookup_hash(&oldnd.last, old_dir);
+       old_dentry = lookup_hash(&oldnd);
        error = PTR_ERR(old_dentry);
        if (IS_ERR(old_dentry))
                goto exit3;
@@ -2333,7 +2365,7 @@ static inline int do_rename(const char * oldname, const char * newname)
        error = -EINVAL;
        if (old_dentry == trap)
                goto exit4;
-       new_dentry = lookup_hash(&newnd.last, new_dir);
+       new_dentry = lookup_hash(&newnd);
        error = PTR_ERR(new_dentry);
        if (IS_ERR(new_dentry))
                goto exit4;
@@ -2536,6 +2568,8 @@ EXPORT_SYMBOL(path_lookup);
 EXPORT_SYMBOL(path_release);
 EXPORT_SYMBOL(path_walk);
 EXPORT_SYMBOL(permission);
+EXPORT_SYMBOL(vfs_permission);
+EXPORT_SYMBOL(file_permission);
 EXPORT_SYMBOL(unlock_rename);
 EXPORT_SYMBOL(vfs_create);
 EXPORT_SYMBOL(vfs_follow_link);
index caa9187f67e5e639cba914edb10fabeb66016f7b..2019899f2ab822caec7dd235e8c610096549a93b 100644 (file)
@@ -637,7 +637,7 @@ static int mount_is_safe(struct nameidata *nd)
                if (current->uid != nd->dentry->d_inode->i_uid)
                        return -EPERM;
        }
-       if (permission(nd->dentry->d_inode, MAY_WRITE, nd))
+       if (vfs_permission(nd, MAY_WRITE))
                return -EPERM;
        return 0;
 #endif
index 88df79356a1f333b75f079f6940dc9492709312d..fd3efdca5ae39cc5d923392785ae2c03bbb88c5c 100644 (file)
 #define NCP_PACKET_SIZE_INTERNAL 65536
 
 static int
-ncp_get_fs_info(struct ncp_server* server, struct inode* inode, struct ncp_fs_info __user *arg)
+ncp_get_fs_info(struct ncp_server * server, struct file *file,
+               struct ncp_fs_info __user *arg)
 {
+       struct inode *inode = file->f_dentry->d_inode;
        struct ncp_fs_info info;
 
-       if ((permission(inode, MAY_WRITE, NULL) != 0)
+       if ((file_permission(file, MAY_WRITE) != 0)
            && (current->uid != server->m.mounted_uid)) {
                return -EACCES;
        }
@@ -58,11 +60,13 @@ ncp_get_fs_info(struct ncp_server* server, struct inode* inode, struct ncp_fs_in
 }
 
 static int
-ncp_get_fs_info_v2(struct ncp_server* server, struct inode* inode, struct ncp_fs_info_v2 __user * arg)
+ncp_get_fs_info_v2(struct ncp_server * server, struct file *file,
+                  struct ncp_fs_info_v2 __user * arg)
 {
+       struct inode *inode = file->f_dentry->d_inode;
        struct ncp_fs_info_v2 info2;
 
-       if ((permission(inode, MAY_WRITE, NULL) != 0)
+       if ((file_permission(file, MAY_WRITE) != 0)
            && (current->uid != server->m.mounted_uid)) {
                return -EACCES;
        }
@@ -190,7 +194,7 @@ int ncp_ioctl(struct inode *inode, struct file *filp,
        switch (cmd) {
        case NCP_IOC_NCPREQUEST:
 
-               if ((permission(inode, MAY_WRITE, NULL) != 0)
+               if ((file_permission(filp, MAY_WRITE) != 0)
                    && (current->uid != server->m.mounted_uid)) {
                        return -EACCES;
                }
@@ -245,16 +249,16 @@ int ncp_ioctl(struct inode *inode, struct file *filp,
                return ncp_conn_logged_in(inode->i_sb);
 
        case NCP_IOC_GET_FS_INFO:
-               return ncp_get_fs_info(server, inode, argp);
+               return ncp_get_fs_info(server, filp, argp);
 
        case NCP_IOC_GET_FS_INFO_V2:
-               return ncp_get_fs_info_v2(server, inode, argp);
+               return ncp_get_fs_info_v2(server, filp, argp);
 
        case NCP_IOC_GETMOUNTUID2:
                {
                        unsigned long tmp = server->m.mounted_uid;
 
-                       if (   (permission(inode, MAY_READ, NULL) != 0)
+                       if ((file_permission(filp, MAY_READ) != 0)
                            && (current->uid != server->m.mounted_uid))
                        {
                                return -EACCES;
@@ -268,7 +272,7 @@ int ncp_ioctl(struct inode *inode, struct file *filp,
                {
                        struct ncp_setroot_ioctl sr;
 
-                       if (   (permission(inode, MAY_READ, NULL) != 0)
+                       if ((file_permission(filp, MAY_READ) != 0)
                            && (current->uid != server->m.mounted_uid))
                        {
                                return -EACCES;
@@ -343,7 +347,7 @@ int ncp_ioctl(struct inode *inode, struct file *filp,
 
 #ifdef CONFIG_NCPFS_PACKET_SIGNING     
        case NCP_IOC_SIGN_INIT:
-               if ((permission(inode, MAY_WRITE, NULL) != 0)
+               if ((file_permission(filp, MAY_WRITE) != 0)
                    && (current->uid != server->m.mounted_uid))
                {
                        return -EACCES;
@@ -366,7 +370,7 @@ int ncp_ioctl(struct inode *inode, struct file *filp,
                return 0;               
                
         case NCP_IOC_SIGN_WANTED:
-               if (   (permission(inode, MAY_READ, NULL) != 0)
+               if ((file_permission(filp, MAY_READ) != 0)
                    && (current->uid != server->m.mounted_uid))
                {
                        return -EACCES;
@@ -379,7 +383,7 @@ int ncp_ioctl(struct inode *inode, struct file *filp,
                {
                        int newstate;
 
-                       if (   (permission(inode, MAY_WRITE, NULL) != 0)
+                       if ((file_permission(filp, MAY_WRITE) != 0)
                            && (current->uid != server->m.mounted_uid))
                        {
                                return -EACCES;
@@ -400,7 +404,7 @@ int ncp_ioctl(struct inode *inode, struct file *filp,
 
 #ifdef CONFIG_NCPFS_IOCTL_LOCKING
        case NCP_IOC_LOCKUNLOCK:
-               if (   (permission(inode, MAY_WRITE, NULL) != 0)
+               if ((file_permission(filp, MAY_WRITE) != 0)
                    && (current->uid != server->m.mounted_uid))
                {
                        return -EACCES;
@@ -605,7 +609,7 @@ outrel:
 #endif /* CONFIG_NCPFS_NLS */
 
        case NCP_IOC_SETDENTRYTTL:
-               if ((permission(inode, MAY_WRITE, NULL) != 0) &&
+               if ((file_permission(filp, MAY_WRITE) != 0) &&
                                 (current->uid != server->m.mounted_uid))
                        return -EACCES;
                {
@@ -635,7 +639,7 @@ outrel:
            so we have this out of switch */
        if (cmd == NCP_IOC_GETMOUNTUID) {
                __kernel_uid_t uid = 0;
-               if ((permission(inode, MAY_READ, NULL) != 0)
+               if ((file_permission(filp, MAY_READ) != 0)
                    && (current->uid != server->m.mounted_uid)) {
                        return -EACCES;
                }
index 6e8136751e9a49e1c89f47eb1957ed9f635281a7..f53a5b9ffb7dce308f6e0e05d4982d343261564c 100644 (file)
--- a/fs/open.c
+++ b/fs/open.c
@@ -240,7 +240,7 @@ static inline long do_sys_truncate(const char __user * path, loff_t length)
        if (!S_ISREG(inode->i_mode))
                goto dput_and_out;
 
-       error = permission(inode,MAY_WRITE,&nd);
+       error = vfs_permission(&nd, MAY_WRITE);
        if (error)
                goto dput_and_out;
 
@@ -394,7 +394,7 @@ asmlinkage long sys_utime(char __user * filename, struct utimbuf __user * times)
                         goto dput_and_out;
 
                if (current->fsuid != inode->i_uid &&
-                   (error = permission(inode,MAY_WRITE,&nd)) != 0)
+                   (error = vfs_permission(&nd, MAY_WRITE)) != 0)
                        goto dput_and_out;
        }
        down(&inode->i_sem);
@@ -447,7 +447,7 @@ long do_utimes(char __user * filename, struct timeval * times)
                         goto dput_and_out;
 
                if (current->fsuid != inode->i_uid &&
-                   (error = permission(inode,MAY_WRITE,&nd)) != 0)
+                   (error = vfs_permission(&nd, MAY_WRITE)) != 0)
                        goto dput_and_out;
        }
        down(&inode->i_sem);
@@ -506,7 +506,7 @@ asmlinkage long sys_access(const char __user * filename, int mode)
 
        res = __user_walk(filename, LOOKUP_FOLLOW|LOOKUP_ACCESS, &nd);
        if (!res) {
-               res = permission(nd.dentry->d_inode, mode, &nd);
+               res = vfs_permission(&nd, mode);
                /* SuS v2 requires we report a read only fs too */
                if(!res && (mode & S_IWOTH) && IS_RDONLY(nd.dentry->d_inode)
                   && !special_file(nd.dentry->d_inode->i_mode))
@@ -530,7 +530,7 @@ asmlinkage long sys_chdir(const char __user * filename)
        if (error)
                goto out;
 
-       error = permission(nd.dentry->d_inode,MAY_EXEC,&nd);
+       error = vfs_permission(&nd, MAY_EXEC);
        if (error)
                goto dput_and_out;
 
@@ -563,7 +563,7 @@ asmlinkage long sys_fchdir(unsigned int fd)
        if (!S_ISDIR(inode->i_mode))
                goto out_putf;
 
-       error = permission(inode, MAY_EXEC, NULL);
+       error = file_permission(file, MAY_EXEC);
        if (!error)
                set_fs_pwd(current->fs, mnt, dentry);
 out_putf:
@@ -581,7 +581,7 @@ asmlinkage long sys_chroot(const char __user * filename)
        if (error)
                goto out;
 
-       error = permission(nd.dentry->d_inode,MAY_EXEC,&nd);
+       error = vfs_permission(&nd, MAY_EXEC);
        if (error)
                goto dput_and_out;
 
index 6fd57f1541972cfb182e325d39df30c02850690a..fb117b74809eca5169b8805a1c83437cd5033105 100644 (file)
@@ -48,6 +48,39 @@ static int property_read_proc(char *page, char **start, off_t off,
  * and "@10" to it.
  */
 
+/*
+ * Add a property to a node
+ */
+static struct proc_dir_entry *
+__proc_device_tree_add_prop(struct proc_dir_entry *de, struct property *pp)
+{
+       struct proc_dir_entry *ent;
+
+       /*
+        * Unfortunately proc_register puts each new entry
+        * at the beginning of the list.  So we rearrange them.
+        */
+       ent = create_proc_read_entry(pp->name,
+                                    strncmp(pp->name, "security-", 9)
+                                    ? S_IRUGO : S_IRUSR, de,
+                                    property_read_proc, pp);
+       if (ent == NULL)
+               return NULL;
+
+       if (!strncmp(pp->name, "security-", 9))
+               ent->size = 0; /* don't leak number of password chars */
+       else
+               ent->size = pp->length;
+
+       return ent;
+}
+
+
+void proc_device_tree_add_prop(struct proc_dir_entry *pde, struct property *prop)
+{
+       __proc_device_tree_add_prop(pde, prop);
+}
+
 /*
  * Process a node, adding entries for its children and its properties.
  */
@@ -57,11 +90,9 @@ void proc_device_tree_add_node(struct device_node *np,
        struct property *pp;
        struct proc_dir_entry *ent;
        struct device_node *child;
-       struct proc_dir_entry *list = NULL, **lastp;
        const char *p;
 
        set_node_proc_entry(np, de);
-       lastp = &list;
        for (child = NULL; (child = of_get_next_child(np, child));) {
                p = strrchr(child->full_name, '/');
                if (!p)
@@ -71,9 +102,6 @@ void proc_device_tree_add_node(struct device_node *np,
                ent = proc_mkdir(p, de);
                if (ent == 0)
                        break;
-               *lastp = ent;
-               ent->next = NULL;
-               lastp = &ent->next;
                proc_device_tree_add_node(child, ent);
        }
        of_node_put(child);
@@ -84,7 +112,7 @@ void proc_device_tree_add_node(struct device_node *np,
                 * properties are quite unimportant for us though, thus we
                 * simply "skip" them here, but we do have to check.
                 */
-               for (ent = list; ent != NULL; ent = ent->next)
+               for (ent = de->subdir; ent != NULL; ent = ent->next)
                        if (!strcmp(ent->name, pp->name))
                                break;
                if (ent != NULL) {
@@ -94,25 +122,10 @@ void proc_device_tree_add_node(struct device_node *np,
                        continue;
                }
 
-               /*
-                * Unfortunately proc_register puts each new entry
-                * at the beginning of the list.  So we rearrange them.
-                */
-               ent = create_proc_read_entry(pp->name,
-                                            strncmp(pp->name, "security-", 9)
-                                            ? S_IRUGO : S_IRUSR, de,
-                                            property_read_proc, pp);
+               ent = __proc_device_tree_add_prop(de, pp);
                if (ent == 0)
                        break;
-               if (!strncmp(pp->name, "security-", 9))
-                    ent->size = 0; /* don't leak number of password chars */
-               else
-                    ent->size = pp->length;
-               ent->next = NULL;
-               *lastp = ent;
-               lastp = &ent->next;
        }
-       de->subdir = list;
 }
 
 /*
index c20babd6216d970bdb1fbf2c879cab4de7341d2f..7892a865b58aeaecb904cf45b25e659c92c46540 100644 (file)
@@ -251,12 +251,12 @@ static int reiserfs_allocate_blocks_for_region(struct reiserfs_transaction_handl
                                                       blocks_to_allocate,
                                                       blocks_to_allocate);
                        if (res != CARRY_ON) {
-                               res = -ENOSPC;
+                               res = res == QUOTA_EXCEEDED ? -EDQUOT : -ENOSPC;
                                pathrelse(&path);
                                goto error_exit;
                        }
                } else {
-                       res = -ENOSPC;
+                       res = res == QUOTA_EXCEEDED ? -EDQUOT : -ENOSPC;
                        pathrelse(&path);
                        goto error_exit;
                }
index bb40d63f328fa12b9da2b6cae5f6921d81797c72..01f520c71dc1287102ef44b3fa2884cdeecd1876 100644 (file)
@@ -186,7 +186,7 @@ int udf_ioctl(struct inode *inode, struct file *filp, unsigned int cmd,
 {
        int result = -EINVAL;
 
-       if ( permission(inode, MAY_READ, NULL) != 0 )
+       if ( file_permission(filp, MAY_READ) != 0 )
        {
                udf_debug("no permission to access inode %lu\n",
                                                inode->i_ino);
index 44fed10af0ddc63bdbe5e4eb20d8ed225c7617a8..d8e21ba0cccc4df561857cf82bb1d2c0c48c27c2 100644 (file)
@@ -72,7 +72,6 @@
 #include <linux/init.h>
 #include <linux/list.h>
 #include <linux/proc_fs.h>
-#include <linux/version.h>
 #include <linux/sort.h>
 
 #include <asm/page.h>
index 99b50d2bda9bd77d3aa4085fc47dcfc577586703..1a48dbb902a7bf214c1114dea3c0dfd5711fda83 100644 (file)
  */
 #ifndef __XFS_H__
 #define __XFS_H__
-
-#include <linux/version.h>
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)
 #include <linux-2.6/xfs_linux.h>
-#else
-#include <linux-2.4/xfs_linux.h>
-#endif
-
 #endif /* __XFS_H__ */
index 5a5c7a63e80b80a356ef0f27a7f134c2646140ed..864bf6955689d5c2089ec4a548cf5db751bb78dc 100644 (file)
@@ -18,6 +18,7 @@
 #ifndef __XFS_DMAPI_H__
 #define __XFS_DMAPI_H__
 
+#include <linux/version.h>
 /*     Values used to define the on-disk version of dm_attrname_t. All
  *     on-disk attribute names start with the 8-byte string "SGI_DMI_".
  *
index d7a4a8354fa9854be8a2bc23203a0336b57b93fa..ddd1578a7ee0a40d2877434176f7718797c9b1a4 100644 (file)
@@ -116,6 +116,8 @@ putstr(const char *ptr)
        }
 }
 
+#define __raw_writel(d,ad) do { *((volatile unsigned int *)(ad)) = (d); } while(0)
+
 /* CONFIG_S3C2410_BOOT_WATCHDOG
  *
  * Simple boot-time watchdog setup, to reboot the system if there is
@@ -126,8 +128,6 @@ putstr(const char *ptr)
 
 #define WDOG_COUNT (0xff00)
 
-#define __raw_writel(d,ad) do { *((volatile unsigned int *)(ad)) = (d); } while(0)
-
 static inline void arch_decomp_wdog(void)
 {
        __raw_writel(WDOG_COUNT, S3C2410_WTCNT);
@@ -145,6 +145,24 @@ static void arch_decomp_wdog_start(void)
 #define arch_decomp_wdog()
 #endif
 
+#ifdef CONFIG_S3C2410_BOOT_ERROR_RESET
+
+static void arch_decomp_error(const char *x)
+{
+       putstr("\n\n");
+       putstr(x);
+       putstr("\n\n -- System resetting\n");
+
+       __raw_writel(0x4000, S3C2410_WTDAT);
+       __raw_writel(0x4000, S3C2410_WTCNT);
+       __raw_writel(S3C2410_WTCON_ENABLE | S3C2410_WTCON_DIV128 | S3C2410_WTCON_RSTEN | S3C2410_WTCON_PRESCALE(0x40), S3C2410_WTCON);
+
+       while(1);
+}
+
+#define arch_error arch_decomp_error
+#endif
+
 static void error(char *err);
 
 static void
index e5ccb6b8ff83c60700f57db2279de77fac382454..1cbb173bf5b108b2d136a78961ed7ffc873dc276 100644 (file)
@@ -8,6 +8,7 @@
 
 typedef struct {
        unsigned int __softirq_pending;
+       unsigned int local_timer_irqs;
 } ____cacheline_aligned irq_cpustat_t;
 
 #include <linux/irq_cpustat.h> /* Standard mappings for irq_cpustat_t above */
index a8f1013930e363140381c9f9385b63885b0dd774..d37bf7443264c347141ae9550dfbda9d59dedd85 100644 (file)
@@ -52,8 +52,14 @@ struct scoop_pcmcia_dev {
        unsigned char keep_rd;
 };
 
-extern int scoop_num;
-extern struct scoop_pcmcia_dev *scoop_devs;
+struct scoop_pcmcia_config {
+       struct scoop_pcmcia_dev *devs;
+       int num_devs;
+       void (*pcmcia_init)(void);
+       void (*power_ctrl)(struct device *scoop, unsigned short cpr, int nr);
+};
+
+extern struct scoop_pcmcia_config *platform_scoop_config;
 
 void reset_scoop(struct device *dev);
 unsigned short set_scoop_gpio(struct device *dev, unsigned short bit);
index 551cd3c3093cd8bde19f3a435e46ca4a86d446a4..5a72e50ca9fc0ab5f1640d5ba975ee155851e14e 100644 (file)
@@ -36,6 +36,11 @@ struct seq_file;
  */
 extern void show_ipi_list(struct seq_file *p);
 
+/*
+ * Called from assembly code, this handles an IPI.
+ */
+asmlinkage void do_IPI(struct pt_regs *regs);
+
 /*
  * Move global data into per-processor storage.
  */
@@ -46,12 +51,23 @@ extern void smp_store_cpu_info(unsigned int cpuid);
  */
 extern void smp_cross_call(cpumask_t callmap);
 
+/*
+ * Broadcast a timer interrupt to the other CPUs.
+ */
+extern void smp_send_timer(void);
+
 /*
  * Boot a secondary CPU, and assign it the specified idle task.
  * This also gives us the initial stack to use for this CPU.
  */
 extern int boot_secondary(unsigned int cpu, struct task_struct *);
 
+/*
+ * Called from platform specific assembly code, this is the
+ * secondary CPU entry point.
+ */
+asmlinkage void secondary_start_kernel(void);
+
 /*
  * Perform platform specific initialisation of the specified CPU.
  */
@@ -76,4 +92,42 @@ extern void platform_cpu_die(unsigned int cpu);
 extern int platform_cpu_kill(unsigned int cpu);
 extern void platform_cpu_enable(unsigned int cpu);
 
+#ifdef CONFIG_LOCAL_TIMERS
+/*
+ * Setup a local timer interrupt for a CPU.
+ */
+extern void local_timer_setup(unsigned int cpu);
+
+/*
+ * Stop a local timer interrupt.
+ */
+extern void local_timer_stop(unsigned int cpu);
+
+/*
+ * Platform provides this to acknowledge a local timer IRQ
+ */
+extern int local_timer_ack(void);
+
+#else
+
+static inline void local_timer_setup(unsigned int cpu)
+{
+}
+
+static inline void local_timer_stop(unsigned int cpu)
+{
+}
+
+#endif
+
+/*
+ * show local interrupt info
+ */
+extern void show_local_irqs(struct seq_file *);
+
+/*
+ * Called from assembly, this is the local timer IRQ handler
+ */
+asmlinkage void do_local_timer(struct pt_regs *);
+
 #endif /* ifndef __ASM_ARM_SMP_H */
similarity index 83%
rename from include/asm-ppc/ide.h
rename to include/asm-powerpc/ide.h
index 7d6e6599fac4172e2459161268111ce3951d0605..da5f640480cf3eb89a064e42bcba728c6ec6e856 100644 (file)
@@ -1,24 +1,27 @@
 /*
- *  linux/include/asm-ppc/ide.h
+ *  Copyright (C) 1994-1996 Linus Torvalds & authors
  *
- *  Copyright (C) 1994-1996 Linus Torvalds & authors */
-
-/*
- *  This file contains the ppc architecture specific IDE code.
+ *  This file contains the powerpc architecture specific IDE code.
  */
-
-#ifndef __ASMPPC_IDE_H
-#define __ASMPPC_IDE_H
+#ifndef _ASM_POWERPC_IDE_H
+#define _ASM_POWERPC_IDE_H
 
 #ifdef __KERNEL__
 
+#ifndef __powerpc64__
 #include <linux/sched.h>
 #include <asm/mpc8xx.h>
+#endif
 
 #ifndef MAX_HWIFS
+#ifdef __powerpc64__
+#define MAX_HWIFS      10
+#else
 #define MAX_HWIFS      8
 #endif
+#endif
 
+#ifndef  __powerpc64__
 #include <linux/config.h>
 #include <linux/hdreg.h>
 #include <linux/ioport.h>
@@ -59,9 +62,6 @@ static __inline__ unsigned long ide_default_io_base(int index)
        return 0;
 }
 
-#define IDE_ARCH_OBSOLETE_INIT
-#define ide_default_io_ctl(base)       ((base) + 0x206) /* obsolete */
-
 #ifdef CONFIG_PCI
 #define ide_init_default_irq(base)     (0)
 #else
@@ -73,6 +73,11 @@ static __inline__ unsigned long ide_default_io_base(int index)
 #define ide_ack_intr(hwif) (hwif->hw.ack_intr ? hwif->hw.ack_intr(hwif) : 1)
 #endif
 
+#endif /* __powerpc64__ */
+
+#define IDE_ARCH_OBSOLETE_INIT
+#define ide_default_io_ctl(base)       ((base) + 0x206) /* obsolete */
+
 #endif /* __KERNEL__ */
 
-#endif /* __ASMPPC_IDE_H */
+#endif /* _ASM_POWERPC_IDE_H */
index fa03864d06eb0d69c528ffa4f25e110d102ca44c..5670f0cd61433e69b1bcb05aff5dd7ea3c7e9f9e 100644 (file)
@@ -82,7 +82,6 @@ struct machdep_calls {
        void            (*iommu_dev_setup)(struct pci_dev *dev);
        void            (*iommu_bus_setup)(struct pci_bus *bus);
        void            (*irq_bus_setup)(struct pci_bus *bus);
-       int             (*set_dabr)(unsigned long dabr);
 #endif
 
        int             (*probe)(int platform);
@@ -158,6 +157,9 @@ struct machdep_calls {
           platform, called once per cpu. */
        void            (*enable_pmcs)(void);
 
+       /* Set DABR for this platform, leave empty for default implemenation */
+       int             (*set_dabr)(unsigned long dabr);
+
 #ifdef CONFIG_PPC32    /* XXX for now */
        /* A general init function, called by ppc_init in init/main.c.
           May be NULL. */
index 2f3c3fc2b796ed2f214aad9ad0775d117ebe0c69..5f41f3a2b293cfd304795330f2f758e345dd67fc 100644 (file)
@@ -22,6 +22,7 @@
 #include <asm/ptrace.h>
 
 typedef void (*perf_irq_t)(struct pt_regs *);
+extern perf_irq_t perf_irq;
 
 int reserve_pmc_hardware(perf_irq_t new_perf_irq);
 void release_pmc_hardware(void);
index a88728fba8f68953e81ccef575ea27d67afb8e7d..13aacff755f383ab21c2f7c997fdf10187a21f25 100644 (file)
@@ -34,6 +34,7 @@ void *traverse_pci_devices(struct device_node *start, traverse_func pre,
 
 void pci_devs_phb_init(void);
 void pci_devs_phb_init_dynamic(struct pci_controller *phb);
+void __devinit scan_phb(struct pci_controller *hose);
 
 /* PCI address cache management routines */
 void pci_addr_cache_insert_device(struct pci_dev *dev);
index 7587bf5f38c6eb71aeef5ab518c1563241d622f8..f999df1c5c90bc18c994fe4e83b3b2cb4b1f9e57 100644 (file)
@@ -203,7 +203,7 @@ extern int prom_n_addr_cells(struct device_node* np);
 extern int prom_n_size_cells(struct device_node* np);
 extern int prom_n_intr_cells(struct device_node* np);
 extern void prom_get_irq_senses(unsigned char *senses, int off, int max);
-extern void prom_add_property(struct device_node* np, struct property* prop);
+extern int prom_add_property(struct device_node* np, struct property* prop);
 
 #ifdef CONFIG_PPC32
 /*
index da848412f11b1dd73d4d72ae672d3cb4a18bcba3..489cf4c99c21470c7856856aa6f4a8c3377a4083 100644 (file)
 #define SPRN_VRSAVE    0x100   /* Vector Register Save Register */
 #define SPRN_XER       0x001   /* Fixed Point Exception Register */
 
+#define SPRN_SCOMC     0x114   /* SCOM Access Control */
+#define SPRN_SCOMD     0x115   /* SCOM Access DATA */
+
 /* Performance monitor SPRs */
 #ifdef CONFIG_PPC64
 #define SPRN_MMCR0     795
@@ -594,7 +597,11 @@ static inline void ppc64_runlatch_off(void)
                mtspr(SPRN_CTRLT, ctrl);
        }
 }
-#endif
+
+extern unsigned long scom970_read(unsigned int address);
+extern void scom970_write(unsigned int address, unsigned long value);
+
+#endif /* CONFIG_PPC64 */
 
 #define __get_SP()     ({unsigned long sp; \
                        asm volatile("mr %0,1": "=r" (sp)); sp;})
index 8bcdd0faefea83515934bf141bbb524f95158e82..98581e5a827957712599d215aa8ba7077e494187 100644 (file)
@@ -86,7 +86,6 @@ extern void __cpu_die(unsigned int cpu);
 #else
 /* for UP */
 #define smp_setup_cpu_maps()
-#define smp_release_cpus()
 
 #endif /* CONFIG_SMP */
 
@@ -94,6 +93,9 @@ extern void __cpu_die(unsigned int cpu);
 #define get_hard_smp_processor_id(CPU) (paca[(CPU)].hw_cpu_id)
 #define set_hard_smp_processor_id(CPU, VAL) \
        do { (paca[(CPU)].hw_cpu_id = (VAL)); } while (0)
+
+extern void smp_release_cpus(void);
+
 #else
 /* 32-bit */
 #ifndef CONFIG_SMP
index dee8eefe47bc88bc038991527668c170c4e1215c..76c29a9784ddb3ece86c1718f0edf56c1e034470 100644 (file)
 /*
  * Partition info commands
  *
- * I do not know what those are for at this point
+ * These commands are used to retreive the sdb-partition-XX datas from
+ * the SMU. The lenght is always 2. First byte is the subcommand code
+ * and second byte is the partition ID.
+ *
+ * The reply is 6 bytes:
+ *
+ *  - 0..1 : partition address
+ *  - 2    : a byte containing the partition ID
+ *  - 3    : length (maybe other bits are rest of header ?)
+ *
+ * The data must then be obtained with calls to another command:
+ * SMU_CMD_MISC_ee_GET_DATABLOCK_REC (described below).
  */
 #define SMU_CMD_PARTITION_COMMAND              0x3e
+#define   SMU_CMD_PARTITION_LATEST             0x01
+#define   SMU_CMD_PARTITION_BASE               0x02
+#define   SMU_CMD_PARTITION_UPDATE             0x03
 
 
 /*
  * Fan control
  *
- * This is a "mux" for fan control commands, first byte is the
- * "sub" command.
+ * This is a "mux" for fan control commands. The command seem to
+ * act differently based on the number of arguments. With 1 byte
+ * of argument, this seem to be queries for fans status, setpoint,
+ * etc..., while with 0xe arguments, we will set the fans speeds.
+ *
+ * Queries (1 byte arg):
+ * ---------------------
+ *
+ * arg=0x01: read RPM fans status
+ * arg=0x02: read RPM fans setpoint
+ * arg=0x11: read PWM fans status
+ * arg=0x12: read PWM fans setpoint
+ *
+ * the "status" queries return the current speed while the "setpoint" ones
+ * return the programmed/target speed. It _seems_ that the result is a bit
+ * mask in the first byte of active/available fans, followed by 6 words (16
+ * bits) containing the requested speed.
+ *
+ * Setpoint (14 bytes arg):
+ * ------------------------
+ *
+ * first arg byte is 0 for RPM fans and 0x10 for PWM. Second arg byte is the
+ * mask of fans affected by the command. Followed by 6 words containing the
+ * setpoint value for selected fans in the mask (or 0 if mask value is 0)
  */
 #define SMU_CMD_FAN_COMMAND                    0x4a
 
  *  - lenght 8 ("VSLEWxyz") has 3 additional bytes appended, and is
  *    used to set the voltage slewing point. The SMU replies with "DONE"
  * I yet have to figure out their exact meaning of those 3 bytes in
- * both cases.
+ * both cases. They seem to be:
+ *  x = processor mask
+ *  y = op. point index
+ *  z = processor freq. step index
+ * I haven't yet decyphered result codes
  *
  */
 #define SMU_CMD_POWER_COMMAND                  0xaa
 #define   SMU_CMD_POWER_SHUTDOWN               "SHUTDOWN"
 #define   SMU_CMD_POWER_VOLTAGE_SLEW           "VSLEW"
 
+/*
+ * Read ADC sensors
+ *
+ * This command takes one byte of parameter: the sensor ID (or "reg"
+ * value in the device-tree) and returns a 16 bits value
+ */
+#define SMU_CMD_READ_ADC                       0xd8
+
 /* Misc commands
  *
  * This command seem to be a grab bag of various things
  * Misc commands
  *
  * This command seem to be a grab bag of various things
+ *
+ * SMU_CMD_MISC_ee_GET_DATABLOCK_REC is used, among others, to
+ * transfer blocks of data from the SMU. So far, I've decrypted it's
+ * usage to retreive partition data. In order to do that, you have to
+ * break your transfer in "chunks" since that command cannot transfer
+ * more than a chunk at a time. The chunk size used by OF is 0xe bytes,
+ * but it seems that the darwin driver will let you do 0x1e bytes if
+ * your "PMU" version is >= 0x30. You can get the "PMU" version apparently
+ * either in the last 16 bits of property "smu-version-pmu" or as the 16
+ * bytes at offset 1 of "smu-version-info"
+ *
+ * For each chunk, the command takes 7 bytes of arguments:
+ *  byte 0: subcommand code (0x02)
+ *  byte 1: 0x04 (always, I don't know what it means, maybe the address
+ *                space to use or some other nicety. It's hard coded in OF)
+ *  byte 2..5: SMU address of the chunk (big endian 32 bits)
+ *  byte 6: size to transfer (up to max chunk size)
+ *
+ * The data is returned directly
  */
 #define SMU_CMD_MISC_ee_COMMAND                        0xee
 #define   SMU_CMD_MISC_ee_GET_DATABLOCK_REC    0x02
@@ -333,6 +400,128 @@ extern int smu_queue_i2c(struct smu_i2c_cmd *cmd);
 
 #endif /* __KERNEL__ */
 
+
+/*
+ * - SMU "sdb" partitions informations -
+ */
+
+
+/*
+ * Partition header format
+ */
+struct smu_sdbp_header {
+       __u8    id;
+       __u8    len;
+       __u8    version;
+       __u8    flags;
+};
+
+
+ /*
+ * demangle 16 and 32 bits integer in some SMU partitions
+ * (currently, afaik, this concerns only the FVT partition
+ * (0x12)
+ */
+#define SMU_U16_MIX(x) le16_to_cpu(x);
+#define SMU_U32_MIX(x)  ((((x) & 0xff00ff00u) >> 8)|(((x) & 0x00ff00ffu) << 8))
+
+
+/* This is the definition of the SMU sdb-partition-0x12 table (called
+ * CPU F/V/T operating points in Darwin). The definition for all those
+ * SMU tables should be moved to some separate file
+ */
+#define SMU_SDB_FVT_ID                 0x12
+
+struct smu_sdbp_fvt {
+       __u32   sysclk;                 /* Base SysClk frequency in Hz for
+                                        * this operating point. Value need to
+                                        * be unmixed with SMU_U32_MIX()
+                                        */
+       __u8    pad;
+       __u8    maxtemp;                /* Max temp. supported by this
+                                        * operating point
+                                        */
+
+       __u16   volts[3];               /* CPU core voltage for the 3
+                                        * PowerTune modes, a mode with
+                                        * 0V = not supported. Value need
+                                        * to be unmixed with SMU_U16_MIX()
+                                        */
+};
+
+/* This partition contains voltage & current sensor calibration
+ * informations
+ */
+#define SMU_SDB_CPUVCP_ID              0x21
+
+struct smu_sdbp_cpuvcp {
+       __u16   volt_scale;             /* u4.12 fixed point */
+       __s16   volt_offset;            /* s4.12 fixed point */
+       __u16   curr_scale;             /* u4.12 fixed point */
+       __s16   curr_offset;            /* s4.12 fixed point */
+       __s32   power_quads[3];         /* s4.28 fixed point */
+};
+
+/* This partition contains CPU thermal diode calibration
+ */
+#define SMU_SDB_CPUDIODE_ID            0x18
+
+struct smu_sdbp_cpudiode {
+       __u16   m_value;                /* u1.15 fixed point */
+       __s16   b_value;                /* s10.6 fixed point */
+
+};
+
+/* This partition contains Slots power calibration
+ */
+#define SMU_SDB_SLOTSPOW_ID            0x78
+
+struct smu_sdbp_slotspow {
+       __u16   pow_scale;              /* u4.12 fixed point */
+       __s16   pow_offset;             /* s4.12 fixed point */
+};
+
+/* This partition contains machine specific version information about
+ * the sensor/control layout
+ */
+#define SMU_SDB_SENSORTREE_ID          0x25
+
+struct smu_sdbp_sensortree {
+       u8      model_id;
+       u8      unknown[3];
+};
+
+/* This partition contains CPU thermal control PID informations. So far
+ * only single CPU machines have been seen with an SMU, so we assume this
+ * carries only informations for those
+ */
+#define SMU_SDB_CPUPIDDATA_ID          0x17
+
+struct smu_sdbp_cpupiddata {
+       u8      unknown1;
+       u8      target_temp_delta;
+       u8      unknown2;
+       u8      history_len;
+       s16     power_adj;
+       u16     max_power;
+       s32     gp,gr,gd;
+};
+
+
+/* Other partitions without known structures */
+#define SMU_SDB_DEBUG_SWITCHES_ID      0x05
+
+#ifdef __KERNEL__
+/*
+ * This returns the pointer to an SMU "sdb" partition data or NULL
+ * if not found. The data format is described below
+ */
+extern struct smu_sdbp_header *smu_get_sdb_partition(int id,
+                                                    unsigned int *size);
+
+#endif /* __KERNEL__ */
+
+
 /*
  * - Userland interface -
  */
@@ -365,8 +554,10 @@ struct smu_user_cmd_hdr
        __u32           cmdtype;
 #define SMU_CMDTYPE_SMU                        0       /* SMU command */
 #define SMU_CMDTYPE_WANTS_EVENTS       1       /* switch fd to events mode */
+#define SMU_CMDTYPE_GET_PARTITION      2       /* retreive an sdb partition */
 
        __u8            cmd;                    /* SMU command byte */
+       __u8            pad[3];                 /* padding */
        __u32           data_len;               /* Lenght of data following */
 };
 
index 43f7129984c723312c3ca394ccf32fe53d52a4e8..ace2072d4a833fd331ded2e13be7cf7bd1d8a556 100644 (file)
@@ -7,6 +7,7 @@ struct pt_regs;
 extern int xmon(struct pt_regs *excp);
 extern void xmon_printf(const char *fmt, ...);
 extern void xmon_init(int);
+extern void xmon_map_scc(void);
 
 #endif
 #endif
index 36c7640d00f2d88d5ec176070004c702710e4adc..ccaefabe0bf5a5442eebbc41758a06a6935ea3ac 100644 (file)
@@ -17,18 +17,18 @@ extern unsigned long disp_BAT[2];
 extern boot_infos_t disp_bi;
 extern int boot_text_mapped;
 
-void btext_init(boot_infos_t *bi);
-void btext_welcome(void);
-void btext_prepare_BAT(void);
-void btext_setup_display(int width, int height, int depth, int pitch,
-                        unsigned long address);
-void map_boot_text(void);
-void btext_update_display(unsigned long phys, int width, int height,
-                         int depth, int pitch);
+extern void init_boot_display(void);
+extern void btext_welcome(void);
+extern void btext_prepare_BAT(void);
+extern void btext_setup_display(int width, int height, int depth, int pitch,
+                               unsigned long address);
+extern void map_boot_text(void);
+extern void btext_update_display(unsigned long phys, int width, int height,
+                                int depth, int pitch);
 
-void btext_drawchar(char c);
-void btext_drawstring(const char *str);
-void btext_drawhex(unsigned long v);
+extern void btext_drawchar(char c);
+extern void btext_drawstring(const char *str);
+extern void btext_drawhex(unsigned long v);
 
 #endif /* __KERNEL__ */
 #endif /* __PPC_BTEXT_H */
index f7f614dfc648170760cc31da3284b20ffcc717b6..2bfdf9c98459e9ee28d98ccb90c3e638f0bc69be 100644 (file)
@@ -237,9 +237,9 @@ static inline void __raw_writel(__u32 b, volatile void __iomem *addr)
 #define outsl(port, buf, nl)   _outsl_ns((port)+___IO_BASE, (buf), (nl))
 
 /*
- * On powermacs, we will get a machine check exception if we
- * try to read data from a non-existent I/O port.  Because the
- * machine check is an asynchronous exception, it isn't
+ * On powermacs and 8xx we will get a machine check exception 
+ * if we try to read data from a non-existent I/O port. Because
+ * the machine check is an asynchronous exception, it isn't
  * well-defined which instruction SRR0 will point to when the
  * exception occurs.
  * With the sequence below (twi; isync; nop), we have found that
@@ -258,7 +258,7 @@ extern __inline__ unsigned int name(unsigned int port)      \
 {                                                      \
        unsigned int x;                                 \
        __asm__ __volatile__(                           \
-                       op "    %0,0,%1\n"              \
+               "0:"    op "    %0,0,%1\n"              \
                "1:     twi     0,%0,0\n"               \
                "2:     isync\n"                        \
                "3:     nop\n"                          \
@@ -269,6 +269,7 @@ extern __inline__ unsigned int name(unsigned int port)      \
                ".previous\n"                           \
                ".section __ex_table,\"a\"\n"           \
                "       .align  2\n"                    \
+               "       .long   0b,5b\n"                \
                "       .long   1b,5b\n"                \
                "       .long   2b,5b\n"                \
                "       .long   3b,5b\n"                \
@@ -282,11 +283,12 @@ extern __inline__ unsigned int name(unsigned int port)    \
 extern __inline__ void name(unsigned int val, unsigned int port) \
 {                                                      \
        __asm__ __volatile__(                           \
-               op " %0,0,%1\n"                         \
+               "0:" op " %0,0,%1\n"                    \
                "1:     sync\n"                         \
                "2:\n"                                  \
                ".section __ex_table,\"a\"\n"           \
                "       .align  2\n"                    \
+               "       .long   0b,2b\n"                \
                "       .long   1b,2b\n"                \
                ".previous"                             \
                : : "r" (val), "r" (port + ___IO_BASE));        \
index 1d3c927ce62626a81c5f9f6ee98841f8232598d9..b617dac82969085a2217e9ee502e05e04ac9ca11 100644 (file)
@@ -31,7 +31,7 @@ extern void breakpoint(void);
 /* For taking exceptions
  * these are defined in traps.c
  */
-extern void (*debugger)(struct pt_regs *regs);
+extern int (*debugger)(struct pt_regs *regs);
 extern int (*debugger_bpt)(struct pt_regs *regs);
 extern int (*debugger_sstep)(struct pt_regs *regs);
 extern int (*debugger_iabr_match)(struct pt_regs *regs);
index bb1b0576c947e7ef4828d41d396b1abe90053f9b..ce212201db2aeec7c7ea9d161d4f66228c79953d 100644 (file)
@@ -107,6 +107,7 @@ enum ppc_sys_devices {
        MPC83xx_SEC2,
        MPC83xx_USB2_DR,
        MPC83xx_USB2_MPH,
+       MPC83xx_MDIO,
 };
 
 #endif /* CONFIG_83xx */
index 75c0637acdc8ad2e7615be70f3819b71905befb2..3e39827ed56690bace2991437a6082fdddd88f34 100644 (file)
@@ -93,7 +93,7 @@ extern int device_is_compatible(struct device_node *device, const char *);
 extern int machine_is_compatible(const char *compat);
 extern unsigned char *get_property(struct device_node *node, const char *name,
                                   int *lenp);
-extern void prom_add_property(struct device_node* np, struct property* prop);
+extern int prom_add_property(struct device_node* np, struct property* prop);
 extern void prom_get_irq_senses(unsigned char *, int, int);
 extern int prom_n_addr_cells(struct device_node* np);
 extern int prom_n_size_cells(struct device_node* np);
diff --git a/include/asm-ppc64/ide.h b/include/asm-ppc64/ide.h
deleted file mode 100644 (file)
index 0aae1c5..0000000
+++ /dev/null
@@ -1,30 +0,0 @@
-/*
- *  linux/include/asm-ppc/ide.h
- *
- *  Copyright (C) 1994-1996 Linus Torvalds & authors
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version
- * 2 of the License, or (at your option) any later version.
- */
-
-/*
- *  This file contains the ppc64 architecture specific IDE code.
- */
-
-#ifndef __ASMPPC64_IDE_H
-#define __ASMPPC64_IDE_H
-
-#ifdef __KERNEL__
-
-#ifndef MAX_HWIFS
-# define MAX_HWIFS     10
-#endif
-
-#define IDE_ARCH_OBSOLETE_INIT
-#define ide_default_io_ctl(base)       ((base) + 0x206) /* obsolete */
-
-#endif /* __KERNEL__ */
-
-#endif /* __ASMPPC64_IDE_H */
index 342e2d755550a1de3cf7907352e86b54ce53fcad..fafdf885a3cca595091c3520a4bde7b390b5dceb 100644 (file)
@@ -162,6 +162,14 @@ pcibios_fixup_device_resources(struct pci_dev *dev, struct pci_bus *bus);
 
 extern struct pci_controller *init_phb_dynamic(struct device_node *dn);
 
+extern struct pci_dev *of_create_pci_dev(struct device_node *node,
+                                       struct pci_bus *bus, int devfn);
+
+extern void of_scan_pci_bridge(struct device_node *node,
+                               struct pci_dev *dev);
+
+extern void of_scan_bus(struct device_node *node, struct pci_bus *bus);
+
 extern int pci_read_irq_line(struct pci_dev *dev);
 
 extern void pcibios_add_platform_entries(struct pci_dev *dev);
diff --git a/include/asm-ppc64/ppcdebug.h b/include/asm-ppc64/ppcdebug.h
deleted file mode 100644 (file)
index fd7f696..0000000
+++ /dev/null
@@ -1,108 +0,0 @@
-#ifndef __PPCDEBUG_H
-#define __PPCDEBUG_H
-/********************************************************************
- * Author: Adam Litke, IBM Corp
- * (c) 2001
- *
- * This file contains definitions and macros for a runtime debugging
- * system for ppc64 (This should also work on 32 bit with a few    
- * adjustments.                                                   
- *
- * 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.
- *
- ********************************************************************/
-
-#include <linux/config.h>
-#include <linux/types.h>
-#include <asm/udbg.h>
-#include <stdarg.h>
-
-#define PPCDBG_BITVAL(X)     ((1UL)<<((unsigned long)(X)))
-
-/* Defined below are the bit positions of various debug flags in the
- * ppc64_debug_switch variable.
- * -- When adding new values, please enter them into trace names below -- 
- *
- * Values 62 & 63 can be used to stress the hardware page table management
- * code.  They must be set statically, any attempt to change them dynamically
- * would be a very bad idea.
- */
-#define PPCDBG_MMINIT        PPCDBG_BITVAL(0)
-#define PPCDBG_MM            PPCDBG_BITVAL(1)
-#define PPCDBG_SYS32         PPCDBG_BITVAL(2)
-#define PPCDBG_SYS32NI       PPCDBG_BITVAL(3)
-#define PPCDBG_SYS32X       PPCDBG_BITVAL(4)
-#define PPCDBG_SYS32M       PPCDBG_BITVAL(5)
-#define PPCDBG_SYS64         PPCDBG_BITVAL(6)
-#define PPCDBG_SYS64NI       PPCDBG_BITVAL(7)
-#define PPCDBG_SYS64X       PPCDBG_BITVAL(8)
-#define PPCDBG_SIGNAL        PPCDBG_BITVAL(9)
-#define PPCDBG_SIGNALXMON    PPCDBG_BITVAL(10)
-#define PPCDBG_BINFMT32      PPCDBG_BITVAL(11)
-#define PPCDBG_BINFMT64      PPCDBG_BITVAL(12)
-#define PPCDBG_BINFMTXMON    PPCDBG_BITVAL(13)
-#define PPCDBG_BINFMT_32ADDR PPCDBG_BITVAL(14)
-#define PPCDBG_ALIGNFIXUP    PPCDBG_BITVAL(15)
-#define PPCDBG_TCEINIT       PPCDBG_BITVAL(16)
-#define PPCDBG_TCE           PPCDBG_BITVAL(17)
-#define PPCDBG_PHBINIT       PPCDBG_BITVAL(18)
-#define PPCDBG_SMP           PPCDBG_BITVAL(19)
-#define PPCDBG_BOOT          PPCDBG_BITVAL(20)
-#define PPCDBG_BUSWALK       PPCDBG_BITVAL(21)
-#define PPCDBG_PROM         PPCDBG_BITVAL(22)
-#define PPCDBG_RTAS         PPCDBG_BITVAL(23)
-#define PPCDBG_HTABSTRESS    PPCDBG_BITVAL(62)
-#define PPCDBG_HTABSIZE      PPCDBG_BITVAL(63)
-#define PPCDBG_NONE          (0UL)
-#define PPCDBG_ALL           (0xffffffffUL)
-
-/* The default initial value for the debug switch */
-#define PPC_DEBUG_DEFAULT    0 
-/* #define PPC_DEBUG_DEFAULT    PPCDBG_ALL        */
-
-#define PPCDBG_NUM_FLAGS     64
-
-extern u64 ppc64_debug_switch;
-
-#ifdef WANT_PPCDBG_TAB
-/* A table of debug switch names to allow name lookup in xmon 
- * (and whoever else wants it.
- */
-char *trace_names[PPCDBG_NUM_FLAGS] = {
-       /* Known debug names */
-       "mminit",       "mm",
-       "syscall32",    "syscall32_ni", "syscall32x",   "syscall32m",
-       "syscall64",    "syscall64_ni", "syscall64x",
-       "signal",       "signal_xmon",
-       "binfmt32",     "binfmt64",     "binfmt_xmon",  "binfmt_32addr",
-       "alignfixup",   "tceinit",      "tce",          "phb_init",     
-       "smp",          "boot",         "buswalk",      "prom",
-       "rtas"
-};
-#else
-extern char *trace_names[64];
-#endif /* WANT_PPCDBG_TAB */
-
-#ifdef CONFIG_PPCDBG
-/* Macro to conditionally print debug based on debug_switch */
-#define PPCDBG(...) udbg_ppcdbg(__VA_ARGS__)
-
-/* Macro to conditionally call a debug routine based on debug_switch */
-#define PPCDBGCALL(FLAGS,FUNCTION) ifppcdebug(FLAGS) FUNCTION
-
-/* Macros to test for debug states */
-#define ifppcdebug(FLAGS) if (udbg_ifdebug(FLAGS))
-#define ppcdebugset(FLAGS) (udbg_ifdebug(FLAGS))
-#define PPCDBG_BINFMT (test_thread_flag(TIF_32BIT) ? PPCDBG_BINFMT32 : PPCDBG_BINFMT64)
-
-#else
-#define PPCDBG(...) do {;} while (0)
-#define PPCDBGCALL(FLAGS,FUNCTION) do {;} while (0)
-#define ifppcdebug(...) if (0)
-#define ppcdebugset(FLAGS) (0)
-#endif /* CONFIG_PPCDBG */
-
-#endif /*__PPCDEBUG_H */
index bdb47174ff0eacde3a69089905bafa02196d3d5b..76bb0266d67c1d2a6c241fe41d7129f003f00e24 100644 (file)
@@ -213,6 +213,6 @@ extern int prom_n_addr_cells(struct device_node* np);
 extern int prom_n_size_cells(struct device_node* np);
 extern int prom_n_intr_cells(struct device_node* np);
 extern void prom_get_irq_senses(unsigned char *senses, int off, int max);
-extern void prom_add_property(struct device_node* np, struct property* prop);
+extern int prom_add_property(struct device_node* np, struct property* prop);
 
 #endif /* _PPC64_PROM_H */
index 8192fb8541cc424d45d6f7bbfeada93b28ce2574..e3b927991851d357e6efe9d1ce30bda3f6d298ee 100644 (file)
@@ -23,9 +23,6 @@ extern int udbg_read(char *buf, int buflen);
 
 extern void register_early_udbg_console(void);
 extern void udbg_printf(const char *fmt, ...);
-extern void udbg_ppcdbg(unsigned long flags, const char *fmt, ...);
-extern unsigned long udbg_ifdebug(unsigned long flags);
-extern void __init ppcdbg_initialize(void);
 
 extern void udbg_init_uart(void __iomem *comport, unsigned int speed);
 
index 7127030ae162c1253380fe01b114ea3ccf595d47..23450ed4b571907e6c66609fa536c19a9f386b63 100644 (file)
@@ -129,7 +129,7 @@ void debug_set_level(debug_info_t* id, int new_level);
 
 void debug_stop_all(void);
 
-extern inline debug_entry_t* 
+static inline debug_entry_t*
 debug_event(debug_info_t* id, int level, void* data, int length)
 {
        if ((!id) || (level > id->level) || (id->pages_per_area == 0))
@@ -137,7 +137,7 @@ debug_event(debug_info_t* id, int level, void* data, int length)
         return debug_event_common(id,level,data,length);
 }
 
-extern inline debug_entry_t* 
+static inline debug_entry_t*
 debug_int_event(debug_info_t* id, int level, unsigned int tag)
 {
         unsigned int t=tag;
@@ -146,7 +146,7 @@ debug_int_event(debug_info_t* id, int level, unsigned int tag)
         return debug_event_common(id,level,&t,sizeof(unsigned int));
 }
 
-extern inline debug_entry_t *
+static inline debug_entry_t *
 debug_long_event (debug_info_t* id, int level, unsigned long tag)
 {
         unsigned long t=tag;
@@ -155,7 +155,7 @@ debug_long_event (debug_info_t* id, int level, unsigned long tag)
         return debug_event_common(id,level,&t,sizeof(unsigned long));
 }
 
-extern inline debug_entry_t* 
+static inline debug_entry_t*
 debug_text_event(debug_info_t* id, int level, const char* txt)
 {
        if ((!id) || (level > id->level) || (id->pages_per_area == 0))
@@ -168,7 +168,7 @@ debug_sprintf_event(debug_info_t* id,int level,char *string,...)
        __attribute__ ((format(printf, 3, 4)));
 
 
-extern inline debug_entry_t* 
+static inline debug_entry_t*
 debug_exception(debug_info_t* id, int level, void* data, int length)
 {
        if ((!id) || (level > id->level) || (id->pages_per_area == 0))
@@ -176,7 +176,7 @@ debug_exception(debug_info_t* id, int level, void* data, int length)
         return debug_exception_common(id,level,data,length);
 }
 
-extern inline debug_entry_t* 
+static inline debug_entry_t*
 debug_int_exception(debug_info_t* id, int level, unsigned int tag)
 {
         unsigned int t=tag;
@@ -185,7 +185,7 @@ debug_int_exception(debug_info_t* id, int level, unsigned int tag)
         return debug_exception_common(id,level,&t,sizeof(unsigned int));
 }
 
-extern inline debug_entry_t * 
+static inline debug_entry_t *
 debug_long_exception (debug_info_t* id, int level, unsigned long tag)
 {
         unsigned long t=tag;
@@ -194,7 +194,7 @@ debug_long_exception (debug_info_t* id, int level, unsigned long tag)
         return debug_exception_common(id,level,&t,sizeof(unsigned long));
 }
 
-extern inline debug_entry_t* 
+static inline debug_entry_t*
 debug_text_exception(debug_info_t* id, int level, const char* txt)
 {
        if ((!id) || (level > id->level) || (id->pages_per_area == 0))
index 20e81e8858214562ce12c7f8aa418194afdcc24f..4cbc336e4d60ad95a5aa956ccd385e16b702a7e2 100644 (file)
@@ -21,7 +21,7 @@ extern __u8 _ebcasc[];   /* EBCDIC -> ASCII conversion table */
 extern __u8 _ebc_tolower[]; /* EBCDIC -> lowercase */
 extern __u8 _ebc_toupper[]; /* EBCDIC -> uppercase */
 
-extern __inline__ void
+static inline void
 codepage_convert(const __u8 *codepage, volatile __u8 * addr, unsigned long nr)
 {
        if (nr-- <= 0)
index 8188fdc9884f94d04a088785d3ca21c0b1c8ab49..71f55eb2350a3e77838d73684b08fff5d34b7fde 100644 (file)
@@ -24,7 +24,7 @@
  * Change virtual addresses to physical addresses and vv.
  * These are pretty trivial
  */
-extern inline unsigned long virt_to_phys(volatile void * address)
+static inline unsigned long virt_to_phys(volatile void * address)
 {
        unsigned long real_address;
        __asm__ (
@@ -42,7 +42,7 @@ extern inline unsigned long virt_to_phys(volatile void * address)
         return real_address;
 }
 
-extern inline void * phys_to_virt(unsigned long address)
+static inline void * phys_to_virt(unsigned long address)
 {
         return __io_virt(address);
 }
@@ -54,7 +54,7 @@ extern inline void * phys_to_virt(unsigned long address)
 
 extern void * __ioremap(unsigned long offset, unsigned long size, unsigned long flags);
 
-extern inline void * ioremap (unsigned long offset, unsigned long size)
+static inline void * ioremap (unsigned long offset, unsigned long size)
 {
         return __ioremap(offset, size, 0);
 }
@@ -64,7 +64,7 @@ extern inline void * ioremap (unsigned long offset, unsigned long size)
  * it's useful if some control registers are in such an area and write combining
  * or read caching is not desirable:
  */
-extern inline void * ioremap_nocache (unsigned long offset, unsigned long size)
+static inline void * ioremap_nocache (unsigned long offset, unsigned long size)
 {
         return __ioremap(offset, size, 0);
 }
index c6f51c9ce3ffb89daa43903f0a6f00b9a23574d5..db0606c1abd4fbf56c938905790f8785a904c364 100644 (file)
@@ -346,7 +346,7 @@ struct _lowcore
 #define S390_lowcore (*((struct _lowcore *) 0))
 extern struct _lowcore *lowcore_ptr[];
 
-extern __inline__ void set_prefix(__u32 address)
+static inline void set_prefix(__u32 address)
 {
         __asm__ __volatile__ ("spx %0" : : "m" (address) : "memory" );
 }
index 3a3bb3f2dad56834aa7c7355f8ce6a203edcc37a..bcf24a8738740e4b663a9d22e486b82978e9f11b 100644 (file)
@@ -44,7 +44,7 @@ static inline void switch_mm(struct mm_struct *prev, struct mm_struct *next,
 
 #define deactivate_mm(tsk,mm)  do { } while (0)
 
-extern inline void activate_mm(struct mm_struct *prev,
+static inline void activate_mm(struct mm_struct *prev,
                                struct mm_struct *next)
 {
         switch_mm(prev, next, current);
index 9be741bb1496fd831601559936d51708127990da..859b5e969826302baf456044a48272f0cb66bfc0 100644 (file)
@@ -319,7 +319,7 @@ extern char empty_zero_page[PAGE_SIZE];
  * within a page table are directly modified.  Thus, the following
  * hook is made available.
  */
-extern inline void set_pte(pte_t *pteptr, pte_t pteval)
+static inline void set_pte(pte_t *pteptr, pte_t pteval)
 {
        *pteptr = pteval;
 }
@@ -330,63 +330,63 @@ extern inline void set_pte(pte_t *pteptr, pte_t pteval)
  */
 #ifndef __s390x__
 
-extern inline int pgd_present(pgd_t pgd) { return 1; }
-extern inline int pgd_none(pgd_t pgd)    { return 0; }
-extern inline int pgd_bad(pgd_t pgd)     { return 0; }
+static inline int pgd_present(pgd_t pgd) { return 1; }
+static inline int pgd_none(pgd_t pgd)    { return 0; }
+static inline int pgd_bad(pgd_t pgd)     { return 0; }
 
-extern inline int pmd_present(pmd_t pmd) { return pmd_val(pmd) & _SEG_PRESENT; }
-extern inline int pmd_none(pmd_t pmd)    { return pmd_val(pmd) & _PAGE_TABLE_INV; }
-extern inline int pmd_bad(pmd_t pmd)
+static inline int pmd_present(pmd_t pmd) { return pmd_val(pmd) & _SEG_PRESENT; }
+static inline int pmd_none(pmd_t pmd)    { return pmd_val(pmd) & _PAGE_TABLE_INV; }
+static inline int pmd_bad(pmd_t pmd)
 {
        return (pmd_val(pmd) & (~PAGE_MASK & ~_PAGE_TABLE_INV)) != _PAGE_TABLE;
 }
 
 #else /* __s390x__ */
 
-extern inline int pgd_present(pgd_t pgd)
+static inline int pgd_present(pgd_t pgd)
 {
        return (pgd_val(pgd) & ~PAGE_MASK) == _PGD_ENTRY;
 }
 
-extern inline int pgd_none(pgd_t pgd)
+static inline int pgd_none(pgd_t pgd)
 {
        return pgd_val(pgd) & _PGD_ENTRY_INV;
 }
 
-extern inline int pgd_bad(pgd_t pgd)
+static inline int pgd_bad(pgd_t pgd)
 {
        return (pgd_val(pgd) & (~PAGE_MASK & ~_PGD_ENTRY_INV)) != _PGD_ENTRY;
 }
 
-extern inline int pmd_present(pmd_t pmd)
+static inline int pmd_present(pmd_t pmd)
 {
        return (pmd_val(pmd) & ~PAGE_MASK) == _PMD_ENTRY;
 }
 
-extern inline int pmd_none(pmd_t pmd)
+static inline int pmd_none(pmd_t pmd)
 {
        return pmd_val(pmd) & _PMD_ENTRY_INV;
 }
 
-extern inline int pmd_bad(pmd_t pmd)
+static inline int pmd_bad(pmd_t pmd)
 {
        return (pmd_val(pmd) & (~PAGE_MASK & ~_PMD_ENTRY_INV)) != _PMD_ENTRY;
 }
 
 #endif /* __s390x__ */
 
-extern inline int pte_none(pte_t pte)
+static inline int pte_none(pte_t pte)
 {
        return (pte_val(pte) & _PAGE_INVALID_MASK) == _PAGE_INVALID_EMPTY;
 }
 
-extern inline int pte_present(pte_t pte)
+static inline int pte_present(pte_t pte)
 {
        return !(pte_val(pte) & _PAGE_INVALID) ||
                (pte_val(pte) & _PAGE_INVALID_MASK) == _PAGE_INVALID_NONE;
 }
 
-extern inline int pte_file(pte_t pte)
+static inline int pte_file(pte_t pte)
 {
        return (pte_val(pte) & _PAGE_INVALID_MASK) == _PAGE_INVALID_FILE;
 }
@@ -397,12 +397,12 @@ extern inline int pte_file(pte_t pte)
  * query functions pte_write/pte_dirty/pte_young only work if
  * pte_present() is true. Undefined behaviour if not..
  */
-extern inline int pte_write(pte_t pte)
+static inline int pte_write(pte_t pte)
 {
        return (pte_val(pte) & _PAGE_RO) == 0;
 }
 
-extern inline int pte_dirty(pte_t pte)
+static inline int pte_dirty(pte_t pte)
 {
        /* A pte is neither clean nor dirty on s/390. The dirty bit
         * is in the storage key. See page_test_and_clear_dirty for
@@ -411,7 +411,7 @@ extern inline int pte_dirty(pte_t pte)
        return 0;
 }
 
-extern inline int pte_young(pte_t pte)
+static inline int pte_young(pte_t pte)
 {
        /* A pte is neither young nor old on s/390. The young bit
         * is in the storage key. See page_test_and_clear_young for
@@ -420,7 +420,7 @@ extern inline int pte_young(pte_t pte)
        return 0;
 }
 
-extern inline int pte_read(pte_t pte)
+static inline int pte_read(pte_t pte)
 {
        /* All pages are readable since we don't use the fetch
         * protection bit in the storage key.
@@ -434,9 +434,9 @@ extern inline int pte_read(pte_t pte)
 
 #ifndef __s390x__
 
-extern inline void pgd_clear(pgd_t * pgdp)      { }
+static inline void pgd_clear(pgd_t * pgdp)      { }
 
-extern inline void pmd_clear(pmd_t * pmdp)
+static inline void pmd_clear(pmd_t * pmdp)
 {
        pmd_val(pmdp[0]) = _PAGE_TABLE_INV;
        pmd_val(pmdp[1]) = _PAGE_TABLE_INV;
@@ -446,12 +446,12 @@ extern inline void pmd_clear(pmd_t * pmdp)
 
 #else /* __s390x__ */
 
-extern inline void pgd_clear(pgd_t * pgdp)
+static inline void pgd_clear(pgd_t * pgdp)
 {
        pgd_val(*pgdp) = _PGD_ENTRY_INV | _PGD_ENTRY;
 }
 
-extern inline void pmd_clear(pmd_t * pmdp)
+static inline void pmd_clear(pmd_t * pmdp)
 {
        pmd_val(*pmdp) = _PMD_ENTRY_INV | _PMD_ENTRY;
        pmd_val1(*pmdp) = _PMD_ENTRY_INV | _PMD_ENTRY;
@@ -459,7 +459,7 @@ extern inline void pmd_clear(pmd_t * pmdp)
 
 #endif /* __s390x__ */
 
-extern inline void pte_clear(struct mm_struct *mm, unsigned long addr, pte_t *ptep)
+static inline void pte_clear(struct mm_struct *mm, unsigned long addr, pte_t *ptep)
 {
        pte_val(*ptep) = _PAGE_INVALID_EMPTY;
 }
@@ -468,14 +468,14 @@ extern inline void pte_clear(struct mm_struct *mm, unsigned long addr, pte_t *pt
  * The following pte modification functions only work if
  * pte_present() is true. Undefined behaviour if not..
  */
-extern inline pte_t pte_modify(pte_t pte, pgprot_t newprot)
+static inline pte_t pte_modify(pte_t pte, pgprot_t newprot)
 {
        pte_val(pte) &= PAGE_MASK;
        pte_val(pte) |= pgprot_val(newprot);
        return pte;
 }
 
-extern inline pte_t pte_wrprotect(pte_t pte)
+static inline pte_t pte_wrprotect(pte_t pte)
 {
        /* Do not clobber _PAGE_INVALID_NONE pages!  */
        if (!(pte_val(pte) & _PAGE_INVALID))
@@ -483,13 +483,13 @@ extern inline pte_t pte_wrprotect(pte_t pte)
        return pte;
 }
 
-extern inline pte_t pte_mkwrite(pte_t pte) 
+static inline pte_t pte_mkwrite(pte_t pte)
 {
        pte_val(pte) &= ~_PAGE_RO;
        return pte;
 }
 
-extern inline pte_t pte_mkclean(pte_t pte)
+static inline pte_t pte_mkclean(pte_t pte)
 {
        /* The only user of pte_mkclean is the fork() code.
           We must *not* clear the *physical* page dirty bit
@@ -498,7 +498,7 @@ extern inline pte_t pte_mkclean(pte_t pte)
        return pte;
 }
 
-extern inline pte_t pte_mkdirty(pte_t pte)
+static inline pte_t pte_mkdirty(pte_t pte)
 {
        /* We do not explicitly set the dirty bit because the
         * sske instruction is slow. It is faster to let the
@@ -507,7 +507,7 @@ extern inline pte_t pte_mkdirty(pte_t pte)
        return pte;
 }
 
-extern inline pte_t pte_mkold(pte_t pte)
+static inline pte_t pte_mkold(pte_t pte)
 {
        /* S/390 doesn't keep its dirty/referenced bit in the pte.
         * There is no point in clearing the real referenced bit.
@@ -515,7 +515,7 @@ extern inline pte_t pte_mkold(pte_t pte)
        return pte;
 }
 
-extern inline pte_t pte_mkyoung(pte_t pte)
+static inline pte_t pte_mkyoung(pte_t pte)
 {
        /* S/390 doesn't keep its dirty/referenced bit in the pte.
         * There is no point in setting the real referenced bit.
@@ -695,7 +695,7 @@ static inline pte_t mk_pte_phys(unsigned long physpage, pgprot_t pgprot)
 #ifndef __s390x__
 
 /* Find an entry in the second-level page table.. */
-extern inline pmd_t * pmd_offset(pgd_t * dir, unsigned long address)
+static inline pmd_t * pmd_offset(pgd_t * dir, unsigned long address)
 {
         return (pmd_t *) dir;
 }
@@ -758,7 +758,7 @@ extern inline pmd_t * pmd_offset(pgd_t * dir, unsigned long address)
 #else
 #define __SWP_OFFSET_MASK (~0UL >> 11)
 #endif
-extern inline pte_t mk_swap_pte(unsigned long type, unsigned long offset)
+static inline pte_t mk_swap_pte(unsigned long type, unsigned long offset)
 {
        pte_t pte;
        offset &= __SWP_OFFSET_MASK;
index 3979bc3858e2a4be93d6b5b6537ee7b2381c6866..fc56458aff66b8e52470235c6d11923d8ea027a2 100644 (file)
@@ -67,7 +67,7 @@ typedef enum
 /*
  * Signal processor
  */
-extern __inline__ sigp_ccode
+static inline sigp_ccode
 signal_processor(__u16 cpu_addr, sigp_order_code order_code)
 {
        sigp_ccode ccode;
@@ -86,7 +86,7 @@ signal_processor(__u16 cpu_addr, sigp_order_code order_code)
 /*
  * Signal processor with parameter
  */
-extern __inline__ sigp_ccode
+static inline sigp_ccode
 signal_processor_p(__u32 parameter, __u16 cpu_addr,
                   sigp_order_code order_code)
 {
@@ -107,7 +107,7 @@ signal_processor_p(__u32 parameter, __u16 cpu_addr,
 /*
  * Signal processor with parameter and return status
  */
-extern __inline__ sigp_ccode
+static inline sigp_ccode
 signal_processor_ps(__u32 *statusptr, __u32 parameter,
                    __u16 cpu_addr, sigp_order_code order_code)
 {
index dd50e57a928f2a6fa37e29b5cca503075221971c..a2ae7628bbaaf8e0c0d06a9fab16863aac607777 100644 (file)
@@ -52,7 +52,7 @@ extern int smp_call_function_on(void (*func) (void *info), void *info,
 extern int smp_get_cpu(cpumask_t cpu_map);
 extern void smp_put_cpu(int cpu);
 
-extern __inline__ __u16 hard_smp_processor_id(void)
+static inline __u16 hard_smp_processor_id(void)
 {
         __u16 cpu_address;
  
index ecb0d39c0798645db4fcde73c8f815e1b678be6e..2209ad3499a3b4b9dd0be3a32451dd161e0765d5 100644 (file)
 #define ULONG_IOCTL(cmd)  HANDLE_IOCTL((cmd),(ioctl_trans_handler_t)sys_ioctl)
 #endif
 
+
+COMPATIBLE_IOCTL(0x4B50)   /* KDGHWCLK - not in the kernel, but don't complain */
+COMPATIBLE_IOCTL(0x4B51)   /* KDSHWCLK - not in the kernel, but don't complain */
+
 /* Big T */
 COMPATIBLE_IOCTL(TCGETA)
 COMPATIBLE_IOCTL(TCSETA)
@@ -52,13 +56,6 @@ ULONG_IOCTL(TIOCSCTTY)
 COMPATIBLE_IOCTL(TIOCGPTN)
 COMPATIBLE_IOCTL(TIOCSPTLCK)
 COMPATIBLE_IOCTL(TIOCSERGETLSR)
-/* Big F */
-COMPATIBLE_IOCTL(FBIOBLANK)
-COMPATIBLE_IOCTL(FBIOGET_VSCREENINFO)
-COMPATIBLE_IOCTL(FBIOPUT_VSCREENINFO)
-COMPATIBLE_IOCTL(FBIOPAN_DISPLAY)
-COMPATIBLE_IOCTL(FBIOGET_CON2FBMAP)
-COMPATIBLE_IOCTL(FBIOPUT_CON2FBMAP)
 /* Little f */
 COMPATIBLE_IOCTL(FIOCLEX)
 COMPATIBLE_IOCTL(FIONCLEX)
@@ -81,6 +78,8 @@ COMPATIBLE_IOCTL(HDIO_DRIVE_CMD)
 COMPATIBLE_IOCTL(HDIO_DRIVE_TASK)
 COMPATIBLE_IOCTL(HDIO_SET_PIO_MODE)
 COMPATIBLE_IOCTL(HDIO_SET_NICE)
+COMPATIBLE_IOCTL(HDIO_SET_KEEPSETTINGS)
+COMPATIBLE_IOCTL(HDIO_SCAN_HWIF)
 /* 0x02 -- Floppy ioctls */
 COMPATIBLE_IOCTL(FDMSGON)
 COMPATIBLE_IOCTL(FDMSGOFF)
@@ -99,6 +98,7 @@ COMPATIBLE_IOCTL(FDTWADDLE)
 COMPATIBLE_IOCTL(FDFMTTRK)
 COMPATIBLE_IOCTL(FDRAWCMD)
 /* 0x12 */
+COMPATIBLE_IOCTL(BLKRASET)
 COMPATIBLE_IOCTL(BLKROSET)
 COMPATIBLE_IOCTL(BLKROGET)
 COMPATIBLE_IOCTL(BLKRRPART)
@@ -262,6 +262,7 @@ COMPATIBLE_IOCTL(RTC_WKALM_RD)
 /* Little m */
 COMPATIBLE_IOCTL(MTIOCTOP)
 /* Socket level stuff */
+COMPATIBLE_IOCTL(FIOQSIZE)
 COMPATIBLE_IOCTL(FIOSETOWN)
 COMPATIBLE_IOCTL(SIOCSPGRP)
 COMPATIBLE_IOCTL(FIOGETOWN)
index 1f7b2c097503380692ddb48a33e3d00474f3e71c..43c44530ef9dc02297c6a27e8478c80e7cbf5c79 100644 (file)
@@ -42,6 +42,7 @@ struct notifier_block;
 /* Need to know about CPUs going up/down? */
 extern int register_cpu_notifier(struct notifier_block *nb);
 extern void unregister_cpu_notifier(struct notifier_block *nb);
+extern int current_in_cpu_hotplug(void);
 
 int cpu_up(unsigned int cpu);
 
@@ -54,6 +55,10 @@ static inline int register_cpu_notifier(struct notifier_block *nb)
 static inline void unregister_cpu_notifier(struct notifier_block *nb)
 {
 }
+static inline int current_in_cpu_hotplug(void)
+{
+       return 0;
+}
 
 #endif /* CONFIG_SMP */
 extern struct sysdev_class cpu_sysdev_class;
index e7ff98e395f620c5b17625683176bf9d85ab8fdb..04a58f33ec53b5e33d98d046049b3b7d4fe512b3 100644 (file)
@@ -201,6 +201,14 @@ struct fb_bitfield {
 #define FB_VMODE_SMOOTH_XPAN   512     /* smooth xpan possible (internally used) */
 #define FB_VMODE_CONUPDATE     512     /* don't update x/yoffset       */
 
+/*
+ * Display rotation support
+ */
+#define FB_ROTATE_UR      0
+#define FB_ROTATE_CW      1
+#define FB_ROTATE_UD      2
+#define FB_ROTATE_CCW     3
+
 #define PICOS2KHZ(a) (1000000000UL/(a))
 #define KHZ2PICOS(a) (1000000000UL/(a))
 
@@ -489,9 +497,9 @@ struct fb_cursor_user {
 #define FB_EVENT_MODE_DELETE            0x04
 /*      A driver registered itself */
 #define FB_EVENT_FB_REGISTERED          0x05
-/*      get console to framebuffer mapping */
+/*      CONSOLE-SPECIFIC: get console to framebuffer mapping */
 #define FB_EVENT_GET_CONSOLE_MAP        0x06
-/*      set console to framebuffer mapping */
+/*      CONSOLE-SPECIFIC: set console to framebuffer mapping */
 #define FB_EVENT_SET_CONSOLE_MAP        0x07
 /*      A display blank is requested       */
 #define FB_EVENT_BLANK                  0x08
@@ -500,6 +508,12 @@ struct fb_cursor_user {
 /*     The resolution of the passed in fb_info about to change and
         all vc's should be changed         */
 #define FB_EVENT_MODE_CHANGE_ALL       0x0A
+/*      CONSOLE-SPECIFIC: set console rotation */
+#define FB_EVENT_SET_CON_ROTATE         0x0B
+/*      CONSOLE-SPECIFIC: get console rotation */
+#define FB_EVENT_GET_CON_ROTATE         0x0C
+/*      CONSOLE-SPECIFIC: rotate all consoles */
+#define FB_EVENT_SET_CON_ROTATE_ALL     0x0D
 
 struct fb_event {
        struct fb_info *info;
@@ -817,8 +831,8 @@ extern void cfb_imageblit(struct fb_info *info, const struct fb_image *image);
 /* drivers/video/fbmem.c */
 extern int register_framebuffer(struct fb_info *fb_info);
 extern int unregister_framebuffer(struct fb_info *fb_info);
-extern int fb_prepare_logo(struct fb_info *fb_info);
-extern int fb_show_logo(struct fb_info *fb_info);
+extern int fb_prepare_logo(struct fb_info *fb_info, int rotate);
+extern int fb_show_logo(struct fb_info *fb_info, int rotate);
 extern char* fb_get_buffer_offset(struct fb_info *info, struct fb_pixmap *buf, u32 size);
 extern void fb_pad_unaligned_buffer(u8 *dst, u32 d_pitch, u8 *src, u32 idx,
                                u32 height, u32 shift_high, u32 shift_low, u32 mod);
@@ -828,6 +842,7 @@ extern int fb_get_color_depth(struct fb_var_screeninfo *var,
                              struct fb_fix_screeninfo *fix);
 extern int fb_get_options(char *name, char **option);
 extern int fb_new_modelist(struct fb_info *info);
+extern int fb_con_duit(struct fb_info *info, int event, void *data);
 
 extern struct fb_info *registered_fb[FB_MAX];
 extern int num_registered_fb;
index 1b5f502a4b8fdb303f932079ac1f4498113d1374..cc35b6ac778d6778f51a5112bc2569b9c1f563f4 100644 (file)
@@ -874,6 +874,7 @@ static inline void unlock_super(struct super_block * sb)
 /*
  * VFS helper functions..
  */
+extern int vfs_permission(struct nameidata *, int);
 extern int vfs_create(struct inode *, struct dentry *, int, struct nameidata *);
 extern int vfs_mkdir(struct inode *, struct dentry *, int);
 extern int vfs_mknod(struct inode *, struct dentry *, int, dev_t);
@@ -888,6 +889,11 @@ extern int vfs_rename(struct inode *, struct dentry *, struct inode *, struct de
  */
 extern void dentry_unhash(struct dentry *dentry);
 
+/*
+ * VFS file helper functions.
+ */
+extern int file_permission(struct file *, int);
+
 /*
  * File types
  *
index bef23bbf869044bafece0dcdb9a389f5f964cf46..783c476b8674483ff11d415b30d991895667ddeb 100644 (file)
@@ -16,7 +16,6 @@
 #ifndef FS_ENET_PD_H
 #define FS_ENET_PD_H
 
-#include <linux/version.h>
 #include <asm/types.h>
 
 #define FS_ENET_NAME   "fs_enet"
index 1ce4b54caa211d4f89ac87cad60f501a5c4e0fd7..74abaecdb57268e66b155c87803f5424c162b3d5 100644 (file)
  * ---- Driver types -----------------------------------------------------
  *       device id name + number        function description, i2c address(es)
  *
- *  Range 1000-1999 range is defined in sensors/sensors.h 
- *  Range 0x100 - 0x1ff is for V4L2 Common Components 
+ *  Range 1000-1999 range is defined in sensors/sensors.h
+ *  Range 0x100 - 0x1ff is for V4L2 Common Components
  *  Range 0xf000 - 0xffff is reserved for local experimentation, and should
- *        never be used in official drivers 
+ *        never be used in official drivers
  */
 
 #define I2C_DRIVERID_MSP3400    1
 #define I2C_DRIVERID_MAX6900   63      /* MAX6900 real-time clock      */
 #define I2C_DRIVERID_SAA7114H  64      /* video decoder                */
 #define I2C_DRIVERID_DS1374    65      /* DS1374 real time clock       */
-
+#define I2C_DRIVERID_TDA9874   66      /* TV sound decoder             */
+#define I2C_DRIVERID_SAA6752HS 67      /* MPEG2 encoder                */
+#define I2C_DRIVERID_TVEEPROM  68      /* TV EEPROM                    */
+#define I2C_DRIVERID_WM8775    69      /* wm8775 audio processor       */
+#define I2C_DRIVERID_CS53L32A  70      /* cs53l32a audio processor     */
+#define I2C_DRIVERID_CX25840   71      /* cx2584x video encoder        */
+#define I2C_DRIVERID_SAA7127   72      /* saa7124 video encoder        */
+#define I2C_DRIVERID_SAA711X   73      /* saa711x video encoders       */
 
 #define I2C_DRIVERID_EXP0      0xF0    /* experimental use id's        */
 #define I2C_DRIVERID_EXP1      0xF1
 #define I2C_DRIVERID_ARP        902    /* SMBus ARP Client              */
 #define I2C_DRIVERID_ALERT      903    /* SMBus Alert Responder Client  */
 
-/* IDs --   Use DRIVERIDs 1000-1999 for sensors. 
+/* IDs --   Use DRIVERIDs 1000-1999 for sensors.
    These were originally in sensors.h in the lm_sensors package */
 #define I2C_DRIVERID_LM78 1002
 #define I2C_DRIVERID_LM75 1003
 #define I2C_HW_B_NVIDIA                0x01001c /* nvidia framebuffer driver */
 #define I2C_HW_B_SAVAGE                0x01001d /* savage framebuffer driver */
 #define I2C_HW_B_RADEON                0x01001e /* radeon framebuffer driver */
+#define I2C_HW_B_EM28XX                0x01001f /* em28xx video capture cards */
 
 /* --- PCF 8584 based algorithms                                       */
 #define I2C_HW_P_LP            0x020000 /* Parallel port interface */
index 572aff7daa216fd9956407f6bae82bad480ca5da..768372f07caab7928a284acf592174608eb87213 100644 (file)
@@ -21,7 +21,7 @@
  */
 
 /*
- *  ==FILEVERSION 20000724==
+ *  ==FILEVERSION 20050812==
  *
  *  NOTE TO MAINTAINERS:
  *     If you modify this file at all, please set the above date.
@@ -35,6 +35,8 @@
 #ifndef _IF_PPP_H_
 #define _IF_PPP_H_
 
+#include <linux/compiler.h>
+
 /*
  * Packet sizes
  */
@@ -70,7 +72,8 @@
 #define SC_LOG_RAWIN   0x00080000      /* log all chars received */
 #define SC_LOG_FLUSH   0x00100000      /* log all chars flushed */
 #define        SC_SYNC         0x00200000      /* synchronous serial mode */
-#define        SC_MASK         0x0f200fff      /* bits that user can change */
+#define        SC_MUST_COMP    0x00400000      /* no uncompressed packets may be sent or received */
+#define        SC_MASK         0x0f600fff      /* bits that user can change */
 
 /* state bits */
 #define SC_XMIT_BUSY   0x10000000      /* (used by isdn_ppp?) */
index f25fec8ee2cafee5d0e4780f3e8b49c3bb54cf56..6e5461d69fdd818d09c195b6f160d6cbfdc607f7 100644 (file)
@@ -17,8 +17,6 @@
 #ifndef _WANPIPE_SOCK_DRIVER_COMMON_H
 #define _WANPIPE_SOCK_DRIVER_COMMON_H
 
-#include <linux/version.h>
-
 typedef struct {
        struct net_device *slave;
        atomic_t packet_sent;
index 5f4ee646c119812ddefa7ff387821de462430854..1f996621bc9c9cf67a85f71ef665e0eda7615466 100644 (file)
@@ -21,8 +21,6 @@
  *     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  */
 
-#include <linux/version.h>
-
 /*****************************************************************************/
 #ifndef        _ISTALLION_H
 #define        _ISTALLION_H
index 39f1430bd6d5fc2bee1702d96c6d0c11f78e8875..3c9ea4b7adda50b85c52dd335cd56191ac5b541c 100644 (file)
@@ -8,7 +8,6 @@
 #define __MTD_CFI_H__
 
 #include <linux/config.h>
-#include <linux/version.h>
 #include <linux/delay.h>
 #include <linux/types.h>
 #include <linux/interrupt.h>
index e95d0463a3e5a5237007455c02f8bba71367eee4..b6f2fdae65c6c284b9f511d35301af420a049303 100644 (file)
@@ -14,7 +14,6 @@
 #endif
 
 #include <linux/config.h>
-#include <linux/version.h>
 #include <linux/types.h>
 #include <linux/module.h>
 #include <linux/uio.h>
index 1c975d0d9e949b628eb4fa35ef5001c763fb529c..455660eafba943f159313d198702f14cbcaed646 100644 (file)
@@ -74,7 +74,7 @@ extern struct file *nameidata_to_filp(struct nameidata *nd, int flags);
 extern void release_open_intent(struct nameidata *);
 
 extern struct dentry * lookup_one_len(const char *, struct dentry *, int);
-extern struct dentry * lookup_hash(struct qstr *, struct dentry *);
+extern struct dentry * lookup_hash(struct nameidata *);
 
 extern int follow_down(struct vfsmount **, struct dentry **);
 extern int follow_up(struct vfsmount **, struct dentry **);
index d54049eed0c395a9ae762404554ac1c37a65123d..a0e31adf3abe1e6b2b457da037c1ceaf71658df4 100644 (file)
@@ -2,7 +2,6 @@
 #define __LINUX_PHONEDEV_H
 
 #include <linux/types.h>
-#include <linux/version.h>
 
 #ifdef __KERNEL__
 
index 7227e653b3beacdb7e496196e86b08f821671772..e86a7a5cf355ce3135e3351f9bec314fbbb24b24 100644 (file)
@@ -111,6 +111,8 @@ struct compressor {
 
        /* Used in locking compressor modules */
        struct module *owner;
+       /* Extra skb space needed by the compressor algorithm */
+       unsigned int comp_extra;
 };
 
 /*
@@ -190,6 +192,13 @@ struct compressor {
 #define DEFLATE_MAKE_OPT(w)    ((((w) - 8) << 4) + DEFLATE_METHOD_VAL)
 #define DEFLATE_CHK_SEQUENCE   0
 
+/*
+ * Definitions for MPPE.
+ */
+
+#define CI_MPPE                18      /* config option for MPPE */
+#define CILEN_MPPE              6      /* length of config option */
+
 /*
  * Definitions for other, as yet unsupported, compression methods.
  */
index 0563581e3a0289b7c4ff9ce2868609cf2d39dda4..74488e49166d88c40018c91f247e5873ad842510 100644 (file)
@@ -66,6 +66,7 @@ struct proc_dir_entry {
        write_proc_t *write_proc;
        atomic_t count;         /* use count */
        int deleted;            /* delete flag */
+       void *set;
 };
 
 struct kcore_list {
@@ -139,15 +140,12 @@ extern void proc_tty_unregister_driver(struct tty_driver *driver);
 /*
  * proc_devtree.c
  */
+#ifdef CONFIG_PROC_DEVICETREE
 struct device_node;
+struct property;
 extern void proc_device_tree_init(void);
-#ifdef CONFIG_PROC_DEVICETREE
 extern void proc_device_tree_add_node(struct device_node *, struct proc_dir_entry *);
-#else /* !CONFIG_PROC_DEVICETREE */
-static inline void proc_device_tree_add_node(struct device_node *np, struct proc_dir_entry *pde)
-{
-       return;
-}
+extern void proc_device_tree_add_prop(struct proc_dir_entry *pde, struct property *prop);
 #endif /* CONFIG_PROC_DEVICETREE */
 
 extern struct proc_dir_entry *proc_symlink(const char *,
index 9de99198caf10a353a69e8a9fef32ed3c9d8c36d..899437802aeafb75b2c2e4ea8cb80eb593fb5397 100644 (file)
@@ -6,7 +6,13 @@
 #ifndef BITMAP_H
 #define BITMAP_H 1
 
-#define BITMAP_MAJOR 3
+#define BITMAP_MAJOR_LO 3
+/* version 4 insists the bitmap is in little-endian order
+ * with version 3, it is host-endian which is non-portable
+ */
+#define BITMAP_MAJOR_HI 4
+#define        BITMAP_MAJOR_HOSTENDIAN 3
+
 #define BITMAP_MINOR 39
 
 /*
@@ -133,7 +139,8 @@ typedef __u16 bitmap_counter_t;
 /* use these for bitmap->flags and bitmap->sb->state bit-fields */
 enum bitmap_state {
        BITMAP_ACTIVE = 0x001, /* the bitmap is in use */
-       BITMAP_STALE  = 0x002  /* the bitmap file is out of date or had -EIO */
+       BITMAP_STALE  = 0x002,  /* the bitmap file is out of date or had -EIO */
+       BITMAP_HOSTENDIAN = 0x8000,
 };
 
 /* the superblock at the front of the bitmap file -- little endian */
index ffa316ce4dc834aa3ab4a4e8967e95a47c0b5c49..13e7c4b62367f6e75d536e1eb124265694db50db 100644 (file)
  *     and major_version/minor_version accordingly
  * >=2 means that Internal bitmaps are supported by setting MD_SB_BITMAP_PRESENT
  *     in the super status byte
+ * >=3 means that bitmap superblock version 4 is supported, which uses
+ *     little-ending representation rather than host-endian
  */
-#define MD_PATCHLEVEL_VERSION           2
+#define MD_PATCHLEVEL_VERSION           3
 
 extern int register_md_personality (int p_num, mdk_personality_t *p);
 extern int unregister_md_personality (int p_num);
@@ -87,6 +89,7 @@ extern void md_print_devices (void);
 
 extern void md_super_write(mddev_t *mddev, mdk_rdev_t *rdev,
                           sector_t sector, int size, struct page *page);
+extern void md_super_wait(mddev_t *mddev);
 extern int sync_page_io(struct block_device *bdev, sector_t sector, int size,
                        struct page *page, int rw);
 
index ebce949b14432c4e3e157da8c32d74336e9de5e1..46629a275ba9bb06f9d270c187da6a00f8805815 100644 (file)
@@ -105,6 +105,8 @@ struct mdk_rdev_s
        int             sb_size;        /* bytes in the superblock */
        int             preferred_minor;        /* autorun support */
 
+       struct kobject  kobj;
+
        /* A device can be in one of three states based on two flags:
         * Not working:   faulty==1 in_sync==0
         * Fully working: faulty==0 in_sync==1
@@ -115,11 +117,12 @@ struct mdk_rdev_s
         * It can never have faulty==1, in_sync==1
         * This reduces the burden of testing multiple flags in many cases
         */
-       int faulty;                     /* if faulty do not issue IO requests */
-       int in_sync;                    /* device is a full member of the array */
 
-       unsigned long   flags;          /* Should include faulty and in_sync here. */
+       unsigned long   flags;
+#define        Faulty          1               /* device is known to have a fault */
+#define        In_sync         2               /* device is in_sync with rest of array */
 #define        WriteMostly     4               /* Avoid reading if at all possible */
+#define        BarriersNotsupp 5               /* BIO_RW_BARRIER is not supported */
 
        int desc_nr;                    /* descriptor index in the superblock */
        int raid_disk;                  /* role of device in array */
@@ -132,6 +135,9 @@ struct mdk_rdev_s
                                         * only maintained for arrays that
                                         * support hot removal
                                         */
+       atomic_t        read_errors;    /* number of consecutive read errors that
+                                        * we have tried to ignore.
+                                        */
 };
 
 typedef struct mdk_personality_s mdk_personality_t;
@@ -148,6 +154,8 @@ struct mddev_s
 
        struct gendisk                  *gendisk;
 
+       struct kobject                  kobj;
+
        /* Superblock information */
        int                             major_version,
                                        minor_version,
@@ -171,6 +179,10 @@ struct mddev_s
        sector_t                        resync_mark_cnt;/* blocks written at resync_mark */
 
        sector_t                        resync_max_sectors; /* may be set by personality */
+
+       sector_t                        resync_mismatches; /* count of sectors where
+                                                           * parity/replica mismatch found
+                                                           */
        /* recovery/resync flags 
         * NEEDED:   we might need to start a resync/recover
         * RUNNING:  a thread is running, or about to be started
@@ -178,6 +190,8 @@ struct mddev_s
         * ERR:      and IO error was detected - abort the resync/recovery
         * INTR:     someone requested a (clean) early abort.
         * DONE:     thread is done and is waiting to be reaped
+        * REQUEST:  user-space has requested a sync (used with SYNC)
+        * CHECK:    user-space request for for check-only, no repair
         */
 #define        MD_RECOVERY_RUNNING     0
 #define        MD_RECOVERY_SYNC        1
@@ -185,6 +199,8 @@ struct mddev_s
 #define        MD_RECOVERY_INTR        3
 #define        MD_RECOVERY_DONE        4
 #define        MD_RECOVERY_NEEDED      5
+#define        MD_RECOVERY_REQUESTED   6
+#define        MD_RECOVERY_CHECK       7
        unsigned long                   recovery;
 
        int                             in_sync;        /* know to not need resync */
@@ -195,6 +211,13 @@ struct mddev_s
        int                             degraded;       /* whether md should consider
                                                         * adding a spare
                                                         */
+       int                             barriers_work;  /* initialised to true, cleared as soon
+                                                        * as a barrier request to slave
+                                                        * fails.  Only supported
+                                                        */
+       struct bio                      *biolist;       /* bios that need to be retried
+                                                        * because BIO_RW_BARRIER is not supported
+                                                        */
 
        atomic_t                        recovery_active; /* blocks scheduled, but not written */
        wait_queue_head_t               recovery_wait;
@@ -232,7 +255,7 @@ struct mddev_s
 
 static inline void rdev_dec_pending(mdk_rdev_t *rdev, mddev_t *mddev)
 {
-       int faulty = rdev->faulty;
+       int faulty = test_bit(Faulty, &rdev->flags);
        if (atomic_dec_and_test(&rdev->nr_pending) && faulty)
                set_bit(MD_RECOVERY_NEEDED, &mddev->recovery);
 }
@@ -270,6 +293,13 @@ struct mdk_personality_s
 };
 
 
+struct md_sysfs_entry {
+       struct attribute attr;
+       ssize_t (*show)(mddev_t *, char *);
+       ssize_t (*store)(mddev_t *, const char *, size_t);
+};
+
+
 static inline char * mdname (mddev_t * mddev)
 {
        return mddev->gendisk ? mddev->gendisk->disk_name : "mdX";
@@ -304,10 +334,8 @@ typedef struct mdk_thread_s {
        mddev_t                 *mddev;
        wait_queue_head_t       wqueue;
        unsigned long           flags;
-       struct completion       *event;
        struct task_struct      *tsk;
        unsigned long           timeout;
-       const char              *name;
 } mdk_thread_t;
 
 #define THREAD_WAKEUP  0
index 60e19b667548feccf6d8dd5cac96ab0c3420c3a5..292b98f2b408dd375154c9bf24569c5289c0f6ee 100644 (file)
@@ -110,7 +110,9 @@ struct r1bio_s {
 #define        R1BIO_Uptodate  0
 #define        R1BIO_IsSync    1
 #define        R1BIO_Degraded  2
-#define        R1BIO_BehindIO   3
+#define        R1BIO_BehindIO  3
+#define        R1BIO_Barrier   4
+#define R1BIO_BarrierRetry 5
 /* For write-behind requests, we call bi_end_io when
  * the last non-write-behind device completes, providing
  * any write was successful.  Otherwise we call when
index 176fc653c284711d2e6b627c348d9e5c66d2cdf7..f025ba6fb14c10c3492e6dcf23d8703bb741d824 100644 (file)
@@ -154,6 +154,8 @@ struct stripe_head {
 #define        R5_Wantwrite    5
 #define        R5_Syncio       6       /* this io need to be accounted as resync io */
 #define        R5_Overlap      7       /* There is a pending overlapping request on this block */
+#define        R5_ReadError    8       /* seen a read error here recently */
+#define        R5_ReWrite      9       /* have tried to over-write the readerror */
 
 /*
  * Write method
index 03b68a7b4b82ae7c775a375f1fe3aa0b6a9909ec..2bbf968b23d9b62cdc58094f5799db09ecc51ff2 100644 (file)
@@ -909,6 +909,7 @@ do { if (atomic_dec_and_test(&(tsk)->usage)) __put_task_struct(tsk); } while(0)
 #define PF_SYNCWRITE   0x00200000      /* I am doing a sync write */
 #define PF_BORROWED_MM 0x00400000      /* I am a kthread doing use_mm */
 #define PF_RANDOMIZE   0x00800000      /* randomize virtual address space */
+#define PF_HOTPLUG_CPU 0x01000000      /* Currently performing CPU hotplug */
 
 /*
  * Only the _current_ task can read/write to tsk->flags, but other
index e89b77b6505a835aec23e00096225a754891c6d0..13a37f137ea2169dd911551b8ac4d3f4a89c06c6 100644 (file)
@@ -21,8 +21,6 @@
  *     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  */
 
-#include <linux/version.h>
-
 /*****************************************************************************/
 #ifndef        _STALLION_H
 #define        _STALLION_H
index fc8e367f671e11bccc88faccb6247ce0017e5009..fc131d6602b989a289f0bd9ff3f4c4f1aa987c71 100644 (file)
@@ -24,6 +24,7 @@
 #include <linux/compiler.h>
 
 struct file;
+struct completion;
 
 #define CTL_MAXNAME 10         /* how many path components do we allow in a
                                   call to sysctl?   In other words, what is
@@ -925,6 +926,8 @@ struct ctl_table_header
 {
        ctl_table *ctl_table;
        struct list_head ctl_entry;
+       int used;
+       struct completion *unregistering;
 };
 
 struct ctl_table_header * register_sysctl_table(ctl_table * table, 
index 1cc8c31b798878aea1469b989e74e6fda2d65237..91140091ced2f2b510a3ac2bf05d79d738078f0e 100644 (file)
@@ -1,57 +1,16 @@
 #ifndef __LINUX_VIDEODEV_H
 #define __LINUX_VIDEODEV_H
 
-#include <linux/compiler.h>
 #include <linux/types.h>
 
-#define HAVE_V4L2 1
+#define HAVE_V4L1 1
+
 #include <linux/videodev2.h>
 
 #ifdef __KERNEL__
 
-#include <linux/poll.h>
 #include <linux/mm.h>
-#include <linux/device.h>
-
-struct video_device
-{
-       /* device info */
-       struct device *dev;
-       char name[32];
-       int type;       /* v4l1 */
-       int type2;      /* v4l2 */
-       int hardware;
-       int minor;
-
-       /* device ops + callbacks */
-       struct file_operations *fops;
-       void (*release)(struct video_device *vfd);
-
-
-       /* obsolete -- fops->owner is used instead */
-       struct module *owner;
-       /* dev->driver_data will be used instead some day.
-        * Use the video_{get|set}_drvdata() helper functions,
-        * so the switch over will be transparent for you.
-        * Or use {pci|usb}_{get|set}_drvdata() directly. */
-       void *priv;
-
-       /* for videodev.c intenal usage -- please don't touch */
-       int users;                     /* video_exclusive_{open|close} ... */
-       struct semaphore lock;         /* ... helper function uses these   */
-       char devfs_name[64];           /* devfs */
-       struct class_device class_dev; /* sysfs */
-};
-
-#define VIDEO_MAJOR    81
-
-#define VFL_TYPE_GRABBER       0
-#define VFL_TYPE_VBI           1
-#define VFL_TYPE_RADIO         2
-#define VFL_TYPE_VTX           3
 
-extern int video_register_device(struct video_device *, int type, int nr);
-extern void video_unregister_device(struct video_device *);
 extern struct video_device* video_devdata(struct file*);
 
 #define to_video_device(cd) container_of(cd, struct video_device, class_dev)
@@ -68,11 +27,7 @@ video_device_remove_file(struct video_device *vfd,
        class_device_remove_file(&vfd->class_dev, attr);
 }
 
-/* helper functions to alloc / release struct video_device, the
-   later can be used for video_device->release() */
-struct video_device *video_device_alloc(void);
-void video_device_release(struct video_device *vfd);
-
+#if OBSOLETE_OWNER /* to be removed in 2.6.15 */
 /* helper functions to access driver private data. */
 static inline void *video_get_drvdata(struct video_device *dev)
 {
@@ -83,30 +38,12 @@ static inline void video_set_drvdata(struct video_device *dev, void *data)
 {
        dev->priv = data;
 }
+#endif
 
 extern int video_exclusive_open(struct inode *inode, struct file *file);
 extern int video_exclusive_release(struct inode *inode, struct file *file);
-extern int video_usercopy(struct inode *inode, struct file *file,
-                         unsigned int cmd, unsigned long arg,
-                         int (*func)(struct inode *inode, struct file *file,
-                                     unsigned int cmd, void *arg));
 #endif /* __KERNEL__ */
 
-#define VID_TYPE_CAPTURE       1       /* Can capture */
-#define VID_TYPE_TUNER         2       /* Can tune */
-#define VID_TYPE_TELETEXT      4       /* Does teletext */
-#define VID_TYPE_OVERLAY       8       /* Overlay onto frame buffer */
-#define VID_TYPE_CHROMAKEY     16      /* Overlay by chromakey */
-#define VID_TYPE_CLIPPING      32      /* Can clip */
-#define VID_TYPE_FRAMERAM      64      /* Uses the frame buffer memory */
-#define VID_TYPE_SCALES                128     /* Scalable */
-#define VID_TYPE_MONOCHROME    256     /* Monochrome only */
-#define VID_TYPE_SUBCAPTURE    512     /* Can capture subareas of the image */
-#define VID_TYPE_MPEG_DECODER  1024    /* Can decode MPEG streams */
-#define VID_TYPE_MPEG_ENCODER  2048    /* Can encode MPEG streams */
-#define VID_TYPE_MJPEG_DECODER 4096    /* Can decode MJPEG streams */
-#define VID_TYPE_MJPEG_ENCODER 8192    /* Can encode MJPEG streams */
-
 struct video_capability
 {
        char name[32];
@@ -202,9 +139,9 @@ struct video_audio
 #define VIDEO_SOUND_STEREO     2
 #define VIDEO_SOUND_LANG1      4
 #define VIDEO_SOUND_LANG2      8
-        __u16   mode;
-        __u16  balance;        /* Stereo balance */
-        __u16  step;           /* Step actual volume uses */
+       __u16   mode;
+       __u16   balance;        /* Stereo balance */
+       __u16   step;           /* Step actual volume uses */
 };
 
 struct video_clip
@@ -260,9 +197,6 @@ struct video_key
        __u32   flags;
 };
 
-
-#define VIDEO_MAX_FRAME                32
-
 struct video_mbuf
 {
        int     size;           /* Total memory to map */
@@ -270,10 +204,8 @@ struct video_mbuf
        int     offsets[VIDEO_MAX_FRAME];
 };
 
-
 #define        VIDEO_NO_UNIT   (-1)
 
-
 struct video_unit
 {
        int     video;          /* Video minor */
index 89a055761bed8e877ce1f7af782ae3f0e33371cf..a114fff6568b18d303dd28d579fe591033c5f9c8 100644 (file)
  */
 #ifdef __KERNEL__
 #include <linux/time.h> /* need struct timeval */
+#include <linux/poll.h>
+#include <linux/device.h>
 #endif
 #include <linux/compiler.h> /* need __user */
 
+
+#define OBSOLETE_OWNER 1 /* It will be removed for 2.6.15 */
+#define HAVE_V4L2 1
+
+/*
+ * Common stuff for both V4L1 and V4L2
+ * Moved from videodev.h
+ */
+
+#define VIDEO_MAX_FRAME               32
+
+#define VID_TYPE_CAPTURE       1       /* Can capture */
+#define VID_TYPE_TUNER         2       /* Can tune */
+#define VID_TYPE_TELETEXT      4       /* Does teletext */
+#define VID_TYPE_OVERLAY       8       /* Overlay onto frame buffer */
+#define VID_TYPE_CHROMAKEY     16      /* Overlay by chromakey */
+#define VID_TYPE_CLIPPING      32      /* Can clip */
+#define VID_TYPE_FRAMERAM      64      /* Uses the frame buffer memory */
+#define VID_TYPE_SCALES                128     /* Scalable */
+#define VID_TYPE_MONOCHROME    256     /* Monochrome only */
+#define VID_TYPE_SUBCAPTURE    512     /* Can capture subareas of the image */
+#define VID_TYPE_MPEG_DECODER  1024    /* Can decode MPEG streams */
+#define VID_TYPE_MPEG_ENCODER  2048    /* Can encode MPEG streams */
+#define VID_TYPE_MJPEG_DECODER 4096    /* Can decode MJPEG streams */
+#define VID_TYPE_MJPEG_ENCODER 8192    /* Can encode MJPEG streams */
+
+#ifdef __KERNEL__
+
+#define VFL_TYPE_GRABBER       0
+#define VFL_TYPE_VBI           1
+#define VFL_TYPE_RADIO         2
+#define VFL_TYPE_VTX           3
+
+struct video_device
+{
+       /* device info */
+       struct device *dev;
+       char name[32];
+       int type;       /* v4l1 */
+       int type2;      /* v4l2 */
+       int hardware;
+       int minor;
+
+       /* device ops + callbacks */
+       struct file_operations *fops;
+       void (*release)(struct video_device *vfd);
+
+
+#if OBSOLETE_OWNER /* to be removed in 2.6.15 */
+       /* obsolete -- fops->owner is used instead */
+       struct module *owner;
+       /* dev->driver_data will be used instead some day.
+        * Use the video_{get|set}_drvdata() helper functions,
+        * so the switch over will be transparent for you.
+        * Or use {pci|usb}_{get|set}_drvdata() directly. */
+       void *priv;
+#endif
+
+       /* for videodev.c intenal usage -- please don't touch */
+       int users;                     /* video_exclusive_{open|close} ... */
+       struct semaphore lock;         /* ... helper function uses these   */
+       char devfs_name[64];           /* devfs */
+       struct class_device class_dev; /* sysfs */
+};
+
+#define VIDEO_MAJOR    81
+
+extern int video_register_device(struct video_device *, int type, int nr);
+extern void video_unregister_device(struct video_device *);
+extern int video_usercopy(struct inode *inode, struct file *file,
+                         unsigned int cmd, unsigned long arg,
+                         int (*func)(struct inode *inode, struct file *file,
+                                     unsigned int cmd, void *arg));
+
+/* helper functions to alloc / release struct video_device, the
+   later can be used for video_device->release() */
+struct video_device *video_device_alloc(void);
+void video_device_release(struct video_device *vfd);
+
+#endif
+
 /*
  *     M I S C E L L A N E O U S
  */
 
 /*  Four-character-code (FOURCC) */
 #define v4l2_fourcc(a,b,c,d)\
-        (((__u32)(a)<<0)|((__u32)(b)<<8)|((__u32)(c)<<16)|((__u32)(d)<<24))
+       (((__u32)(a)<<0)|((__u32)(b)<<8)|((__u32)(c)<<16)|((__u32)(d)<<24))
 
 /*
  *     E N U M S
@@ -154,20 +237,20 @@ struct v4l2_capability
 };
 
 /* Values for 'capabilities' field */
-#define V4L2_CAP_VIDEO_CAPTURE         0x00000001  /* Is a video capture device */
-#define V4L2_CAP_VIDEO_OUTPUT          0x00000002  /* Is a video output device */
-#define V4L2_CAP_VIDEO_OVERLAY         0x00000004  /* Can do video overlay */
-#define V4L2_CAP_VBI_CAPTURE           0x00000010  /* Is a raw VBI capture device */
-#define V4L2_CAP_VBI_OUTPUT            0x00000020  /* Is a raw VBI output device */
+#define V4L2_CAP_VIDEO_CAPTURE         0x00000001  /* Is a video capture device */
+#define V4L2_CAP_VIDEO_OUTPUT          0x00000002  /* Is a video output device */
+#define V4L2_CAP_VIDEO_OVERLAY         0x00000004  /* Can do video overlay */
+#define V4L2_CAP_VBI_CAPTURE           0x00000010  /* Is a raw VBI capture device */
+#define V4L2_CAP_VBI_OUTPUT            0x00000020  /* Is a raw VBI output device */
 #if 1
 #define V4L2_CAP_SLICED_VBI_CAPTURE    0x00000040  /* Is a sliced VBI capture device */
 #define V4L2_CAP_SLICED_VBI_OUTPUT     0x00000080  /* Is a sliced VBI output device */
 #endif
-#define V4L2_CAP_RDS_CAPTURE           0x00000100  /* RDS data capture */
+#define V4L2_CAP_RDS_CAPTURE           0x00000100  /* RDS data capture */
 
-#define V4L2_CAP_TUNER                 0x00010000  /* has a tuner */
-#define V4L2_CAP_AUDIO                 0x00020000  /* has audio support */
-#define V4L2_CAP_RADIO                 0x00040000  /* is a radio device */
+#define V4L2_CAP_TUNER                 0x00010000  /* has a tuner */
+#define V4L2_CAP_AUDIO                 0x00020000  /* has audio support */
+#define V4L2_CAP_RADIO                 0x00040000  /* is a radio device */
 
 #define V4L2_CAP_READWRITE              0x01000000  /* read/write systemcalls */
 #define V4L2_CAP_ASYNCIO                0x02000000  /* async I/O */
@@ -179,13 +262,13 @@ struct v4l2_capability
 
 struct v4l2_pix_format
 {
-       __u32                   width;
-       __u32                   height;
-       __u32                   pixelformat;
+       __u32                   width;
+       __u32                   height;
+       __u32                   pixelformat;
        enum v4l2_field         field;
        __u32                   bytesperline;   /* for padding, zero if unused */
-       __u32                   sizeimage;
-        enum v4l2_colorspace   colorspace;
+       __u32                   sizeimage;
+       enum v4l2_colorspace    colorspace;
        __u32                   priv;           /* private data, depends on pixelformat */
 };
 
@@ -238,12 +321,12 @@ struct v4l2_pix_format
  */
 struct v4l2_fmtdesc
 {
-       __u32               index;             /* Format number      */
+       __u32               index;             /* Format number      */
        enum v4l2_buf_type  type;              /* buffer type        */
        __u32               flags;
-       __u8                description[32];   /* Description string */
-       __u32               pixelformat;       /* Format fourcc      */
-       __u32               reserved[4];
+       __u8                description[32];   /* Description string */
+       __u32               pixelformat;       /* Format fourcc      */
+       __u32               reserved[4];
 };
 
 #define V4L2_FMT_FLAG_COMPRESSED 0x0001
@@ -393,7 +476,7 @@ struct v4l2_jpegcompression
 #define V4L2_JPEG_MARKER_DRI (1<<5)    /* Define Restart Interval */
 #define V4L2_JPEG_MARKER_COM (1<<6)    /* Comment segment */
 #define V4L2_JPEG_MARKER_APP (1<<7)    /* App segment, driver will
-                                        * allways use APP0 */
+                                       * allways use APP0 */
 };
 
 
@@ -402,10 +485,10 @@ struct v4l2_jpegcompression
  */
 struct v4l2_requestbuffers
 {
-       __u32                   count;
+       __u32                   count;
        enum v4l2_buf_type      type;
        enum v4l2_memory        memory;
-       __u32                   reserved[2];
+       __u32                   reserved[2];
 };
 
 struct v4l2_buffer
@@ -511,9 +594,9 @@ struct v4l2_outputparm
 
 struct v4l2_cropcap {
        enum v4l2_buf_type      type;
-        struct v4l2_rect        bounds;
-        struct v4l2_rect        defrect;
-        struct v4l2_fract       pixelaspect;
+       struct v4l2_rect        bounds;
+       struct v4l2_rect        defrect;
+       struct v4l2_fract       pixelaspect;
 };
 
 struct v4l2_crop {
@@ -544,6 +627,7 @@ typedef __u64 v4l2_std_id;
 
 #define V4L2_STD_NTSC_M         ((v4l2_std_id)0x00001000)
 #define V4L2_STD_NTSC_M_JP      ((v4l2_std_id)0x00002000)
+#define V4L2_STD_NTSC_443       ((v4l2_std_id)0x00004000)
 
 #define V4L2_STD_SECAM_B        ((v4l2_std_id)0x00010000)
 #define V4L2_STD_SECAM_D        ((v4l2_std_id)0x00020000)
@@ -581,13 +665,14 @@ typedef __u64 v4l2_std_id;
 
 #define V4L2_STD_525_60                (V4L2_STD_PAL_M         |\
                                 V4L2_STD_PAL_60        |\
-                                V4L2_STD_NTSC)
+                                V4L2_STD_NTSC          |\
+                                V4L2_STD_NTSC_443)
 #define V4L2_STD_625_50                (V4L2_STD_PAL           |\
                                 V4L2_STD_PAL_N         |\
                                 V4L2_STD_PAL_Nc        |\
                                 V4L2_STD_SECAM)
 #define V4L2_STD_ATSC           (V4L2_STD_ATSC_8_VSB    |\
-                                V4L2_STD_ATSC_16_VSB)
+                                V4L2_STD_ATSC_16_VSB)
 
 #define V4L2_STD_UNKNOWN        0
 #define V4L2_STD_ALL            (V4L2_STD_525_60       |\
@@ -595,7 +680,7 @@ typedef __u64 v4l2_std_id;
 
 struct v4l2_standard
 {
-       __u32                index;
+       __u32                index;
        v4l2_std_id          id;
        __u8                 name[24];
        struct v4l2_fract    frameperiod; /* Frames, not fields */
@@ -610,9 +695,9 @@ struct v4l2_standard
 struct v4l2_input
 {
        __u32        index;             /*  Which input */
-       __u8         name[32];          /*  Label */
+       __u8         name[32];          /*  Label */
        __u32        type;              /*  Type of input */
-       __u32        audioset;          /*  Associated audios (bitfield) */
+       __u32        audioset;          /*  Associated audios (bitfield) */
        __u32        tuner;             /*  Associated tuner */
        v4l2_std_id  std;
        __u32        status;
@@ -647,9 +732,9 @@ struct v4l2_input
 struct v4l2_output
 {
        __u32        index;             /*  Which output */
-       __u8         name[32];          /*  Label */
+       __u8         name[32];          /*  Label */
        __u32        type;              /*  Type of output */
-       __u32        audioset;          /*  Associated audios (bitfield) */
+       __u32        audioset;          /*  Associated audios (bitfield) */
        __u32        modulator;         /*  Associated modulator */
        v4l2_std_id  std;
        __u32        reserved[4];
@@ -671,12 +756,12 @@ struct v4l2_control
 /*  Used in the VIDIOC_QUERYCTRL ioctl for querying controls */
 struct v4l2_queryctrl
 {
-       __u32                id;
+       __u32                id;
        enum v4l2_ctrl_type  type;
        __u8                 name[32];  /* Whatever */
        __s32                minimum;   /* Note signedness */
        __s32                maximum;
-       __s32                step;
+       __s32                step;
        __s32                default_value;
        __u32                flags;
        __u32                reserved[2];
@@ -779,10 +864,10 @@ struct v4l2_modulator
 
 struct v4l2_frequency
 {
-       __u32                 tuner;
+       __u32                 tuner;
        enum v4l2_tuner_type  type;
-        __u32                frequency;
-       __u32                 reserved[8];
+       __u32                 frequency;
+       __u32                 reserved[8];
 };
 
 /*
@@ -802,6 +887,7 @@ struct v4l2_audio
 
 /*  Flags for the 'mode' field */
 #define V4L2_AUDMODE_AVL               0x00001
+#define V4L2_AUDMODE_32BITS            0x00002
 
 struct v4l2_audioout
 {
@@ -846,14 +932,14 @@ struct v4l2_vbi_format
 
 struct v4l2_sliced_vbi_format
 {
-        __u16   service_set;
-        /* service_lines[0][...] specifies lines 0-23 (1-23 used) of the first field
-           service_lines[1][...] specifies lines 0-23 (1-23 used) of the second field
-                                 (equals frame lines 313-336 for 625 line video
-                                  standards, 263-286 for 525 line standards) */
-        __u16   service_lines[2][24];
-        __u32   io_size;
-        __u32   reserved[2];            /* must be zero */
+       __u16   service_set;
+       /* service_lines[0][...] specifies lines 0-23 (1-23 used) of the first field
+          service_lines[1][...] specifies lines 0-23 (1-23 used) of the second field
+                                (equals frame lines 313-336 for 625 line video
+                                 standards, 263-286 for 525 line standards) */
+       __u16   service_lines[2][24];
+       __u32   io_size;
+       __u32   reserved[2];            /* must be zero */
 };
 
 #define V4L2_SLICED_TELETEXT_B          (0x0001)
@@ -866,22 +952,22 @@ struct v4l2_sliced_vbi_format
 
 struct v4l2_sliced_vbi_cap
 {
-        __u16   service_set;
-        /* service_lines[0][...] specifies lines 0-23 (1-23 used) of the first field
-           service_lines[1][...] specifies lines 0-23 (1-23 used) of the second field
-                                 (equals frame lines 313-336 for 625 line video
-                                  standards, 263-286 for 525 line standards) */
-        __u16   service_lines[2][24];
-        __u32   reserved[4];    /* must be 0 */
+       __u16   service_set;
+       /* service_lines[0][...] specifies lines 0-23 (1-23 used) of the first field
+          service_lines[1][...] specifies lines 0-23 (1-23 used) of the second field
+                                (equals frame lines 313-336 for 625 line video
+                                 standards, 263-286 for 525 line standards) */
+       __u16   service_lines[2][24];
+       __u32   reserved[4];    /* must be 0 */
 };
 
 struct v4l2_sliced_vbi_data
 {
-        __u32   id;
-        __u32   field;          /* 0: first field, 1: second field */
-        __u32   line;           /* 1-23 */
-        __u32   reserved;       /* must be 0 */
-        __u8    data[48];
+       __u32   id;
+       __u32   field;          /* 0: first field, 1: second field */
+       __u32   line;           /* 1-23 */
+       __u32   reserved;       /* must be 0 */
+       __u8    data[48];
 };
 #endif
 
@@ -896,9 +982,9 @@ struct v4l2_format
        enum v4l2_buf_type type;
        union
        {
-               struct v4l2_pix_format          pix;     // V4L2_BUF_TYPE_VIDEO_CAPTURE
-               struct v4l2_window              win;     // V4L2_BUF_TYPE_VIDEO_OVERLAY
-               struct v4l2_vbi_format          vbi;     // V4L2_BUF_TYPE_VBI_CAPTURE
+               struct v4l2_pix_format          pix;     // V4L2_BUF_TYPE_VIDEO_CAPTURE
+               struct v4l2_window              win;     // V4L2_BUF_TYPE_VIDEO_OVERLAY
+               struct v4l2_vbi_format          vbi;     // V4L2_BUF_TYPE_VBI_CAPTURE
 #if 1
                struct v4l2_sliced_vbi_format   sliced;  // V4L2_BUF_TYPE_SLICED_VBI_CAPTURE
 #endif
@@ -981,6 +1067,7 @@ struct v4l2_streamparm
 #if 1
 #define VIDIOC_G_SLICED_VBI_CAP _IOR  ('V', 69, struct v4l2_sliced_vbi_cap)
 #endif
+#define VIDIOC_LOG_STATUS       _IO   ('V', 70)
 
 /* for compatibility, will go away some day */
 #define VIDIOC_OVERLAY_OLD             _IOWR ('V', 14, int)
index a7ceee9fc5e9a0edd113a2c9c2ecdd52c8a50425..b7d4b0930408c3e366e28de0a196387bd03a743d 100644 (file)
@@ -4,6 +4,23 @@
 #ifndef AUDIOCHIP_H
 #define AUDIOCHIP_H
 
+enum audiochip {
+       AUDIO_CHIP_NONE,
+       AUDIO_CHIP_UNKNOWN,
+       /* Provided by video chip */
+       AUDIO_CHIP_INTERNAL,
+       /* Provided by tvaudio.c */
+       AUDIO_CHIP_TDA8425,
+       AUDIO_CHIP_TEA6300,
+       AUDIO_CHIP_TEA6420,
+       AUDIO_CHIP_TDA9840,
+       AUDIO_CHIP_TDA985X,
+       AUDIO_CHIP_TDA9874,
+       AUDIO_CHIP_PIC16C54,
+       /* Provided by msp3400.c */
+       AUDIO_CHIP_MSP34XX
+};
+
 /* ---------------------------------------------------------------------- */
 
 /* v4l device was opened in Radio mode */
diff --git a/include/media/id.h b/include/media/id.h
deleted file mode 100644 (file)
index 6d02c94..0000000
+++ /dev/null
@@ -1,35 +0,0 @@
-/*
- */
-
-/* FIXME: this temporarely, until these are included in linux/i2c-id.h */
-
-/* drivers */
-#ifndef  I2C_DRIVERID_TVMIXER
-# define I2C_DRIVERID_TVMIXER I2C_DRIVERID_EXP0
-#endif
-#ifndef  I2C_DRIVERID_TVAUDIO
-# define I2C_DRIVERID_TVAUDIO I2C_DRIVERID_EXP1
-#endif
-
-/* chips */
-#ifndef  I2C_DRIVERID_DPL3518
-# define I2C_DRIVERID_DPL3518 I2C_DRIVERID_EXP2
-#endif
-#ifndef  I2C_DRIVERID_TDA9873
-# define I2C_DRIVERID_TDA9873 I2C_DRIVERID_EXP3
-#endif
-#ifndef  I2C_DRIVERID_TDA9875
-# define I2C_DRIVERID_TDA9875 I2C_DRIVERID_EXP0+4
-#endif
-#ifndef  I2C_DRIVERID_PIC16C54_PV951
-# define I2C_DRIVERID_PIC16C54_PV951 I2C_DRIVERID_EXP0+5
-#endif
-#ifndef  I2C_DRIVERID_TDA7432
-# define I2C_DRIVERID_TDA7432 I2C_DRIVERID_EXP0+6
-#endif
-#ifndef  I2C_DRIVERID_TDA9874
-# define I2C_DRIVERID_TDA9874 I2C_DRIVERID_EXP0+7
-#endif
-#ifndef  I2C_DRIVERID_SAA6752HS
-# define I2C_DRIVERID_SAA6752HS I2C_DRIVERID_EXP0+8
-#endif
index 01b56822df4d9a9077aa3adaf6c5d9b714ee39ff..0f1ba95ec8d654ad2102ff0b08ef934a4c59197f 100644 (file)
  *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
  */
 
-#include <linux/input.h>
+#ifndef _IR_COMMON
+#define _IR_COMMON
 
+#include <linux/input.h>
 
 #define IR_TYPE_RC5     1
 #define IR_TYPE_PD      2 /* Pulse distance encoded IR */
@@ -61,6 +63,8 @@ int  ir_dump_samples(u32 *samples, int count);
 int  ir_decode_biphase(u32 *samples, int count, int low, int high);
 int  ir_decode_pulsedistance(u32 *samples, int count, int low, int high);
 
+#endif
+
 /*
  * Local variables:
  * c-basic-offset: 8
diff --git a/include/media/ir-kbd-i2c.h b/include/media/ir-kbd-i2c.h
new file mode 100644 (file)
index 0000000..00fa57e
--- /dev/null
@@ -0,0 +1,22 @@
+#ifndef _IR_I2C
+#define _IR_I2C
+
+#include <media/ir-common.h>
+
+struct IR_i2c;
+
+struct IR_i2c {
+       IR_KEYTAB_TYPE         *ir_codes;
+       struct i2c_client      c;
+       struct input_dev       *input;
+       struct ir_input_state  ir;
+
+       /* Used to avoid fast repeating */
+       unsigned char          old;
+
+       struct work_struct     work;
+       struct timer_list      timer;
+       char                   phys[32];
+       int                    (*get_key)(struct IR_i2c*, u32*, u32*);
+};
+#endif
index f3aa24f8131ce3625a9f34afab6e83ea3a2b9d59..64691753721edc1e82d38ff0cc9473273ddedede 100644 (file)
@@ -1,7 +1,7 @@
 #ifndef __SAA7146_VV__
 #define __SAA7146_VV__
 
-#include <linux/videodev2.h>
+#include <linux/videodev.h>
 
 #include <media/saa7146.h>
 #include <media/video-buf.h>
index 4ad08e24a1aa2cc32933a5092f66dfb011a7b020..9184e534b7efce2a31253a09e4913a31394943d2 100644 (file)
@@ -95,7 +95,7 @@
 #define TUNER_THOMSON_DTT7610          52
 #define TUNER_PHILIPS_FQ1286           53
 #define TUNER_PHILIPS_TDA8290          54
-#define TUNER_LG_PAL_TAPE              55      /* Hauppauge PVR-150 PAL */
+#define TUNER_TCL_2002MB               55      /* Hauppauge PVR-150 PAL */
 
 #define TUNER_PHILIPS_FQ1216AME_MK4    56      /* Hauppauge PVR-150 PAL */
 #define TUNER_PHILIPS_FQ1236A_MK4      57      /* Hauppauge PVR-500MCE NTSC */
 #define TUNER_LG_TDVS_H062F            64      /* DViCO FusionHDTV 5 */
 #define TUNER_YMEC_TVF66T5_B_DFF       65      /* Acorp Y878F */
 #define TUNER_LG_NTSC_TALN_MINI                66
+#define TUNER_PHILIPS_TD1316           67
+
+#define TUNER_PHILIPS_TUV1236D         68      /* ATI HDTV Wonder */
 
 #define NOTUNER 0
 #define PAL     1      /* PAL_BG */
 # define TDA9887_INTERCARRIER        (1<<4)
 # define TDA9887_PORT1_ACTIVE        (1<<5)
 # define TDA9887_PORT2_ACTIVE        (1<<6)
+# define TDA9887_INTERCARRIER_NTSC   (1<<7)
 /* config options */
 # define TDA9887_DEEMPHASIS_MASK     (3<<16)
 # define TDA9887_DEEMPHASIS_NONE     (1<<16)
@@ -188,8 +192,11 @@ struct tuner {
        unsigned int radio_if2;
 
        /* used by tda8290 */
-       unsigned char i2c_easy_mode[2];
-       unsigned char i2c_set_freq[8];
+       unsigned char tda8290_easy_mode;
+       unsigned char tda827x_lpsel;
+       unsigned char tda827x_addr;
+       unsigned char tda827x_ver;
+       unsigned int sgIF;
 
        /* function ptrs */
        void (*tv_freq)(struct i2c_client *c, unsigned int freq);
@@ -204,20 +211,21 @@ extern unsigned const int tuner_count;
 
 extern int microtune_init(struct i2c_client *c);
 extern int tda8290_init(struct i2c_client *c);
+extern int tda8290_probe(struct i2c_client *c);
 extern int tea5767_tuner_init(struct i2c_client *c);
 extern int default_tuner_init(struct i2c_client *c);
 extern int tea5767_autodetection(struct i2c_client *c);
 
 #define tuner_warn(fmt, arg...) do {\
        printk(KERN_WARNING "%s %d-%04x: " fmt, t->i2c.driver->name, \
-                        t->i2c.adapter->nr, t->i2c.addr , ##arg); } while (0)
+                       t->i2c.adapter->nr, t->i2c.addr , ##arg); } while (0)
 #define tuner_info(fmt, arg...) do {\
        printk(KERN_INFO "%s %d-%04x: " fmt, t->i2c.driver->name, \
-                        t->i2c.adapter->nr, t->i2c.addr , ##arg); } while (0)
+                       t->i2c.adapter->nr, t->i2c.addr , ##arg); } while (0)
 #define tuner_dbg(fmt, arg...) do {\
        if (tuner_debug) \
-                printk(KERN_DEBUG "%s %d-%04x: " fmt, t->i2c.driver->name, \
-                        t->i2c.adapter->nr, t->i2c.addr , ##arg); } while (0)
+               printk(KERN_DEBUG "%s %d-%04x: " fmt, t->i2c.driver->name, \
+                       t->i2c.adapter->nr, t->i2c.addr , ##arg); } while (0)
 
 #endif /* __KERNEL__ */
 
index ae8d7a0004402715d015e2962287a9a9c9161f00..8ecfd78e00276abcc8567c9a5fed40c472f3bb68 100644 (file)
@@ -17,7 +17,7 @@
  * (at your option) any later version.
  */
 
-#include <linux/videodev.h>
+#include <linux/videodev2.h>
 
 #define UNSET (-1U)
 
@@ -177,7 +177,7 @@ struct videobuf_queue_ops {
 };
 
 struct videobuf_queue {
-        struct semaphore           lock;
+       struct semaphore           lock;
        spinlock_t                 *irqlock;
        struct pci_dev             *pci;
 
index e42d728b16208d70d1398ec5f1bada1cca4401ea..911ceb5cd263b51c90eee3e5803cee3206a88bd8 100644 (file)
@@ -57,8 +57,6 @@
 #define BT_DBG(fmt, arg...)  printk(KERN_INFO "%s: " fmt "\n" , __FUNCTION__ , ## arg)
 #define BT_ERR(fmt, arg...)  printk(KERN_ERR  "%s: " fmt "\n" , __FUNCTION__ , ## arg)
 
-extern struct proc_dir_entry *proc_bt;
-
 /* Connection and socket states */
 enum {
        BT_CONNECTED = 1, /* Equal to TCP_ESTABLISHED to make net code happy */
@@ -177,4 +175,6 @@ extern int hci_sock_cleanup(void);
 extern int bt_sysfs_init(void);
 extern void bt_sysfs_cleanup(void);
 
+extern struct class bt_class;
+
 #endif /* __BLUETOOTH_H */
index fa2d12b0579b49fc9c5e480c65a931ad36c784a5..b06a2d2f63d2dd3d8aaef4b7f7ad22431609a64d 100644 (file)
@@ -184,10 +184,10 @@ enum {
 struct hci_rp_read_loc_version {
        __u8     status;
        __u8     hci_ver;
-       __u16    hci_rev;
+       __le16   hci_rev;
        __u8     lmp_ver;
-       __u16    manufacturer;
-       __u16    lmp_subver;
+       __le16   manufacturer;
+       __le16   lmp_subver;
 } __attribute__ ((packed));
 
 #define OCF_READ_LOCAL_FEATURES        0x0003
@@ -199,10 +199,10 @@ struct hci_rp_read_loc_features {
 #define OCF_READ_BUFFER_SIZE   0x0005
 struct hci_rp_read_buffer_size {
        __u8     status;
-       __u16    acl_mtu;
+       __le16   acl_mtu;
        __u8     sco_mtu;
-       __u16    acl_max_pkt;
-       __u16    sco_max_pkt;
+       __le16   acl_max_pkt;
+       __le16   sco_max_pkt;
 } __attribute__ ((packed));
 
 #define OCF_READ_BD_ADDR       0x0009
@@ -267,21 +267,21 @@ struct hci_cp_write_dev_class {
 
 #define OCF_READ_VOICE_SETTING 0x0025
 struct hci_rp_read_voice_setting {
-       __u8    status;
-       __u16   voice_setting;
+       __u8     status;
+       __le16   voice_setting;
 } __attribute__ ((packed));
 
 #define OCF_WRITE_VOICE_SETTING        0x0026
 struct hci_cp_write_voice_setting {
-       __u16   voice_setting;
+       __le16   voice_setting;
 } __attribute__ ((packed));
 
 #define OCF_HOST_BUFFER_SIZE   0x0033
 struct hci_cp_host_buffer_size {
-       __u16    acl_mtu;
+       __le16   acl_mtu;
        __u8     sco_mtu;
-       __u16    acl_max_pkt;
-       __u16    sco_max_pkt;
+       __le16   acl_max_pkt;
+       __le16   sco_max_pkt;
 } __attribute__ ((packed));
 
 /* Link Control */
@@ -289,10 +289,10 @@ struct hci_cp_host_buffer_size {
 #define OCF_CREATE_CONN                0x0005
 struct hci_cp_create_conn {
        bdaddr_t bdaddr;
-       __u16    pkt_type;
+       __le16   pkt_type;
        __u8     pscan_rep_mode;
        __u8     pscan_mode;
-       __u16    clock_offset;
+       __le16   clock_offset;
        __u8     role_switch;
 } __attribute__ ((packed));
 
@@ -310,14 +310,14 @@ struct hci_cp_reject_conn_req {
 
 #define OCF_DISCONNECT 0x0006
 struct hci_cp_disconnect {
-       __u16    handle;
+       __le16   handle;
        __u8     reason;
 } __attribute__ ((packed));
 
 #define OCF_ADD_SCO    0x0007
 struct hci_cp_add_sco {
-       __u16    handle;
-       __u16    pkt_type;
+       __le16   handle;
+       __le16   pkt_type;
 } __attribute__ ((packed));
 
 #define OCF_INQUIRY            0x0001
@@ -354,56 +354,56 @@ struct hci_cp_pin_code_neg_reply {
 
 #define OCF_CHANGE_CONN_PTYPE  0x000F
 struct hci_cp_change_conn_ptype {
-       __u16    handle;
-       __u16    pkt_type;
+       __le16   handle;
+       __le16   pkt_type;
 } __attribute__ ((packed));
 
 #define OCF_AUTH_REQUESTED     0x0011
 struct hci_cp_auth_requested {
-       __u16    handle;
+       __le16   handle;
 } __attribute__ ((packed));
 
 #define OCF_SET_CONN_ENCRYPT   0x0013
 struct hci_cp_set_conn_encrypt {
-       __u16    handle;
+       __le16   handle;
        __u8     encrypt;
 } __attribute__ ((packed));
 
 #define OCF_CHANGE_CONN_LINK_KEY 0x0015
 struct hci_cp_change_conn_link_key {
-       __u16    handle;
+       __le16   handle;
 } __attribute__ ((packed));
 
 #define OCF_READ_REMOTE_FEATURES 0x001B
 struct hci_cp_read_rmt_features {
-       __u16    handle;
+       __le16   handle;
 } __attribute__ ((packed));
 
 #define OCF_READ_REMOTE_VERSION 0x001D
 struct hci_cp_read_rmt_version {
-       __u16    handle;
+       __le16   handle;
 } __attribute__ ((packed));
 
 /* Link Policy */
 #define OGF_LINK_POLICY         0x02   
 #define OCF_ROLE_DISCOVERY     0x0009
 struct hci_cp_role_discovery {
-       __u16    handle;
+       __le16   handle;
 } __attribute__ ((packed));
 struct hci_rp_role_discovery {
        __u8     status;
-       __u16    handle;
+       __le16   handle;
        __u8     role;
 } __attribute__ ((packed));
 
 #define OCF_READ_LINK_POLICY   0x000C
 struct hci_cp_read_link_policy {
-       __u16    handle;
+       __le16   handle;
 } __attribute__ ((packed));
 struct hci_rp_read_link_policy {
        __u8     status;
-       __u16    handle;
-       __u16    policy;
+       __le16   handle;
+       __le16   policy;
 } __attribute__ ((packed));
 
 #define OCF_SWITCH_ROLE        0x000B
@@ -414,12 +414,12 @@ struct hci_cp_switch_role {
 
 #define OCF_WRITE_LINK_POLICY  0x000D
 struct hci_cp_write_link_policy {
-       __u16    handle;
-       __u16    policy;
+       __le16   handle;
+       __le16   policy;
 } __attribute__ ((packed));
 struct hci_rp_write_link_policy {
        __u8     status;
-       __u16    handle;
+       __le16   handle;
 } __attribute__ ((packed));
 
 /* Status params */
@@ -441,7 +441,7 @@ struct inquiry_info {
        __u8     pscan_period_mode;
        __u8     pscan_mode;
        __u8     dev_class[3];
-       __u16    clock_offset;
+       __le16   clock_offset;
 } __attribute__ ((packed));
 
 #define HCI_EV_INQUIRY_RESULT_WITH_RSSI        0x22
@@ -450,7 +450,7 @@ struct inquiry_info_with_rssi {
        __u8     pscan_rep_mode;
        __u8     pscan_period_mode;
        __u8     dev_class[3];
-       __u16    clock_offset;
+       __le16   clock_offset;
        __s8     rssi;
 } __attribute__ ((packed));
 struct inquiry_info_with_rssi_and_pscan_mode {
@@ -459,7 +459,7 @@ struct inquiry_info_with_rssi_and_pscan_mode {
        __u8     pscan_period_mode;
        __u8     pscan_mode;
        __u8     dev_class[3];
-       __u16    clock_offset;
+       __le16   clock_offset;
        __s8     rssi;
 } __attribute__ ((packed));
 
@@ -469,7 +469,7 @@ struct extended_inquiry_info {
        __u8     pscan_rep_mode;
        __u8     pscan_period_mode;
        __u8     dev_class[3];
-       __u16    clock_offset;
+       __le16   clock_offset;
        __s8     rssi;
        __u8     data[240];
 } __attribute__ ((packed));
@@ -477,7 +477,7 @@ struct extended_inquiry_info {
 #define HCI_EV_CONN_COMPLETE   0x03
 struct hci_ev_conn_complete {
        __u8     status;
-       __u16    handle;
+       __le16   handle;
        bdaddr_t bdaddr;
        __u8     link_type;
        __u8     encr_mode;
@@ -493,27 +493,27 @@ struct hci_ev_conn_request {
 #define HCI_EV_DISCONN_COMPLETE        0x05
 struct hci_ev_disconn_complete {
        __u8     status;
-       __u16    handle;
+       __le16   handle;
        __u8     reason;
 } __attribute__ ((packed));
 
 #define HCI_EV_AUTH_COMPLETE   0x06
 struct hci_ev_auth_complete {
        __u8     status;
-       __u16    handle;
+       __le16   handle;
 } __attribute__ ((packed));
 
 #define HCI_EV_ENCRYPT_CHANGE  0x08
 struct hci_ev_encrypt_change {
        __u8     status;
-       __u16    handle;
+       __le16   handle;
        __u8     encrypt;
 } __attribute__ ((packed));
 
 #define HCI_EV_CHANGE_CONN_LINK_KEY_COMPLETE   0x09
 struct hci_ev_change_conn_link_key_complete {
        __u8     status;
-       __u16    handle;
+       __le16   handle;
 } __attribute__ ((packed));
 
 #define HCI_EV_QOS_SETUP_COMPLETE      0x0D
@@ -526,21 +526,21 @@ struct hci_qos {
 } __attribute__ ((packed));
 struct hci_ev_qos_setup_complete {
        __u8     status;
-       __u16    handle;
+       __le16   handle;
        struct   hci_qos qos;
 } __attribute__ ((packed));
 
 #define HCI_EV_CMD_COMPLETE    0x0E
 struct hci_ev_cmd_complete {
        __u8     ncmd;
-       __u16    opcode;
+       __le16   opcode;
 } __attribute__ ((packed));
 
 #define HCI_EV_CMD_STATUS      0x0F
 struct hci_ev_cmd_status {
        __u8     status;
        __u8     ncmd;
-       __u16    opcode;
+       __le16   opcode;
 } __attribute__ ((packed));
 
 #define HCI_EV_NUM_COMP_PKTS   0x13
@@ -559,9 +559,9 @@ struct hci_ev_role_change {
 #define HCI_EV_MODE_CHANGE     0x14
 struct hci_ev_mode_change {
        __u8     status;
-       __u16    handle;
+       __le16   handle;
        __u8     mode;
-       __u16    interval;
+       __le16   interval;
 } __attribute__ ((packed));
 
 #define HCI_EV_PIN_CODE_REQ    0x16
@@ -584,24 +584,24 @@ struct hci_ev_link_key_notify {
 #define HCI_EV_RMT_FEATURES    0x0B
 struct hci_ev_rmt_features {
        __u8     status;
-       __u16    handle;
+       __le16   handle;
        __u8     features[8];
 } __attribute__ ((packed));
 
 #define HCI_EV_RMT_VERSION     0x0C
 struct hci_ev_rmt_version {
        __u8     status;
-       __u16    handle;
+       __le16   handle;
        __u8     lmp_ver;
-       __u16    manufacturer;
-       __u16    lmp_subver;
+       __le16   manufacturer;
+       __le16   lmp_subver;
 } __attribute__ ((packed));
 
 #define HCI_EV_CLOCK_OFFSET    0x01C
 struct hci_ev_clock_offset {
        __u8     status;
-       __u16    handle;
-       __u16    clock_offset;
+       __le16   handle;
+       __le16   clock_offset;
 } __attribute__ ((packed));
 
 #define HCI_EV_PSCAN_REP_MODE  0x20
@@ -638,7 +638,7 @@ struct hci_ev_si_security {
 #define HCI_SCO_HDR_SIZE     3
 
 struct hci_command_hdr {
-       __u16   opcode;         /* OCF & OGF */
+       __le16  opcode;         /* OCF & OGF */
        __u8    plen;
 } __attribute__ ((packed));
 
@@ -648,22 +648,22 @@ struct hci_event_hdr {
 } __attribute__ ((packed));
 
 struct hci_acl_hdr {
-       __u16   handle;         /* Handle & Flags(PB, BC) */
-       __u16   dlen;
+       __le16  handle;         /* Handle & Flags(PB, BC) */
+       __le16  dlen;
 } __attribute__ ((packed));
 
 struct hci_sco_hdr {
-       __u16   handle;
+       __le16  handle;
        __u8    dlen;
 } __attribute__ ((packed));
 
 /* Command opcode pack/unpack */
-#define hci_opcode_pack(ogf, ocf)      (__u16)((ocf & 0x03ff)|(ogf << 10))
+#define hci_opcode_pack(ogf, ocf)      (__u16) ((ocf & 0x03ff)|(ogf << 10))
 #define hci_opcode_ogf(op)             (op >> 10)
 #define hci_opcode_ocf(op)             (op & 0x03ff)
 
 /* ACL handle and flags pack/unpack */
-#define hci_handle_pack(h, f)  (__u16)((h & 0x0fff)|(f << 12))
+#define hci_handle_pack(h, f)  (__u16) ((h & 0x0fff)|(f << 12))
 #define hci_handle(h)          (h & 0x0fff)
 #define hci_flags(h)           (h >> 12)
 
index 7f933f30207830333996a9d872acbbef536e636d..bb9f81dc8723c5522daffd6d6184f3df675d0321 100644 (file)
@@ -25,7 +25,6 @@
 #ifndef __HCI_CORE_H
 #define __HCI_CORE_H
 
-#include <linux/proc_fs.h>
 #include <net/bluetooth/hci.h>
 
 /* HCI upper protocols */
@@ -34,8 +33,6 @@
 
 #define HCI_INIT_TIMEOUT (HZ * 10)
 
-extern struct proc_dir_entry *proc_bt_hci;
-
 /* HCI Core structures */
 
 struct inquiry_data {
@@ -44,7 +41,7 @@ struct inquiry_data {
        __u8            pscan_period_mode;
        __u8            pscan_mode;
        __u8            dev_class[3];
-       __u16           clock_offset;
+       __le16          clock_offset;
        __s8            rssi;
 };
 
@@ -126,10 +123,6 @@ struct hci_dev {
 
        atomic_t                promisc;
 
-#ifdef CONFIG_PROC_FS
-       struct proc_dir_entry   *proc;
-#endif
-
        struct class_device     class_dev;
 
        struct module           *owner;
index e656be7c001a342935119c44a8ffd741a5aa0a13..bbfac86734ec44f50b34efaf5067498c8080a3dc 100644 (file)
@@ -351,6 +351,4 @@ int  rfcomm_dev_ioctl(struct sock *sk, unsigned int cmd, void __user *arg);
 int  rfcomm_init_ttys(void);
 void rfcomm_cleanup_ttys(void);
 
-extern struct proc_dir_entry *proc_bt_rfcomm;
-
 #endif /* __RFCOMM_H */
index 65ec86678a08e34280fdd23e7e10f2c2cbb1494f..6addb4d464d6c87b0b7d9ae2884c46e57c2e8737 100644 (file)
@@ -252,12 +252,25 @@ typedef int               (*inet_getfrag_t) (const void *data,
                                           char *,
                                           unsigned int, unsigned int);
 
-
-extern int             ipv6_addr_type(const struct in6_addr *addr);
+extern int __ipv6_addr_type(const struct in6_addr *addr);
+static inline int ipv6_addr_type(const struct in6_addr *addr)
+{
+       return __ipv6_addr_type(addr) & 0xffff;
+}
 
 static inline int ipv6_addr_scope(const struct in6_addr *addr)
 {
-       return ipv6_addr_type(addr) & IPV6_ADDR_SCOPE_MASK;
+       return __ipv6_addr_type(addr) & IPV6_ADDR_SCOPE_MASK;
+}
+
+static inline int __ipv6_addr_src_scope(int type)
+{
+       return (type == IPV6_ADDR_ANY ? __IPV6_ADDR_SCOPE_INVALID : (type >> 16));
+}
+
+static inline int ipv6_addr_src_scope(const struct in6_addr *addr)
+{
+       return __ipv6_addr_src_scope(__ipv6_addr_type(addr));
 }
 
 static inline int ipv6_addr_cmp(const struct in6_addr *a1, const struct in6_addr *a2)
@@ -340,6 +353,54 @@ static inline int ipv6_addr_any(const struct in6_addr *a)
                 a->s6_addr32[2] | a->s6_addr32[3] ) == 0); 
 }
 
+/*
+ * find the first different bit between two addresses
+ * length of address must be a multiple of 32bits
+ */
+static inline int __ipv6_addr_diff(const void *token1, const void *token2, int addrlen)
+{
+       const __u32 *a1 = token1, *a2 = token2;
+       int i;
+
+       addrlen >>= 2;
+
+       for (i = 0; i < addrlen; i++) {
+               __u32 xb = a1[i] ^ a2[i];
+               if (xb) {
+                       int j = 31;
+
+                       xb = ntohl(xb);
+                       while ((xb & (1 << j)) == 0)
+                               j--;
+
+                       return (i * 32 + 31 - j);
+               }
+       }
+
+       /*
+        *      we should *never* get to this point since that 
+        *      would mean the addrs are equal
+        *
+        *      However, we do get to it 8) And exacly, when
+        *      addresses are equal 8)
+        *
+        *      ip route add 1111::/128 via ...
+        *      ip route add 1111::/64 via ...
+        *      and we are here.
+        *
+        *      Ideally, this function should stop comparison
+        *      at prefix length. It does not, but it is still OK,
+        *      if returned value is greater than prefix length.
+        *                                      --ANK (980803)
+        */
+       return (addrlen << 5);
+}
+
+static inline int ipv6_addr_diff(const struct in6_addr *a1, const struct in6_addr *a2)
+{
+       return __ipv6_addr_diff(a1, a2, sizeof(struct in6_addr));
+}
+
 /*
  *     Prototypes exported by ipv6
  */
index e0498bd360042121d99fa0aea7ec77b8ebb2a03b..ff13c4cc287add76e658418aaae91970c1c87f66 100644 (file)
@@ -461,16 +461,16 @@ static inline void sk_stream_free_skb(struct sock *sk, struct sk_buff *skb)
 }
 
 /* The per-socket spinlock must be held here. */
-#define sk_add_backlog(__sk, __skb)                            \
-do {   if (!(__sk)->sk_backlog.tail) {                         \
-               (__sk)->sk_backlog.head =                       \
-                    (__sk)->sk_backlog.tail = (__skb);         \
-       } else {                                                \
-               ((__sk)->sk_backlog.tail)->next = (__skb);      \
-               (__sk)->sk_backlog.tail = (__skb);              \
-       }                                                       \
-       (__skb)->next = NULL;                                   \
-} while(0)
+static inline void sk_add_backlog(struct sock *sk, struct sk_buff *skb)
+{
+       if (!sk->sk_backlog.tail) {
+               sk->sk_backlog.head = sk->sk_backlog.tail = skb;
+       } else {
+               sk->sk_backlog.tail->next = skb;
+               sk->sk_backlog.tail = skb;
+       }
+       skb->next = NULL;
+}
 
 #define sk_wait_event(__sk, __timeo, __condition)              \
 ({     int rc;                                                 \
index f142d403534190f4588b3d7eda585112077e0607..27f97f9b46362c4fa316619fdcc8e0d29751bbd3 100644 (file)
@@ -394,14 +394,16 @@ static void noinline rest_init(void)
        kernel_thread(init, NULL, CLONE_FS | CLONE_SIGHAND);
        numa_default_policy();
        unlock_kernel();
-       preempt_enable_no_resched();
 
        /*
         * The boot idle thread must execute schedule()
         * at least one to get things moving:
         */
+       preempt_enable_no_resched();
        schedule();
+       preempt_disable();
 
+       /* Call into cpu_idle with preempt disabled */
        cpu_idle();
 } 
 
index 3619e939182e3b75c982e33eace09f1b86fe9b85..d61ba88f34e57b90edae90342ed1db59ebfbb59c 100644 (file)
@@ -21,6 +21,24 @@ EXPORT_SYMBOL_GPL(cpucontrol);
 
 static struct notifier_block *cpu_chain;
 
+/*
+ * Used to check by callers if they need to acquire the cpucontrol
+ * or not to protect a cpu from being removed. Its sometimes required to
+ * call these functions both for normal operations, and in response to
+ * a cpu being added/removed. If the context of the call is in the same
+ * thread context as a CPU hotplug thread, we dont need to take the lock
+ * since its already protected
+ * check drivers/cpufreq/cpufreq.c for its usage - Ashok Raj
+ */
+
+int current_in_cpu_hotplug(void)
+{
+       return (current->flags & PF_HOTPLUG_CPU);
+}
+
+EXPORT_SYMBOL_GPL(current_in_cpu_hotplug);
+
+
 /* Need to know about CPUs going up/down? */
 int register_cpu_notifier(struct notifier_block *nb)
 {
@@ -94,6 +112,13 @@ int cpu_down(unsigned int cpu)
                goto out;
        }
 
+       /*
+        * Leave a trace in current->flags indicating we are already in
+        * process of performing CPU hotplug. Callers can check if cpucontrol
+        * is already acquired by current thread, and if so not cause
+        * a dead lock by not acquiring the lock
+        */
+       current->flags |= PF_HOTPLUG_CPU;
        err = notifier_call_chain(&cpu_chain, CPU_DOWN_PREPARE,
                                                (void *)(long)cpu);
        if (err == NOTIFY_BAD) {
@@ -146,6 +171,7 @@ out_thread:
 out_allowed:
        set_cpus_allowed(current, old_allowed);
 out:
+       current->flags &= ~PF_HOTPLUG_CPU;
        unlock_cpu_hotplug();
        return err;
 }
@@ -163,6 +189,12 @@ int __devinit cpu_up(unsigned int cpu)
                ret = -EINVAL;
                goto out;
        }
+
+       /*
+        * Leave a trace in current->flags indicating we are already in
+        * process of performing CPU hotplug.
+        */
+       current->flags |= PF_HOTPLUG_CPU;
        ret = notifier_call_chain(&cpu_chain, CPU_UP_PREPARE, hcpu);
        if (ret == NOTIFY_BAD) {
                printk("%s: attempt to bring up CPU %u failed\n",
@@ -185,6 +217,7 @@ out_notify:
        if (ret != 0)
                notifier_call_chain(&cpu_chain, CPU_UP_CANCELED, hcpu);
 out:
+       current->flags &= ~PF_HOTPLUG_CPU;
        up(&cpucontrol);
        return ret;
 }
index 18d7d693fbba852c48acc40de4ad8809baf5d36e..6ee2cad530e8971f4ad69da2f94d96455039fc5e 100644 (file)
@@ -167,7 +167,7 @@ static int enter_state(suspend_state_t state)
 {
        int error;
 
-       if (pm_ops->valid && !pm_ops->valid(state))
+       if (pm_ops && pm_ops->valid && !pm_ops->valid(state))
                return -ENODEV;
        if (down_trylock(&pm_sem))
                return -EBUSY;
index d4fd96a135abeb7f1e84314469934976bae018f5..6c042b5ee14ba105ce0bf0b53bf8530bf8aee180 100644 (file)
@@ -65,8 +65,8 @@ extern suspend_pagedir_t *pagedir_save;
 extern asmlinkage int swsusp_arch_suspend(void);
 extern asmlinkage int swsusp_arch_resume(void);
 
-extern int restore_highmem(void);
-extern struct pbe * alloc_pagedir(unsigned nr_pages);
+extern void free_pagedir(struct pbe *pblist);
+extern struct pbe *alloc_pagedir(unsigned nr_pages, gfp_t gfp_mask, int safe_needed);
 extern void create_pbe_list(struct pbe *pblist, unsigned nr_pages);
 extern void swsusp_free(void);
-extern int enough_swap(unsigned nr_pages);
+extern int alloc_data_pages(struct pbe *pblist, gfp_t gfp_mask, int safe_needed);
index 723f5179883e57d054d13bbb53bf2854b70e1b00..4a6dbcefd37875d75e404ae6b5799cec3836a700 100644 (file)
@@ -88,8 +88,7 @@ static int save_highmem_zone(struct zone *zone)
        return 0;
 }
 
-
-static int save_highmem(void)
+int save_highmem(void)
 {
        struct zone *zone;
        int res = 0;
@@ -120,11 +119,7 @@ int restore_highmem(void)
        }
        return 0;
 }
-#else
-static int save_highmem(void) { return 0; }
-int restore_highmem(void) { return 0; }
-#endif /* CONFIG_HIGHMEM */
-
+#endif
 
 static int pfn_is_nosave(unsigned long pfn)
 {
@@ -216,7 +211,7 @@ static void copy_data_pages(struct pbe *pblist)
  *     free_pagedir - free pages allocated with alloc_pagedir()
  */
 
-static void free_pagedir(struct pbe *pblist)
+void free_pagedir(struct pbe *pblist)
 {
        struct pbe *pbe;
 
@@ -269,9 +264,30 @@ void create_pbe_list(struct pbe *pblist, unsigned int nr_pages)
        pr_debug("create_pbe_list(): initialized %d PBEs\n", num);
 }
 
-static void *alloc_image_page(void)
+/**
+ *     @safe_needed - on resume, for storing the PBE list and the image,
+ *     we can only use memory pages that do not conflict with the pages
+ *     which had been used before suspend.
+ *
+ *     The unsafe pages are marked with the PG_nosave_free flag
+ *
+ *     Allocated but unusable (ie eaten) memory pages should be marked
+ *     so that swsusp_free() can release them
+ */
+
+static inline void *alloc_image_page(gfp_t gfp_mask, int safe_needed)
 {
-       void *res = (void *)get_zeroed_page(GFP_ATOMIC | __GFP_COLD);
+       void *res;
+
+       if (safe_needed)
+               do {
+                       res = (void *)get_zeroed_page(gfp_mask);
+                       if (res && PageNosaveFree(virt_to_page(res)))
+                               /* This is for swsusp_free() */
+                               SetPageNosave(virt_to_page(res));
+               } while (res && PageNosaveFree(virt_to_page(res)));
+       else
+               res = (void *)get_zeroed_page(gfp_mask);
        if (res) {
                SetPageNosave(virt_to_page(res));
                SetPageNosaveFree(virt_to_page(res));
@@ -279,6 +295,11 @@ static void *alloc_image_page(void)
        return res;
 }
 
+unsigned long get_safe_page(gfp_t gfp_mask)
+{
+       return (unsigned long)alloc_image_page(gfp_mask, 1);
+}
+
 /**
  *     alloc_pagedir - Allocate the page directory.
  *
@@ -292,7 +313,7 @@ static void *alloc_image_page(void)
  *     On each page we set up a list of struct_pbe elements.
  */
 
-struct pbe *alloc_pagedir(unsigned int nr_pages)
+struct pbe *alloc_pagedir(unsigned int nr_pages, gfp_t gfp_mask, int safe_needed)
 {
        unsigned int num;
        struct pbe *pblist, *pbe;
@@ -301,12 +322,12 @@ struct pbe *alloc_pagedir(unsigned int nr_pages)
                return NULL;
 
        pr_debug("alloc_pagedir(): nr_pages = %d\n", nr_pages);
-       pblist = alloc_image_page();
+       pblist = alloc_image_page(gfp_mask, safe_needed);
        /* FIXME: rewrite this ugly loop */
        for (pbe = pblist, num = PBES_PER_PAGE; pbe && num < nr_pages;
                        pbe = pbe->next, num += PBES_PER_PAGE) {
                pbe += PB_PAGE_SKIP;
-               pbe->next = alloc_image_page();
+               pbe->next = alloc_image_page(gfp_mask, safe_needed);
        }
        if (!pbe) { /* get_zeroed_page() failed */
                free_pagedir(pblist);
@@ -354,24 +375,32 @@ static int enough_free_mem(unsigned int nr_pages)
                (nr_pages + PBES_PER_PAGE - 1) / PBES_PER_PAGE);
 }
 
+int alloc_data_pages(struct pbe *pblist, gfp_t gfp_mask, int safe_needed)
+{
+       struct pbe *p;
+
+       for_each_pbe (p, pblist) {
+               p->address = (unsigned long)alloc_image_page(gfp_mask, safe_needed);
+               if (!p->address)
+                       return -ENOMEM;
+       }
+       return 0;
+}
 
 static struct pbe *swsusp_alloc(unsigned int nr_pages)
 {
-       struct pbe *pblist, *p;
+       struct pbe *pblist;
 
-       if (!(pblist = alloc_pagedir(nr_pages))) {
+       if (!(pblist = alloc_pagedir(nr_pages, GFP_ATOMIC | __GFP_COLD, 0))) {
                printk(KERN_ERR "suspend: Allocating pagedir failed.\n");
                return NULL;
        }
        create_pbe_list(pblist, nr_pages);
 
-       for_each_pbe (p, pblist) {
-               p->address = (unsigned long)alloc_image_page();
-               if (!p->address) {
-                       printk(KERN_ERR "suspend: Allocating image pages failed.\n");
-                       swsusp_free();
-                       return NULL;
-               }
+       if (alloc_data_pages(pblist, GFP_ATOMIC | __GFP_COLD, 0)) {
+               printk(KERN_ERR "suspend: Allocating image pages failed.\n");
+               swsusp_free();
+               return NULL;
        }
 
        return pblist;
@@ -382,11 +411,6 @@ asmlinkage int swsusp_save(void)
        unsigned int nr_pages;
 
        pr_debug("swsusp: critical section: \n");
-       if (save_highmem()) {
-               printk(KERN_CRIT "swsusp: Not enough free pages for highmem\n");
-               restore_highmem();
-               return -ENOMEM;
-       }
 
        drain_local_pages();
        nr_pages = count_data_pages();
@@ -406,11 +430,6 @@ asmlinkage int swsusp_save(void)
                return -ENOMEM;
        }
 
-       if (!enough_swap(nr_pages)) {
-               printk(KERN_ERR "swsusp: Not enough free swap\n");
-               return -ENOSPC;
-       }
-
        pagedir_nosave = swsusp_alloc(nr_pages);
        if (!pagedir_nosave)
                return -ENOMEM;
index e1ab28b9b2176fe14c364fb00485e9d0c2067900..c05f46e7348f54c0658f670370094cb1de30a9f5 100644 (file)
 
 #include "power.h"
 
+#ifdef CONFIG_HIGHMEM
+int save_highmem(void);
+int restore_highmem(void);
+#else
+static int save_highmem(void) { return 0; }
+static int restore_highmem(void) { return 0; }
+#endif
+
 #define CIPHER "aes"
 #define MAXKEY 32
 #define MAXIV  32
@@ -499,6 +507,26 @@ static int write_pagedir(void)
        return error;
 }
 
+/**
+ *     enough_swap - Make sure we have enough swap to save the image.
+ *
+ *     Returns TRUE or FALSE after checking the total amount of swap
+ *     space avaiable.
+ *
+ *     FIXME: si_swapinfo(&i) returns all swap devices information.
+ *     We should only consider resume_device.
+ */
+
+static int enough_swap(unsigned int nr_pages)
+{
+       struct sysinfo i;
+
+       si_swapinfo(&i);
+       pr_debug("swsusp: available swap: %lu pages\n", i.freeswap);
+       return i.freeswap > (nr_pages + PAGES_FOR_IO +
+               (nr_pages + PBES_PER_PAGE - 1) / PBES_PER_PAGE);
+}
+
 /**
  *     write_suspend_image - Write entire image and metadata.
  *
@@ -507,6 +535,11 @@ static int write_suspend_image(void)
 {
        int error;
 
+       if (!enough_swap(nr_copy_pages)) {
+               printk(KERN_ERR "swsusp: Not enough free swap\n");
+               return -ENOSPC;
+       }
+
        init_header();
        if ((error = data_write()))
                goto FreeData;
@@ -526,27 +559,6 @@ static int write_suspend_image(void)
        goto Done;
 }
 
-/**
- *     enough_swap - Make sure we have enough swap to save the image.
- *
- *     Returns TRUE or FALSE after checking the total amount of swap
- *     space avaiable.
- *
- *     FIXME: si_swapinfo(&i) returns all swap devices information.
- *     We should only consider resume_device.
- */
-
-int enough_swap(unsigned int nr_pages)
-{
-       struct sysinfo i;
-
-       si_swapinfo(&i);
-       pr_debug("swsusp: available swap: %lu pages\n", i.freeswap);
-       return i.freeswap > (nr_pages + PAGES_FOR_IO +
-               (nr_pages + PBES_PER_PAGE - 1) / PBES_PER_PAGE);
-}
-
-
 /* It is important _NOT_ to umount filesystems at this point. We want
  * them synced (in case something goes wrong) but we DO not want to mark
  * filesystem clean: it is not. (And it does not matter, if we resume
@@ -556,12 +568,15 @@ int swsusp_write(void)
 {
        int error;
 
+       if ((error = swsusp_swap_check())) {
+               printk(KERN_ERR "swsusp: cannot find swap device, try swapon -a.\n");
+               return error;
+       }
        lock_swapdevices();
        error = write_suspend_image();
        /* This will unlock ignored swap devices since writing is finished */
        lock_swapdevices();
        return error;
-
 }
 
 
@@ -569,6 +584,7 @@ int swsusp_write(void)
 int swsusp_suspend(void)
 {
        int error;
+
        if ((error = arch_prepare_suspend()))
                return error;
        local_irq_disable();
@@ -580,15 +596,12 @@ int swsusp_suspend(void)
         */
        if ((error = device_power_down(PMSG_FREEZE))) {
                printk(KERN_ERR "Some devices failed to power down, aborting suspend\n");
-               local_irq_enable();
-               return error;
+               goto Enable_irqs;
        }
 
-       if ((error = swsusp_swap_check())) {
-               printk(KERN_ERR "swsusp: cannot find swap device, try swapon -a.\n");
-               device_power_up();
-               local_irq_enable();
-               return error;
+       if ((error = save_highmem())) {
+               printk(KERN_ERR "swsusp: Not enough free pages for highmem\n");
+               goto Restore_highmem;
        }
 
        save_processor_state();
@@ -596,8 +609,10 @@ int swsusp_suspend(void)
                printk(KERN_ERR "Error %d suspending\n", error);
        /* Restore control flow magically appears here */
        restore_processor_state();
+Restore_highmem:
        restore_highmem();
        device_power_up();
+Enable_irqs:
        local_irq_enable();
        return error;
 }
@@ -629,127 +644,43 @@ int swsusp_resume(void)
 }
 
 /**
- *     On resume, for storing the PBE list and the image,
- *     we can only use memory pages that do not conflict with the pages
- *     which had been used before suspend.
- *
- *     We don't know which pages are usable until we allocate them.
- *
- *     Allocated but unusable (ie eaten) memory pages are marked so that
- *     swsusp_free() can release them
- */
-
-unsigned long get_safe_page(gfp_t gfp_mask)
-{
-       unsigned long m;
-
-       do {
-               m = get_zeroed_page(gfp_mask);
-               if (m && PageNosaveFree(virt_to_page(m)))
-                       /* This is for swsusp_free() */
-                       SetPageNosave(virt_to_page(m));
-       } while (m && PageNosaveFree(virt_to_page(m)));
-       if (m) {
-               /* This is for swsusp_free() */
-               SetPageNosave(virt_to_page(m));
-               SetPageNosaveFree(virt_to_page(m));
-       }
-       return m;
-}
-
-/**
- *     check_pagedir - We ensure here that pages that the PBEs point to
- *     won't collide with pages where we're going to restore from the loaded
- *     pages later
- */
-
-static int check_pagedir(struct pbe *pblist)
-{
-       struct pbe *p;
-
-       /* This is necessary, so that we can free allocated pages
-        * in case of failure
-        */
-       for_each_pbe (p, pblist)
-               p->address = 0UL;
-
-       for_each_pbe (p, pblist) {
-               p->address = get_safe_page(GFP_ATOMIC);
-               if (!p->address)
-                       return -ENOMEM;
-       }
-       return 0;
-}
-
-/**
- *     swsusp_pagedir_relocate - It is possible, that some memory pages
- *     occupied by the list of PBEs collide with pages where we're going to
- *     restore from the loaded pages later.  We relocate them here.
+ *     mark_unsafe_pages - mark the pages that cannot be used for storing
+ *     the image during resume, because they conflict with the pages that
+ *     had been used before suspend
  */
 
-static struct pbe *swsusp_pagedir_relocate(struct pbe *pblist)
+static void mark_unsafe_pages(struct pbe *pblist)
 {
        struct zone *zone;
        unsigned long zone_pfn;
-       struct pbe *pbpage, *tail, *p;
-       void *m;
-       int rel = 0;
+       struct pbe *p;
 
        if (!pblist) /* a sanity check */
-               return NULL;
-
-       pr_debug("swsusp: Relocating pagedir (%lu pages to check)\n",
-                       swsusp_info.pagedir_pages);
+               return;
 
        /* Clear page flags */
-
        for_each_zone (zone) {
-               for (zone_pfn = 0; zone_pfn < zone->spanned_pages; ++zone_pfn)
-                       if (pfn_valid(zone_pfn + zone->zone_start_pfn))
-                               ClearPageNosaveFree(pfn_to_page(zone_pfn +
+               for (zone_pfn = 0; zone_pfn < zone->spanned_pages; ++zone_pfn)
+                       if (pfn_valid(zone_pfn + zone->zone_start_pfn))
+                               ClearPageNosaveFree(pfn_to_page(zone_pfn +
                                        zone->zone_start_pfn));
        }
 
        /* Mark orig addresses */
-
        for_each_pbe (p, pblist)
                SetPageNosaveFree(virt_to_page(p->orig_address));
 
-       tail = pblist + PB_PAGE_SKIP;
-
-       /* Relocate colliding pages */
-
-       for_each_pb_page (pbpage, pblist) {
-               if (PageNosaveFree(virt_to_page((unsigned long)pbpage))) {
-                       m = (void *)get_safe_page(GFP_ATOMIC | __GFP_COLD);
-                       if (!m)
-                               return NULL;
-                       memcpy(m, (void *)pbpage, PAGE_SIZE);
-                       if (pbpage == pblist)
-                               pblist = (struct pbe *)m;
-                       else
-                               tail->next = (struct pbe *)m;
-                       pbpage = (struct pbe *)m;
-
-                       /* We have to link the PBEs again */
-                       for (p = pbpage; p < pbpage + PB_PAGE_SKIP; p++)
-                               if (p->next) /* needed to save the end */
-                                       p->next = p + 1;
-
-                       rel++;
-               }
-               tail = pbpage + PB_PAGE_SKIP;
-       }
+}
 
-       /* This is for swsusp_free() */
-       for_each_pb_page (pbpage, pblist) {
-               SetPageNosave(virt_to_page(pbpage));
-               SetPageNosaveFree(virt_to_page(pbpage));
+static void copy_page_backup_list(struct pbe *dst, struct pbe *src)
+{
+       /* We assume both lists contain the same number of elements */
+       while (src) {
+               dst->orig_address = src->orig_address;
+               dst->swap_address = src->swap_address;
+               dst = dst->next;
+               src = src->next;
        }
-
-       printk("swsusp: Relocated %d pages\n", rel);
-
-       return pblist;
 }
 
 /*
@@ -888,7 +819,7 @@ static int check_sig(void)
                 * Reset swap signature now.
                 */
                error = bio_write_page(0, &swsusp_header);
-       } else { 
+       } else {
                return -EINVAL;
        }
        if (!error)
@@ -990,20 +921,25 @@ static int read_suspend_image(void)
        int error = 0;
        struct pbe *p;
 
-       if (!(p = alloc_pagedir(nr_copy_pages)))
+       if (!(p = alloc_pagedir(nr_copy_pages, GFP_ATOMIC, 0)))
                return -ENOMEM;
 
        if ((error = read_pagedir(p)))
                return error;
-
        create_pbe_list(p, nr_copy_pages);
-
-       if (!(pagedir_nosave = swsusp_pagedir_relocate(p)))
+       mark_unsafe_pages(p);
+       pagedir_nosave = alloc_pagedir(nr_copy_pages, GFP_ATOMIC, 1);
+       if (pagedir_nosave) {
+               create_pbe_list(pagedir_nosave, nr_copy_pages);
+               copy_page_backup_list(pagedir_nosave, p);
+       }
+       free_pagedir(p);
+       if (!pagedir_nosave)
                return -ENOMEM;
 
        /* Allocate memory for the image and read the data from swap */
 
-       error = check_pagedir(pagedir_nosave);
+       error = alloc_data_pages(pagedir_nosave, GFP_ATOMIC, 1);
 
        if (!error)
                error = data_read(pagedir_nosave);
index 3ce26954be1284e4f74abf0c5ca602f6d46dbef0..ac3f5cc3bb51f725bbf5b8eae5db83516a3c9dee 100644 (file)
@@ -206,6 +206,7 @@ struct runqueue {
         */
        unsigned long nr_running;
 #ifdef CONFIG_SMP
+       unsigned long prio_bias;
        unsigned long cpu_load[3];
 #endif
        unsigned long long nr_switches;
@@ -659,13 +660,68 @@ static int effective_prio(task_t *p)
        return prio;
 }
 
+#ifdef CONFIG_SMP
+static inline void inc_prio_bias(runqueue_t *rq, int prio)
+{
+       rq->prio_bias += MAX_PRIO - prio;
+}
+
+static inline void dec_prio_bias(runqueue_t *rq, int prio)
+{
+       rq->prio_bias -= MAX_PRIO - prio;
+}
+
+static inline void inc_nr_running(task_t *p, runqueue_t *rq)
+{
+       rq->nr_running++;
+       if (rt_task(p)) {
+               if (p != rq->migration_thread)
+                       /*
+                        * The migration thread does the actual balancing. Do
+                        * not bias by its priority as the ultra high priority
+                        * will skew balancing adversely.
+                        */
+                       inc_prio_bias(rq, p->prio);
+       } else
+               inc_prio_bias(rq, p->static_prio);
+}
+
+static inline void dec_nr_running(task_t *p, runqueue_t *rq)
+{
+       rq->nr_running--;
+       if (rt_task(p)) {
+               if (p != rq->migration_thread)
+                       dec_prio_bias(rq, p->prio);
+       } else
+               dec_prio_bias(rq, p->static_prio);
+}
+#else
+static inline void inc_prio_bias(runqueue_t *rq, int prio)
+{
+}
+
+static inline void dec_prio_bias(runqueue_t *rq, int prio)
+{
+}
+
+static inline void inc_nr_running(task_t *p, runqueue_t *rq)
+{
+       rq->nr_running++;
+}
+
+static inline void dec_nr_running(task_t *p, runqueue_t *rq)
+{
+       rq->nr_running--;
+}
+#endif
+
 /*
  * __activate_task - move a task to the runqueue.
  */
 static inline void __activate_task(task_t *p, runqueue_t *rq)
 {
        enqueue_task(p, rq->active);
-       rq->nr_running++;
+       inc_nr_running(p, rq);
 }
 
 /*
@@ -674,7 +730,7 @@ static inline void __activate_task(task_t *p, runqueue_t *rq)
 static inline void __activate_idle_task(task_t *p, runqueue_t *rq)
 {
        enqueue_task_head(p, rq->active);
-       rq->nr_running++;
+       inc_nr_running(p, rq);
 }
 
 static int recalc_task_prio(task_t *p, unsigned long long now)
@@ -793,7 +849,7 @@ static void activate_task(task_t *p, runqueue_t *rq, int local)
  */
 static void deactivate_task(struct task_struct *p, runqueue_t *rq)
 {
-       rq->nr_running--;
+       dec_nr_running(p, rq);
        dequeue_task(p, p->array);
        p->array = NULL;
 }
@@ -808,21 +864,28 @@ static void deactivate_task(struct task_struct *p, runqueue_t *rq)
 #ifdef CONFIG_SMP
 static void resched_task(task_t *p)
 {
-       int need_resched, nrpolling;
+       int cpu;
 
        assert_spin_locked(&task_rq(p)->lock);
 
-       /* minimise the chance of sending an interrupt to poll_idle() */
-       nrpolling = test_tsk_thread_flag(p,TIF_POLLING_NRFLAG);
-       need_resched = test_and_set_tsk_thread_flag(p,TIF_NEED_RESCHED);
-       nrpolling |= test_tsk_thread_flag(p,TIF_POLLING_NRFLAG);
+       if (unlikely(test_tsk_thread_flag(p, TIF_NEED_RESCHED)))
+               return;
+
+       set_tsk_thread_flag(p, TIF_NEED_RESCHED);
+
+       cpu = task_cpu(p);
+       if (cpu == smp_processor_id())
+               return;
 
-       if (!need_resched && !nrpolling && (task_cpu(p) != smp_processor_id()))
-               smp_send_reschedule(task_cpu(p));
+       /* NEED_RESCHED must be visible before we test POLLING_NRFLAG */
+       smp_mb();
+       if (!test_tsk_thread_flag(p, TIF_POLLING_NRFLAG))
+               smp_send_reschedule(cpu);
 }
 #else
 static inline void resched_task(task_t *p)
 {
+       assert_spin_locked(&task_rq(p)->lock);
        set_tsk_need_resched(p);
 }
 #endif
@@ -930,27 +993,61 @@ void kick_process(task_t *p)
  * We want to under-estimate the load of migration sources, to
  * balance conservatively.
  */
-static inline unsigned long source_load(int cpu, int type)
+static inline unsigned long __source_load(int cpu, int type, enum idle_type idle)
 {
        runqueue_t *rq = cpu_rq(cpu);
-       unsigned long load_now = rq->nr_running * SCHED_LOAD_SCALE;
+       unsigned long running = rq->nr_running;
+       unsigned long source_load, cpu_load = rq->cpu_load[type-1],
+               load_now = running * SCHED_LOAD_SCALE;
+
        if (type == 0)
-               return load_now;
+               source_load = load_now;
+       else
+               source_load = min(cpu_load, load_now);
 
-       return min(rq->cpu_load[type-1], load_now);
+       if (running > 1 || (idle == NOT_IDLE && running))
+               /*
+                * If we are busy rebalancing the load is biased by
+                * priority to create 'nice' support across cpus. When
+                * idle rebalancing we should only bias the source_load if
+                * there is more than one task running on that queue to
+                * prevent idle rebalance from trying to pull tasks from a
+                * queue with only one running task.
+                */
+               source_load = source_load * rq->prio_bias / running;
+
+       return source_load;
+}
+
+static inline unsigned long source_load(int cpu, int type)
+{
+       return __source_load(cpu, type, NOT_IDLE);
 }
 
 /*
  * Return a high guess at the load of a migration-target cpu
  */
-static inline unsigned long target_load(int cpu, int type)
+static inline unsigned long __target_load(int cpu, int type, enum idle_type idle)
 {
        runqueue_t *rq = cpu_rq(cpu);
-       unsigned long load_now = rq->nr_running * SCHED_LOAD_SCALE;
+       unsigned long running = rq->nr_running;
+       unsigned long target_load, cpu_load = rq->cpu_load[type-1],
+               load_now = running * SCHED_LOAD_SCALE;
+
        if (type == 0)
-               return load_now;
+               target_load = load_now;
+       else
+               target_load = max(cpu_load, load_now);
+
+       if (running > 1 || (idle == NOT_IDLE && running))
+               target_load = target_load * rq->prio_bias / running;
 
-       return max(rq->cpu_load[type-1], load_now);
+       return target_load;
+}
+
+static inline unsigned long target_load(int cpu, int type)
+{
+       return __target_load(cpu, type, NOT_IDLE);
 }
 
 /*
@@ -1411,7 +1508,7 @@ void fastcall wake_up_new_task(task_t *p, unsigned long clone_flags)
                                list_add_tail(&p->run_list, &current->run_list);
                                p->array = current->array;
                                p->array->nr_active++;
-                               rq->nr_running++;
+                               inc_nr_running(p, rq);
                        }
                        set_need_resched();
                } else
@@ -1756,9 +1853,9 @@ void pull_task(runqueue_t *src_rq, prio_array_t *src_array, task_t *p,
               runqueue_t *this_rq, prio_array_t *this_array, int this_cpu)
 {
        dequeue_task(p, src_array);
-       src_rq->nr_running--;
+       dec_nr_running(p, src_rq);
        set_task_cpu(p, this_cpu);
-       this_rq->nr_running++;
+       inc_nr_running(p, this_rq);
        enqueue_task(p, this_array);
        p->timestamp = (p->timestamp - src_rq->timestamp_last_tick)
                                + this_rq->timestamp_last_tick;
@@ -1937,9 +2034,9 @@ find_busiest_group(struct sched_domain *sd, int this_cpu,
 
                        /* Bias balancing toward cpus of our domain */
                        if (local_group)
-                               load = target_load(i, load_idx);
+                               load = __target_load(i, load_idx, idle);
                        else
-                               load = source_load(i, load_idx);
+                               load = __source_load(i, load_idx, idle);
 
                        avg_load += load;
                }
@@ -2044,14 +2141,15 @@ out_balanced:
 /*
  * find_busiest_queue - find the busiest runqueue among the cpus in group.
  */
-static runqueue_t *find_busiest_queue(struct sched_group *group)
+static runqueue_t *find_busiest_queue(struct sched_group *group,
+       enum idle_type idle)
 {
        unsigned long load, max_load = 0;
        runqueue_t *busiest = NULL;
        int i;
 
        for_each_cpu_mask(i, group->cpumask) {
-               load = source_load(i, 0);
+               load = __source_load(i, 0, idle);
 
                if (load > max_load) {
                        max_load = load;
@@ -2095,7 +2193,7 @@ static int load_balance(int this_cpu, runqueue_t *this_rq,
                goto out_balanced;
        }
 
-       busiest = find_busiest_queue(group);
+       busiest = find_busiest_queue(group, idle);
        if (!busiest) {
                schedstat_inc(sd, lb_nobusyq[idle]);
                goto out_balanced;
@@ -2218,7 +2316,7 @@ static int load_balance_newidle(int this_cpu, runqueue_t *this_rq,
                goto out_balanced;
        }
 
-       busiest = find_busiest_queue(group);
+       busiest = find_busiest_queue(group, NEWLY_IDLE);
        if (!busiest) {
                schedstat_inc(sd, lb_nobusyq[NEWLY_IDLE]);
                goto out_balanced;
@@ -3451,8 +3549,10 @@ void set_user_nice(task_t *p, long nice)
                goto out_unlock;
        }
        array = p->array;
-       if (array)
+       if (array) {
                dequeue_task(p, array);
+               dec_prio_bias(rq, p->static_prio);
+       }
 
        old_prio = p->prio;
        new_prio = NICE_TO_PRIO(nice);
@@ -3462,6 +3562,7 @@ void set_user_nice(task_t *p, long nice)
 
        if (array) {
                enqueue_task(p, array);
+               inc_prio_bias(rq, p->static_prio);
                /*
                 * If the task increased its priority or is running and
                 * lowered its priority, then reschedule its CPU:
index a2dcceb9437d61561caf1f85b0099cd4cd9e262d..c67189a25d52efbd2aa6afdf0655cfe860971189 100644 (file)
@@ -73,9 +73,6 @@ void softlockup_tick(struct pt_regs *regs)
 static int watchdog(void * __bind_cpu)
 {
        struct sched_param param = { .sched_priority = 99 };
-       int this_cpu = (long) __bind_cpu;
-
-       printk("softlockup thread %d started up.\n", this_cpu);
 
        sched_setscheduler(current, SCHED_FIFO, &param);
        current->flags |= PF_NOFREEZE;
index c4f35f96884df814c665d0287eba465033d9eabe..9990e10192e8e645c62d1e640b67b48edefe762d 100644 (file)
@@ -169,7 +169,7 @@ struct file_operations proc_sys_file_operations = {
 
 extern struct proc_dir_entry *proc_sys_root;
 
-static void register_proc_table(ctl_table *, struct proc_dir_entry *);
+static void register_proc_table(ctl_table *, struct proc_dir_entry *, void *);
 static void unregister_proc_table(ctl_table *, struct proc_dir_entry *);
 #endif
 
@@ -992,10 +992,51 @@ static ctl_table dev_table[] = {
 
 extern void init_irq_proc (void);
 
+static DEFINE_SPINLOCK(sysctl_lock);
+
+/* called under sysctl_lock */
+static int use_table(struct ctl_table_header *p)
+{
+       if (unlikely(p->unregistering))
+               return 0;
+       p->used++;
+       return 1;
+}
+
+/* called under sysctl_lock */
+static void unuse_table(struct ctl_table_header *p)
+{
+       if (!--p->used)
+               if (unlikely(p->unregistering))
+                       complete(p->unregistering);
+}
+
+/* called under sysctl_lock, will reacquire if has to wait */
+static void start_unregistering(struct ctl_table_header *p)
+{
+       /*
+        * if p->used is 0, nobody will ever touch that entry again;
+        * we'll eliminate all paths to it before dropping sysctl_lock
+        */
+       if (unlikely(p->used)) {
+               struct completion wait;
+               init_completion(&wait);
+               p->unregistering = &wait;
+               spin_unlock(&sysctl_lock);
+               wait_for_completion(&wait);
+               spin_lock(&sysctl_lock);
+       }
+       /*
+        * do not remove from the list until nobody holds it; walking the
+        * list in do_sysctl() relies on that.
+        */
+       list_del_init(&p->ctl_entry);
+}
+
 void __init sysctl_init(void)
 {
 #ifdef CONFIG_PROC_FS
-       register_proc_table(root_table, proc_sys_root);
+       register_proc_table(root_table, proc_sys_root, &root_table_header);
        init_irq_proc();
 #endif
 }
@@ -1004,6 +1045,7 @@ int do_sysctl(int __user *name, int nlen, void __user *oldval, size_t __user *ol
               void __user *newval, size_t newlen)
 {
        struct list_head *tmp;
+       int error = -ENOTDIR;
 
        if (nlen <= 0 || nlen >= CTL_MAXNAME)
                return -ENOTDIR;
@@ -1012,20 +1054,30 @@ int do_sysctl(int __user *name, int nlen, void __user *oldval, size_t __user *ol
                if (!oldlenp || get_user(old_len, oldlenp))
                        return -EFAULT;
        }
+       spin_lock(&sysctl_lock);
        tmp = &root_table_header.ctl_entry;
        do {
                struct ctl_table_header *head =
                        list_entry(tmp, struct ctl_table_header, ctl_entry);
                void *context = NULL;
-               int error = parse_table(name, nlen, oldval, oldlenp, 
+
+               if (!use_table(head))
+                       continue;
+
+               spin_unlock(&sysctl_lock);
+
+               error = parse_table(name, nlen, oldval, oldlenp, 
                                        newval, newlen, head->ctl_table,
                                        &context);
                kfree(context);
+
+               spin_lock(&sysctl_lock);
+               unuse_table(head);
                if (error != -ENOTDIR)
-                       return error;
-               tmp = tmp->next;
-       } while (tmp != &root_table_header.ctl_entry);
-       return -ENOTDIR;
+                       break;
+       } while ((tmp = tmp->next) != &root_table_header.ctl_entry);
+       spin_unlock(&sysctl_lock);
+       return error;
 }
 
 asmlinkage long sys_sysctl(struct __sysctl_args __user *args)
@@ -1236,12 +1288,16 @@ struct ctl_table_header *register_sysctl_table(ctl_table * table,
                return NULL;
        tmp->ctl_table = table;
        INIT_LIST_HEAD(&tmp->ctl_entry);
+       tmp->used = 0;
+       tmp->unregistering = NULL;
+       spin_lock(&sysctl_lock);
        if (insert_at_head)
                list_add(&tmp->ctl_entry, &root_table_header.ctl_entry);
        else
                list_add_tail(&tmp->ctl_entry, &root_table_header.ctl_entry);
+       spin_unlock(&sysctl_lock);
 #ifdef CONFIG_PROC_FS
-       register_proc_table(table, proc_sys_root);
+       register_proc_table(table, proc_sys_root, tmp);
 #endif
        return tmp;
 }
@@ -1255,10 +1311,13 @@ struct ctl_table_header *register_sysctl_table(ctl_table * table,
  */
 void unregister_sysctl_table(struct ctl_table_header * header)
 {
-       list_del(&header->ctl_entry);
+       might_sleep();
+       spin_lock(&sysctl_lock);
+       start_unregistering(header);
 #ifdef CONFIG_PROC_FS
        unregister_proc_table(header->ctl_table, proc_sys_root);
 #endif
+       spin_unlock(&sysctl_lock);
        kfree(header);
 }
 
@@ -1269,7 +1328,7 @@ void unregister_sysctl_table(struct ctl_table_header * header)
 #ifdef CONFIG_PROC_FS
 
 /* Scan the sysctl entries in table and add them all into /proc */
-static void register_proc_table(ctl_table * table, struct proc_dir_entry *root)
+static void register_proc_table(ctl_table * table, struct proc_dir_entry *root, void *set)
 {
        struct proc_dir_entry *de;
        int len;
@@ -1305,13 +1364,14 @@ static void register_proc_table(ctl_table * table, struct proc_dir_entry *root)
                        de = create_proc_entry(table->procname, mode, root);
                        if (!de)
                                continue;
+                       de->set = set;
                        de->data = (void *) table;
                        if (table->proc_handler)
                                de->proc_fops = &proc_sys_file_operations;
                }
                table->de = de;
                if (de->mode & S_IFDIR)
-                       register_proc_table(table->child, de);
+                       register_proc_table(table->child, de, set);
        }
 }
 
@@ -1336,6 +1396,13 @@ static void unregister_proc_table(ctl_table * table, struct proc_dir_entry *root
                                continue;
                }
 
+               /*
+                * In any case, mark the entry as goner; we'll keep it
+                * around if it's busy, but we'll know to do nothing with
+                * its fields.  We are under sysctl_lock here.
+                */
+               de->data = NULL;
+
                /* Don't unregister proc entries that are still being used.. */
                if (atomic_read(&de->count))
                        continue;
@@ -1349,27 +1416,38 @@ static ssize_t do_rw_proc(int write, struct file * file, char __user * buf,
                          size_t count, loff_t *ppos)
 {
        int op;
-       struct proc_dir_entry *de;
+       struct proc_dir_entry *de = PDE(file->f_dentry->d_inode);
        struct ctl_table *table;
        size_t res;
-       ssize_t error;
-       
-       de = PDE(file->f_dentry->d_inode);
-       if (!de || !de->data)
-               return -ENOTDIR;
-       table = (struct ctl_table *) de->data;
-       if (!table || !table->proc_handler)
-               return -ENOTDIR;
-       op = (write ? 002 : 004);
-       if (ctl_perm(table, op))
-               return -EPERM;
+       ssize_t error = -ENOTDIR;
        
-       res = count;
-
-       error = (*table->proc_handler) (table, write, file, buf, &res, ppos);
-       if (error)
-               return error;
-       return res;
+       spin_lock(&sysctl_lock);
+       if (de && de->data && use_table(de->set)) {
+               /*
+                * at that point we know that sysctl was not unregistered
+                * and won't be until we finish
+                */
+               spin_unlock(&sysctl_lock);
+               table = (struct ctl_table *) de->data;
+               if (!table || !table->proc_handler)
+                       goto out;
+               error = -EPERM;
+               op = (write ? 002 : 004);
+               if (ctl_perm(table, op))
+                       goto out;
+               
+               /* careful: calling conventions are nasty here */
+               res = count;
+               error = (*table->proc_handler)(table, write, file,
+                                               buf, &res, ppos);
+               if (!error)
+                       error = res;
+       out:
+               spin_lock(&sysctl_lock);
+               unuse_table(de->set);
+       }
+       spin_unlock(&sysctl_lock);
+       return error;
 }
 
 static int proc_opensys(struct inode *inode, struct file *file)
index 6368d3dce444489ea41e654067aa92c012c0b924..d23e906456eb373ccbbd5ead89270ff198ceaf2e 100644 (file)
@@ -54,8 +54,7 @@ struct datalink_proto *make_8023_client(void)
  */
 void destroy_8023_client(struct datalink_proto *dl)
 {
-       if (dl)
-               kfree(dl);
+       kfree(dl);
 }
 
 EXPORT_SYMBOL(destroy_8023_client);
index 8e37e71e34ff1929aef5a8b8efb2ef362dec6b54..1b683f302657d376f438b8f9ea68805bdd14118c 100644 (file)
@@ -1138,10 +1138,8 @@ static int ax25_connect(struct socket *sock, struct sockaddr *uaddr,
        sk->sk_state   = TCP_CLOSE;
        sock->state = SS_UNCONNECTED;
 
-       if (ax25->digipeat != NULL) {
-               kfree(ax25->digipeat);
-               ax25->digipeat = NULL;
-       }
+       kfree(ax25->digipeat);
+       ax25->digipeat = NULL;
 
        /*
         *      Handle digi-peaters to be used.
index 73cfc3411c461d50d7dbb7d718dd3e2315d26428..4cf87540fb3abd79df222319a9c79e3dc09f2e3d 100644 (file)
@@ -401,10 +401,8 @@ static int ax25_rcv(struct sk_buff *skb, struct net_device *dev,
        }
 
        if (dp.ndigi == 0) {
-               if (ax25->digipeat != NULL) {
-                       kfree(ax25->digipeat);
-                       ax25->digipeat = NULL;
-               }
+               kfree(ax25->digipeat);
+               ax25->digipeat = NULL;
        } else {
                /* Reverse the source SABM's path */
                memcpy(ax25->digipeat, &reverse_dp, sizeof(ax25_digi));
index 26b77d9722201232d7adfcb2bb27dcc3fb90e246..b1e945bd6ed3d0f22e1a306303ad32ca4a471cc6 100644 (file)
@@ -54,15 +54,13 @@ void ax25_rt_device_down(struct net_device *dev)
                if (s->dev == dev) {
                        if (ax25_route_list == s) {
                                ax25_route_list = s->next;
-                               if (s->digipeat != NULL)
-                                       kfree(s->digipeat);
+                               kfree(s->digipeat);
                                kfree(s);
                        } else {
                                for (t = ax25_route_list; t != NULL; t = t->next) {
                                        if (t->next == s) {
                                                t->next = s->next;
-                                               if (s->digipeat != NULL)
-                                                       kfree(s->digipeat);
+                                               kfree(s->digipeat);
                                                kfree(s);
                                                break;
                                        }
@@ -90,10 +88,8 @@ static int ax25_rt_add(struct ax25_routes_struct *route)
        while (ax25_rt != NULL) {
                if (ax25cmp(&ax25_rt->callsign, &route->dest_addr) == 0 &&
                            ax25_rt->dev == ax25_dev->dev) {
-                       if (ax25_rt->digipeat != NULL) {
-                               kfree(ax25_rt->digipeat);
-                               ax25_rt->digipeat = NULL;
-                       }
+                       kfree(ax25_rt->digipeat);
+                       ax25_rt->digipeat = NULL;
                        if (route->digi_count != 0) {
                                if ((ax25_rt->digipeat = kmalloc(sizeof(ax25_digi), GFP_ATOMIC)) == NULL) {
                                        write_unlock(&ax25_route_lock);
@@ -145,8 +141,7 @@ static int ax25_rt_add(struct ax25_routes_struct *route)
 static void ax25_rt_destroy(ax25_route *ax25_rt)
 {
        if (atomic_read(&ax25_rt->ref) == 0) {
-               if (ax25_rt->digipeat != NULL)
-                       kfree(ax25_rt->digipeat);
+               kfree(ax25_rt->digipeat);
                kfree(ax25_rt);
                return;
        }
@@ -530,9 +525,7 @@ void __exit ax25_rt_free(void)
                s       = ax25_rt;
                ax25_rt = ax25_rt->next;
 
-               if (s->digipeat != NULL)
-                       kfree(s->digipeat);
-
+               kfree(s->digipeat);
                kfree(s);
        }
        write_unlock(&ax25_route_lock);
index 03532062a46a9168b662abad180a2e2347017e9d..ea616e3fc98e73f3806a5dc04e9770b6fba38425 100644 (file)
@@ -36,7 +36,6 @@
 #include <linux/skbuff.h>
 #include <linux/init.h>
 #include <linux/poll.h>
-#include <linux/proc_fs.h>
 #include <net/sock.h>
 
 #if defined(CONFIG_KMOD)
 #define BT_DBG(D...)
 #endif
 
-#define VERSION "2.7"
-
-struct proc_dir_entry *proc_bt;
-EXPORT_SYMBOL(proc_bt);
+#define VERSION "2.8"
 
 /* Bluetooth sockets */
 #define BT_MAX_PROTO   8
@@ -312,10 +308,6 @@ static int __init bt_init(void)
 {
        BT_INFO("Core ver %s", VERSION);
 
-       proc_bt = proc_mkdir("bluetooth", NULL);
-       if (proc_bt)
-               proc_bt->owner = THIS_MODULE;
-
        sock_register(&bt_sock_family_ops);
 
        BT_INFO("HCI device and connection manager initialized");
@@ -334,8 +326,6 @@ static void __exit bt_exit(void)
        bt_sysfs_cleanup();
 
        sock_unregister(PF_BLUETOOTH);
-
-       remove_proc_entry("bluetooth", NULL);
 }
 
 subsys_initcall(bt_init);
index cf0df1c8c933c0f346b50f77578ba92f636d99a4..9106354c781e68c868d1830bec83c4312d1ccd04 100644 (file)
@@ -183,7 +183,7 @@ static void hci_reset_req(struct hci_dev *hdev, unsigned long opt)
 static void hci_init_req(struct hci_dev *hdev, unsigned long opt)
 {
        struct sk_buff *skb;
-       __u16 param;
+       __le16 param;
 
        BT_DBG("%s %ld", hdev->name, opt);
 
index b61b4e8e36fdab2bd7c555acdfb7a93f23de5e14..eb64555d1fb346d90ff34dad9ed16ef4700d0fdc 100644 (file)
@@ -242,7 +242,7 @@ static void hci_cc_host_ctl(struct hci_dev *hdev, __u16 ocf, struct sk_buff *skb
                        break;
 
                status = *((__u8 *) skb->data);
-               setting = __le16_to_cpu(get_unaligned((__u16 *) sent));
+               setting = __le16_to_cpu(get_unaligned((__le16 *) sent));
 
                if (!status && hdev->voice_setting != setting) {
                        hdev->voice_setting = setting;
@@ -728,7 +728,7 @@ static inline void hci_disconn_complete_evt(struct hci_dev *hdev, struct sk_buff
 static inline void hci_num_comp_pkts_evt(struct hci_dev *hdev, struct sk_buff *skb)
 {
        struct hci_ev_num_comp_pkts *ev = (struct hci_ev_num_comp_pkts *) skb->data;
-       __u16 *ptr;
+       __le16 *ptr;
        int i;
 
        skb_pull(skb, sizeof(*ev));
@@ -742,7 +742,7 @@ static inline void hci_num_comp_pkts_evt(struct hci_dev *hdev, struct sk_buff *s
 
        tasklet_disable(&hdev->tx_task);
 
-       for (i = 0, ptr = (__u16 *) skb->data; i < ev->num_hndl; i++) {
+       for (i = 0, ptr = (__le16 *) skb->data; i < ev->num_hndl; i++) {
                struct hci_conn *conn;
                __u16  handle, count;
 
index 799e448750ad906114c85c3a908e10ab44ec7cb4..1d6d0a15c099a8c4e8f38a63ed78925c0c6f827e 100644 (file)
@@ -416,7 +416,7 @@ static int hci_sock_sendmsg(struct kiocb *iocb, struct socket *sock,
        skb->dev = (void *) hdev;
 
        if (bt_cb(skb)->pkt_type == HCI_COMMAND_PKT) {
-               u16 opcode = __le16_to_cpu(get_unaligned((u16 *)skb->data));
+               u16 opcode = __le16_to_cpu(get_unaligned((__le16 *) skb->data));
                u16 ogf = hci_opcode_ogf(opcode);
                u16 ocf = hci_opcode_ocf(opcode);
 
index 7856bc26accb2acf6bdc28f9aaa91b6acee89667..bd7568ac87fc5ad7883e19cdd63b2dfb98193760 100644 (file)
@@ -103,7 +103,7 @@ static void bt_release(struct class_device *cdev)
        kfree(hdev);
 }
 
-static struct class bt_class = {
+struct class bt_class = {
        .name           = "bluetooth",
        .release        = bt_release,
 #ifdef CONFIG_HOTPLUG
@@ -111,6 +111,8 @@ static struct class bt_class = {
 #endif
 };
 
+EXPORT_SYMBOL_GPL(bt_class);
+
 int hci_register_sysfs(struct hci_dev *hdev)
 {
        struct class_device *cdev = &hdev->class_dev;
index 860444a7fc0f8e1e014f063721ecdc221a365304..cdb9cfafd960b5c45730b933f0515e1b79f1bfd4 100644 (file)
@@ -660,9 +660,7 @@ unlink:
 failed:
        up_write(&hidp_session_sem);
 
-       if (session->input)
-               kfree(session->input);
-
+       kfree(session->input);
        kfree(session);
        return err;
 }
index 59b2dd36baa77e1414177e1363cb697f2feebbc6..e3bb11ca4235562af24b7748873ef8de5ba1d362 100644 (file)
@@ -38,9 +38,8 @@
 #include <linux/interrupt.h>
 #include <linux/socket.h>
 #include <linux/skbuff.h>
-#include <linux/proc_fs.h>
-#include <linux/seq_file.h>
 #include <linux/list.h>
+#include <linux/device.h>
 #include <net/sock.h>
 
 #include <asm/system.h>
@@ -56,7 +55,7 @@
 #define BT_DBG(D...)
 #endif
 
-#define VERSION "2.7"
+#define VERSION "2.8"
 
 static struct proto_ops l2cap_sock_ops;
 
@@ -2137,94 +2136,29 @@ drop:
        return 0;
 }
 
-/* ---- Proc fs support ---- */
-#ifdef CONFIG_PROC_FS
-static void *l2cap_seq_start(struct seq_file *seq, loff_t *pos)
+static ssize_t l2cap_sysfs_show(struct class *dev, char *buf)
 {
        struct sock *sk;
        struct hlist_node *node;
-       loff_t l = *pos;
+       char *str = buf;
 
        read_lock_bh(&l2cap_sk_list.lock);
 
-       sk_for_each(sk, node, &l2cap_sk_list.head)
-               if (!l--)
-                       goto found;
-       sk = NULL;
-found:
-       return sk;
-}
+       sk_for_each(sk, node, &l2cap_sk_list.head) {
+               struct l2cap_pinfo *pi = l2cap_pi(sk);
 
-static void *l2cap_seq_next(struct seq_file *seq, void *e, loff_t *pos)
-{
-       (*pos)++;
-       return sk_next(e);
-}
+               str += sprintf(str, "%s %s %d %d 0x%4.4x 0x%4.4x %d %d 0x%x\n",
+                               batostr(&bt_sk(sk)->src), batostr(&bt_sk(sk)->dst),
+                               sk->sk_state, pi->psm, pi->scid, pi->dcid, pi->imtu,
+                               pi->omtu, pi->link_mode);
+       }
 
-static void l2cap_seq_stop(struct seq_file *seq, void *e)
-{
        read_unlock_bh(&l2cap_sk_list.lock);
-}
 
-static int  l2cap_seq_show(struct seq_file *seq, void *e)
-{
-       struct sock *sk = e;
-       struct l2cap_pinfo *pi = l2cap_pi(sk);
-
-       seq_printf(seq, "%s %s %d %d 0x%4.4x 0x%4.4x %d %d 0x%x\n",
-                       batostr(&bt_sk(sk)->src), batostr(&bt_sk(sk)->dst), 
-                       sk->sk_state, pi->psm, pi->scid, pi->dcid, pi->imtu,
-                       pi->omtu, pi->link_mode);
-       return 0;
+       return (str - buf);
 }
 
-static struct seq_operations l2cap_seq_ops = {
-       .start  = l2cap_seq_start,
-       .next   = l2cap_seq_next,
-       .stop   = l2cap_seq_stop,
-       .show   = l2cap_seq_show 
-};
-
-static int l2cap_seq_open(struct inode *inode, struct file *file)
-{
-       return seq_open(file, &l2cap_seq_ops);
-}
-
-static struct file_operations l2cap_seq_fops = {
-       .owner          = THIS_MODULE,
-       .open           = l2cap_seq_open,
-       .read           = seq_read,
-       .llseek         = seq_lseek,
-       .release        = seq_release,
-};
-
-static int __init l2cap_proc_init(void)
-{
-       struct proc_dir_entry *p = create_proc_entry("l2cap", S_IRUGO, proc_bt);
-       if (!p)
-               return -ENOMEM;
-       p->owner     = THIS_MODULE;
-       p->proc_fops = &l2cap_seq_fops;
-       return 0;
-}
-
-static void __exit l2cap_proc_cleanup(void)
-{
-       remove_proc_entry("l2cap", proc_bt);
-}
-
-#else /* CONFIG_PROC_FS */
-
-static int __init l2cap_proc_init(void)
-{
-       return 0;
-}
-
-static void __exit l2cap_proc_cleanup(void)
-{
-       return;
-}
-#endif /* CONFIG_PROC_FS */
+static CLASS_ATTR(l2cap, S_IRUGO, l2cap_sysfs_show, NULL);
 
 static struct proto_ops l2cap_sock_ops = {
        .family         = PF_BLUETOOTH,
@@ -2266,7 +2200,7 @@ static struct hci_proto l2cap_hci_proto = {
 static int __init l2cap_init(void)
 {
        int err;
-       
+
        err = proto_register(&l2cap_proto, 0);
        if (err < 0)
                return err;
@@ -2284,7 +2218,7 @@ static int __init l2cap_init(void)
                goto error;
        }
 
-       l2cap_proc_init();
+       class_create_file(&bt_class, &class_attr_l2cap);
 
        BT_INFO("L2CAP ver %s", VERSION);
        BT_INFO("L2CAP socket layer initialized");
@@ -2298,7 +2232,7 @@ error:
 
 static void __exit l2cap_exit(void)
 {
-       l2cap_proc_cleanup();
+       class_remove_file(&bt_class, &class_attr_l2cap);
 
        if (bt_sock_unregister(BTPROTO_L2CAP) < 0)
                BT_ERR("L2CAP socket unregistration failed");
index c3d56ead840cbb42cbfc6814e32fed1ff83de066..0d89d64341364fcf9e6eb4214568c24795ea6a51 100644 (file)
@@ -35,9 +35,8 @@
 #include <linux/signal.h>
 #include <linux/init.h>
 #include <linux/wait.h>
+#include <linux/device.h>
 #include <linux/net.h>
-#include <linux/proc_fs.h>
-#include <linux/seq_file.h>
 #include <net/sock.h>
 #include <asm/uaccess.h>
 #include <asm/unaligned.h>
 #include <net/bluetooth/l2cap.h>
 #include <net/bluetooth/rfcomm.h>
 
-#define VERSION "1.5"
+#define VERSION "1.6"
 
 #ifndef CONFIG_BT_RFCOMM_DEBUG
 #undef  BT_DBG
 #define BT_DBG(D...)
 #endif
 
-#ifdef CONFIG_PROC_FS
-struct proc_dir_entry *proc_bt_rfcomm;
-#endif
-
 static struct task_struct *rfcomm_thread;
 
 static DECLARE_MUTEX(rfcomm_sem);
@@ -2001,117 +1996,32 @@ static struct hci_cb rfcomm_cb = {
        .encrypt_cfm    = rfcomm_encrypt_cfm
 };
 
-/* ---- Proc fs support ---- */
-#ifdef CONFIG_PROC_FS
-static void *rfcomm_seq_start(struct seq_file *seq, loff_t *pos)
+static ssize_t rfcomm_dlc_sysfs_show(struct class *dev, char *buf)
 {
        struct rfcomm_session *s;
        struct list_head *pp, *p;
-       loff_t l = *pos;
+       char *str = buf;
 
        rfcomm_lock();
 
        list_for_each(p, &session_list) {
                s = list_entry(p, struct rfcomm_session, list);
-               list_for_each(pp, &s->dlcs)
-                       if (!l--) {
-                               seq->private = s;
-                               return pp;
-                       }
-       }
-       return NULL;
-}
+               list_for_each(pp, &s->dlcs) {
+                       struct sock *sk = s->sock->sk;
+                       struct rfcomm_dlc *d = list_entry(pp, struct rfcomm_dlc, list);
 
-static void *rfcomm_seq_next(struct seq_file *seq, void *e, loff_t *pos)
-{
-       struct rfcomm_session *s = seq->private;
-       struct list_head *pp, *p = e;
-       (*pos)++;
-
-       if (p->next != &s->dlcs)
-               return p->next;
-
-       list_for_each(p, &session_list) {
-               s = list_entry(p, struct rfcomm_session, list);
-               __list_for_each(pp, &s->dlcs) {
-                       seq->private = s;
-                       return pp;
+                       str += sprintf(str, "%s %s %ld %d %d %d %d\n",
+                                       batostr(&bt_sk(sk)->src), batostr(&bt_sk(sk)->dst),
+                                       d->state, d->dlci, d->mtu, d->rx_credits, d->tx_credits);
                }
        }
-       return NULL;
-}
 
-static void rfcomm_seq_stop(struct seq_file *seq, void *e)
-{
        rfcomm_unlock();
-}
-
-static int  rfcomm_seq_show(struct seq_file *seq, void *e)
-{
-       struct rfcomm_session *s = seq->private;
-       struct sock *sk = s->sock->sk;
-       struct rfcomm_dlc *d = list_entry(e, struct rfcomm_dlc, list);
-
-       seq_printf(seq, "%s %s %ld %d %d %d %d\n",
-                       batostr(&bt_sk(sk)->src), batostr(&bt_sk(sk)->dst),
-                       d->state, d->dlci, d->mtu, d->rx_credits, d->tx_credits);
-       return 0;
-}
-
-static struct seq_operations rfcomm_seq_ops = {
-       .start  = rfcomm_seq_start,
-       .next   = rfcomm_seq_next,
-       .stop   = rfcomm_seq_stop,
-       .show   = rfcomm_seq_show 
-};
-
-static int rfcomm_seq_open(struct inode *inode, struct file *file)
-{
-       return seq_open(file, &rfcomm_seq_ops);
-}
-
-static struct file_operations rfcomm_seq_fops = {
-       .owner   = THIS_MODULE,
-       .open    = rfcomm_seq_open,
-       .read    = seq_read,
-       .llseek  = seq_lseek,
-       .release = seq_release,
-};
-
-static int  __init rfcomm_proc_init(void)
-{
-        struct proc_dir_entry *p;
-
-       proc_bt_rfcomm = proc_mkdir("rfcomm", proc_bt);
-       if (proc_bt_rfcomm) {
-               proc_bt_rfcomm->owner = THIS_MODULE;
-
-               p = create_proc_entry("dlc", S_IRUGO, proc_bt_rfcomm);
-               if (p)
-                       p->proc_fops = &rfcomm_seq_fops;
-       }
-        return 0;
-}
-
-static void __exit rfcomm_proc_cleanup(void)
-{
-        remove_proc_entry("dlc", proc_bt_rfcomm);
 
-       remove_proc_entry("rfcomm", proc_bt);
+       return (str - buf);
 }
 
-#else /* CONFIG_PROC_FS */
-
-static int  __init rfcomm_proc_init(void)
-{
-        return 0;
-}
-
-static void __exit rfcomm_proc_cleanup(void)
-{
-        return;
-}
-#endif /* CONFIG_PROC_FS */
+static CLASS_ATTR(rfcomm_dlc, S_IRUGO, rfcomm_dlc_sysfs_show, NULL);
 
 /* ---- Initialization ---- */
 static int __init rfcomm_init(void)
@@ -2122,9 +2032,7 @@ static int __init rfcomm_init(void)
 
        kernel_thread(rfcomm_run, NULL, CLONE_KERNEL);
 
-       BT_INFO("RFCOMM ver %s", VERSION);
-
-       rfcomm_proc_init();
+       class_create_file(&bt_class, &class_attr_rfcomm_dlc);
 
        rfcomm_init_sockets();
 
@@ -2132,11 +2040,15 @@ static int __init rfcomm_init(void)
        rfcomm_init_ttys();
 #endif
 
+       BT_INFO("RFCOMM ver %s", VERSION);
+
        return 0;
 }
 
 static void __exit rfcomm_exit(void)
 {
+       class_remove_file(&bt_class, &class_attr_rfcomm_dlc);
+
        hci_unregister_cb(&rfcomm_cb);
 
        /* Terminate working thread.
@@ -2153,8 +2065,6 @@ static void __exit rfcomm_exit(void)
 #endif
 
        rfcomm_cleanup_sockets();
-
-       rfcomm_proc_cleanup();
 }
 
 module_init(rfcomm_init);
index a2b30f0aedb7b4bc586cdabc141c392fc6eca775..6c34261b232e4cd2d9d0b254e7ae8701a3dfd021 100644 (file)
@@ -42,8 +42,7 @@
 #include <linux/socket.h>
 #include <linux/skbuff.h>
 #include <linux/list.h>
-#include <linux/proc_fs.h>
-#include <linux/seq_file.h>
+#include <linux/device.h>
 #include <net/sock.h>
 
 #include <asm/system.h>
@@ -887,89 +886,26 @@ done:
        return result;
 }
 
-/* ---- Proc fs support ---- */
-#ifdef CONFIG_PROC_FS
-static void *rfcomm_seq_start(struct seq_file *seq, loff_t *pos)
+static ssize_t rfcomm_sock_sysfs_show(struct class *dev, char *buf)
 {
        struct sock *sk;
        struct hlist_node *node;
-       loff_t l = *pos;
+       char *str = buf;
 
        read_lock_bh(&rfcomm_sk_list.lock);
 
-       sk_for_each(sk, node, &rfcomm_sk_list.head)
-               if (!l--)
-                       return sk;
-       return NULL;
-}
-
-static void *rfcomm_seq_next(struct seq_file *seq, void *e, loff_t *pos)
-{
-       struct sock *sk = e;
-       (*pos)++;
-       return sk_next(sk);
-}
+       sk_for_each(sk, node, &rfcomm_sk_list.head) {
+               str += sprintf(str, "%s %s %d %d\n",
+                               batostr(&bt_sk(sk)->src), batostr(&bt_sk(sk)->dst),
+                               sk->sk_state, rfcomm_pi(sk)->channel);
+       }
 
-static void rfcomm_seq_stop(struct seq_file *seq, void *e)
-{
        read_unlock_bh(&rfcomm_sk_list.lock);
-}
 
-static int  rfcomm_seq_show(struct seq_file *seq, void *e)
-{
-       struct sock *sk = e;
-       seq_printf(seq, "%s %s %d %d\n",
-                       batostr(&bt_sk(sk)->src), batostr(&bt_sk(sk)->dst),
-                       sk->sk_state, rfcomm_pi(sk)->channel);
-       return 0;
-}
-
-static struct seq_operations rfcomm_seq_ops = {
-       .start  = rfcomm_seq_start,
-       .next   = rfcomm_seq_next,
-       .stop   = rfcomm_seq_stop,
-       .show   = rfcomm_seq_show 
-};
-
-static int rfcomm_seq_open(struct inode *inode, struct file *file)
-{
-       return seq_open(file, &rfcomm_seq_ops);
+       return (str - buf);
 }
 
-static struct file_operations rfcomm_seq_fops = {
-       .owner   = THIS_MODULE,
-       .open    = rfcomm_seq_open,
-       .read    = seq_read,
-       .llseek  = seq_lseek,
-       .release = seq_release,
-};
-
-static int  __init rfcomm_sock_proc_init(void)
-{
-        struct proc_dir_entry *p = create_proc_entry("sock", S_IRUGO, proc_bt_rfcomm);
-        if (!p)
-                return -ENOMEM;
-        p->proc_fops = &rfcomm_seq_fops;
-        return 0;
-}
-
-static void __exit rfcomm_sock_proc_cleanup(void)
-{
-        remove_proc_entry("sock", proc_bt_rfcomm);
-}
-
-#else /* CONFIG_PROC_FS */
-
-static int  __init rfcomm_sock_proc_init(void)
-{
-        return 0;
-}
-
-static void __exit rfcomm_sock_proc_cleanup(void)
-{
-        return;
-}
-#endif /* CONFIG_PROC_FS */
+static CLASS_ATTR(rfcomm, S_IRUGO, rfcomm_sock_sysfs_show, NULL);
 
 static struct proto_ops rfcomm_sock_ops = {
        .family         = PF_BLUETOOTH,
@@ -997,7 +933,7 @@ static struct net_proto_family rfcomm_sock_family_ops = {
        .create         = rfcomm_sock_create
 };
 
-int  __init rfcomm_init_sockets(void)
+int __init rfcomm_init_sockets(void)
 {
        int err;
 
@@ -1009,7 +945,7 @@ int  __init rfcomm_init_sockets(void)
        if (err < 0)
                goto error;
 
-       rfcomm_sock_proc_init();
+       class_create_file(&bt_class, &class_attr_rfcomm);
 
        BT_INFO("RFCOMM socket layer initialized");
 
@@ -1023,7 +959,7 @@ error:
 
 void __exit rfcomm_cleanup_sockets(void)
 {
-       rfcomm_sock_proc_cleanup();
+       class_remove_file(&bt_class, &class_attr_rfcomm);
 
        if (bt_sock_unregister(BTPROTO_RFCOMM) < 0)
                BT_ERR("RFCOMM socket layer unregistration failed");
index 997e42df115c5f6eba7be27fa4ec02883eb42a56..9cb00dc6c08c6d18b4cf1031a4405e144d1f69c0 100644 (file)
@@ -38,8 +38,7 @@
 #include <linux/interrupt.h>
 #include <linux/socket.h>
 #include <linux/skbuff.h>
-#include <linux/proc_fs.h>
-#include <linux/seq_file.h>
+#include <linux/device.h>
 #include <linux/list.h>
 #include <net/sock.h>
 
@@ -55,7 +54,7 @@
 #define BT_DBG(D...)
 #endif
 
-#define VERSION "0.4"
+#define VERSION "0.5"
 
 static struct proto_ops sco_sock_ops;
 
@@ -893,91 +892,26 @@ drop:
        return 0;
 }
 
-/* ---- Proc fs support ---- */
-#ifdef CONFIG_PROC_FS
-static void *sco_seq_start(struct seq_file *seq, loff_t *pos)
+static ssize_t sco_sysfs_show(struct class *dev, char *buf)
 {
        struct sock *sk;
        struct hlist_node *node;
-       loff_t l = *pos;
+       char *str = buf;
 
        read_lock_bh(&sco_sk_list.lock);
 
-       sk_for_each(sk, node, &sco_sk_list.head)
-               if (!l--)
-                       goto found;
-       sk = NULL;
-found:
-       return sk;
-}
-
-static void *sco_seq_next(struct seq_file *seq, void *e, loff_t *pos)
-{
-       struct sock *sk = e;
-       (*pos)++;
-       return sk_next(sk);
-}
+       sk_for_each(sk, node, &sco_sk_list.head) {
+               str += sprintf(str, "%s %s %d\n",
+                               batostr(&bt_sk(sk)->src), batostr(&bt_sk(sk)->dst),
+                               sk->sk_state);
+       }
 
-static void sco_seq_stop(struct seq_file *seq, void *e)
-{
        read_unlock_bh(&sco_sk_list.lock);
-}
-
-static int  sco_seq_show(struct seq_file *seq, void *e)
-{
-       struct sock *sk = e;
-       seq_printf(seq, "%s %s %d\n",
-                       batostr(&bt_sk(sk)->src), batostr(&bt_sk(sk)->dst), sk->sk_state);
-       return 0;
-}
 
-static struct seq_operations sco_seq_ops = {
-       .start  = sco_seq_start,
-       .next   = sco_seq_next,
-       .stop   = sco_seq_stop,
-       .show   = sco_seq_show 
-};
-
-static int sco_seq_open(struct inode *inode, struct file *file)
-{
-       return seq_open(file, &sco_seq_ops);
+       return (str - buf);
 }
 
-static struct file_operations sco_seq_fops = {
-       .owner          = THIS_MODULE,
-       .open           = sco_seq_open,
-       .read           = seq_read,
-       .llseek         = seq_lseek,
-       .release        = seq_release,
-};
-
-static int __init sco_proc_init(void)
-{
-       struct proc_dir_entry *p = create_proc_entry("sco", S_IRUGO, proc_bt);
-       if (!p)
-               return -ENOMEM;
-       p->owner     = THIS_MODULE;
-       p->proc_fops = &sco_seq_fops;
-       return 0;
-}
-
-static void __exit sco_proc_cleanup(void)
-{
-       remove_proc_entry("sco", proc_bt);
-}
-
-#else /* CONFIG_PROC_FS */
-
-static int __init sco_proc_init(void)
-{
-       return 0;
-}
-
-static void __exit sco_proc_cleanup(void)
-{
-       return;
-}
-#endif /* CONFIG_PROC_FS */
+static CLASS_ATTR(sco, S_IRUGO, sco_sysfs_show, NULL);
 
 static struct proto_ops sco_sock_ops = {
        .family         = PF_BLUETOOTH,
@@ -1035,7 +969,7 @@ static int __init sco_init(void)
                goto error;
        }
 
-       sco_proc_init();
+       class_create_file(&bt_class, &class_attr_sco);
 
        BT_INFO("SCO (Voice Link) ver %s", VERSION);
        BT_INFO("SCO socket layer initialized");
@@ -1049,7 +983,7 @@ error:
 
 static void __exit sco_exit(void)
 {
-       sco_proc_cleanup();
+       class_remove_file(&bt_class, &class_attr_sco);
 
        if (bt_sock_unregister(BTPROTO_SCO) < 0)
                BT_ERR("SCO socket unregistration failed");
index db098ff3cd6a7509b58cec0b45da50e6cf76673e..cb530eef0e3990f2f3fce1076b2660b5109555b7 100644 (file)
@@ -194,8 +194,7 @@ int dev_mc_add(struct net_device *dev, void *addr, int alen, int glbl)
 
 done:
        spin_unlock_bh(&dev->xmit_lock);
-       if (dmi1)
-               kfree(dmi1);
+       kfree(dmi1);
        return err;
 }
 
index 9602ceb3bac9a2d33eec5ce1bc0cb8a55340203b..13cc3be4f056fb92f86cd660b6dcd29ba88ed30d 100644 (file)
@@ -1242,8 +1242,7 @@ static void sock_def_write_space(struct sock *sk)
 
 static void sock_def_destruct(struct sock *sk)
 {
-       if (sk->sk_protinfo)
-               kfree(sk->sk_protinfo);
+       kfree(sk->sk_protinfo);
 }
 
 void sk_send_sigurg(struct sock *sk)
index 4b9bc81ae1a3a35c6fe91a1c4cea05678c2e0781..ca03521112c52bfa4e279b351aee54c980105e71 100644 (file)
@@ -1263,10 +1263,8 @@ static int dccp_v4_destroy_sock(struct sock *sk)
        if (inet_csk(sk)->icsk_bind_hash != NULL)
                inet_put_port(&dccp_hashinfo, sk);
 
-       if (dp->dccps_service_list != NULL) {
-               kfree(dp->dccps_service_list);
-               dp->dccps_service_list = NULL;
-       }
+       kfree(dp->dccps_service_list);
+       dp->dccps_service_list = NULL;
 
        ccid_hc_rx_exit(dp->dccps_hc_rx_ccid, sk);
        ccid_hc_tx_exit(dp->dccps_hc_tx_ccid, sk);
index a021c3422f6773d3d5643e9b7e9ccdc475511951..e0ace7cbb9960cc5d145304b7ce8bf8a8a5de2a2 100644 (file)
@@ -238,8 +238,7 @@ static int dccp_setsockopt_service(struct sock *sk, const u32 service,
        lock_sock(sk);
        dp->dccps_service = service;
 
-       if (dp->dccps_service_list != NULL)
-               kfree(dp->dccps_service_list);
+       kfree(dp->dccps_service_list);
 
        dp->dccps_service_list = sl;
        release_sock(sk);
index eeba56f99323b0cf82131b0fa3f6c9614dc2927e..6f8b5658cb4e9caf0c9d84438f02dcdd37348b66 100644 (file)
@@ -784,16 +784,14 @@ struct dn_fib_table *dn_fib_get_table(int n, int create)
 
 static void dn_fib_del_tree(int n)
 {
-        struct dn_fib_table *t;
+       struct dn_fib_table *t;
 
-        write_lock(&dn_fib_tables_lock);
-        t = dn_fib_tables[n];
-        dn_fib_tables[n] = NULL;
-        write_unlock(&dn_fib_tables_lock);
+       write_lock(&dn_fib_tables_lock);
+       t = dn_fib_tables[n];
+       dn_fib_tables[n] = NULL;
+       write_unlock(&dn_fib_tables_lock);
 
-        if (t) {
-                kfree(t);
-        }
+       kfree(t);
 }
 
 struct dn_fib_table *dn_fib_empty_table(void)
index 98a494be6039452700e39a227fcf7a23d69ab3f6..9d57b4fb6440c74532856b9fc4160821aa19d2b8 100644 (file)
@@ -32,8 +32,7 @@ struct datalink_proto *make_EII_client(void)
 
 void destroy_EII_client(struct datalink_proto *dl)
 {
-       if (dl)
-               kfree(dl);
+       kfree(dl);
 }
 
 EXPORT_SYMBOL(destroy_EII_client);
index a9d84f93442c9560a8e7050a60292876b09bd508..eaa150c33b0403204fa22224d6434e5c45f7695c 100644 (file)
@@ -147,8 +147,7 @@ void inet_sock_destruct(struct sock *sk)
        BUG_TRAP(!sk->sk_wmem_queued);
        BUG_TRAP(!sk->sk_forward_alloc);
 
-       if (inet->opt)
-               kfree(inet->opt);
+       kfree(inet->opt);
        dst_release(sk->sk_dst_cache);
        sk_refcnt_debug_dec(sk);
 }
index 990633c09dfe4ccdf345d06281880117b57c7906..2267c1fad879f6d047d86a52d572b270d3af5af0 100644 (file)
@@ -266,8 +266,7 @@ int ip_rt_ioctl(unsigned int cmd, void __user *arg)
                                if (tb)
                                        err = tb->tb_insert(tb, &req.rtm, &rta, &req.nlh, NULL);
                        }
-                       if (rta.rta_mx)
-                               kfree(rta.rta_mx);
+                       kfree(rta.rta_mx);
                }
                rtnl_unlock();
                return err;
index bce4e875193be1d596c4c607ab42e9e1f966513f..dbe12da8d8b3960fe7dc796de97eae2546e1528d 100644 (file)
@@ -510,8 +510,7 @@ static int ip_options_get_finish(struct ip_options **optp,
                kfree(opt);
                return -EINVAL;
        }
-       if (*optp)
-               kfree(*optp);
+       kfree(*optp);
        *optp = opt;
        return 0;
 }
index 17758234a3e351e4787824bf1e1cda3dc72dfded..11c2f68254f0a8a04602222216a03578c0327d20 100644 (file)
@@ -353,7 +353,8 @@ packet_routed:
                ip_options_build(skb, opt, inet->daddr, rt, 0);
        }
 
-       ip_select_ident_more(iph, &rt->u.dst, sk, skb_shinfo(skb)->tso_segs);
+       ip_select_ident_more(iph, &rt->u.dst, sk,
+                            (skb_shinfo(skb)->tso_segs ?: 1) - 1);
 
        /* Add an IP checksum. */
        ip_send_check(iph);
@@ -1262,10 +1263,8 @@ int ip_push_pending_frames(struct sock *sk)
 
 out:
        inet->cork.flags &= ~IPCORK_OPT;
-       if (inet->cork.opt) {
-               kfree(inet->cork.opt);
-               inet->cork.opt = NULL;
-       }
+       kfree(inet->cork.opt);
+       inet->cork.opt = NULL;
        if (inet->cork.rt) {
                ip_rt_put(inet->cork.rt);
                inet->cork.rt = NULL;
@@ -1289,10 +1288,8 @@ void ip_flush_pending_frames(struct sock *sk)
                kfree_skb(skb);
 
        inet->cork.flags &= ~IPCORK_OPT;
-       if (inet->cork.opt) {
-               kfree(inet->cork.opt);
-               inet->cork.opt = NULL;
-       }
+       kfree(inet->cork.opt);
+       inet->cork.opt = NULL;
        if (inet->cork.rt) {
                ip_rt_put(inet->cork.rt);
                inet->cork.rt = NULL;
index 2f0b47da5b37e3b3c0c44235355e704958cba8a3..4f2d8725730958f498b3d319c9e3dca68cd50722 100644 (file)
@@ -202,8 +202,7 @@ int ip_ra_control(struct sock *sk, unsigned char on, void (*destructor)(struct s
                if (ra->sk == sk) {
                        if (on) {
                                write_unlock_bh(&ip_ra_lock);
-                               if (new_ra)
-                                       kfree(new_ra);
+                               kfree(new_ra);
                                return -EADDRINUSE;
                        }
                        *rap = ra->next;
@@ -446,8 +445,7 @@ int ip_setsockopt(struct sock *sk, int level, int optname, char __user *optval,
 #endif
                        }
                        opt = xchg(&inet->opt, opt);
-                       if (opt)
-                               kfree(opt);
+                       kfree(opt);
                        break;
                }
                case IP_PKTINFO:
@@ -828,10 +826,8 @@ int ip_setsockopt(struct sock *sk, int level, int optname, char __user *optval,
 
                        err = ip_mc_msfilter(sk, msf, ifindex);
 mc_msf_out:
-                       if (msf)
-                               kfree(msf);
-                       if (gsf)
-                               kfree(gsf);
+                       kfree(msf);
+                       kfree(gsf);
                        break;
                }
                case IP_ROUTER_ALERT:   
index fc6f95aaa96976e27c14d733e09f03888ea31592..d7eb680101c25311233b9195faedca1aa17d812b 100644 (file)
@@ -110,8 +110,7 @@ ip_vs_app_inc_new(struct ip_vs_app *app, __u16 proto, __u16 port)
        return 0;
 
   out:
-       if (inc->timeout_table)
-               kfree(inc->timeout_table);
+       kfree(inc->timeout_table);
        kfree(inc);
        return ret;
 }
@@ -136,8 +135,7 @@ ip_vs_app_inc_release(struct ip_vs_app *inc)
 
        list_del(&inc->a_list);
 
-       if (inc->timeout_table != NULL)
-               kfree(inc->timeout_table);
+       kfree(inc->timeout_table);
        kfree(inc);
 }
 
index 981cc3244ef2724827e9c303a27d2a79a511cb4c..1a0843cd58a9e40d84e03b003ed0984e16763edf 100644 (file)
@@ -1009,11 +1009,10 @@ ip_vs_in(unsigned int hooknum, struct sk_buff **pskb,
                if (sysctl_ip_vs_expire_nodest_conn) {
                        /* try to expire the connection immediately */
                        ip_vs_conn_expire_now(cp);
-               } else {
-                       /* don't restart its timer, and silently
-                          drop the packet. */
-                       __ip_vs_conn_put(cp);
                }
+               /* don't restart its timer, and silently
+                  drop the packet. */
+               __ip_vs_conn_put(cp);
                return NF_DROP;
        }
 
index bd7d75b6abe0a6a7e1ed63d78b5d18becf3eb961..d34a9fa608e0b88dec20adaa567100a5b63c4ee0 100644 (file)
@@ -207,16 +207,12 @@ static void wrandom_select_route(const struct flowi *flp,
                        decision = mpc->rt;
 
                last_power = mpc->power;
-               if (last_mpc)
-                       kfree(last_mpc);
-
+               kfree(last_mpc);
                last_mpc = mpc;
        }
 
-       if (last_mpc) {
-               /* concurrent __multipath_flush may lead to !last_mpc */
-               kfree(last_mpc);
-       }
+       /* concurrent __multipath_flush may lead to !last_mpc */
+       kfree(last_mpc);
 
        decision->u.dst.__use++;
        *rp = decision;
index 93b2c5111bb2338b15f765ed604866d4a860310b..8acb7ed40b47f7c5e25adae81f774601ffaa15ba 100644 (file)
@@ -1161,8 +1161,7 @@ static int snmp_parse_mangle(unsigned char *msg,
                
                if (!snmp_object_decode(&ctx, obj)) {
                        if (*obj) {
-                               if ((*obj)->id)
-                                       kfree((*obj)->id);
+                               kfree((*obj)->id);
                                kfree(*obj);
                        }       
                        kfree(obj);
index 49d67cd75eddcf07a79946c8204fa1265cbca498..634dabb558fd6f5942e709c99846f83985db8b41 100644 (file)
@@ -823,8 +823,7 @@ out:
  */
 static void tcp_v4_reqsk_destructor(struct request_sock *req)
 {
-       if (inet_rsk(req)->opt)
-               kfree(inet_rsk(req)->opt);
+       kfree(inet_rsk(req)->opt);
 }
 
 static inline void syn_flood_warning(struct sk_buff *skb)
index 2c5f57299d63b1f2badbd056286513f7ef51e646..b7a5f51238b3958f88bc18adfac17704d3aa0bf7 100644 (file)
@@ -35,6 +35,9 @@
  *     YOSHIFUJI Hideaki @USAGI        :       ARCnet support
  *     YOSHIFUJI Hideaki @USAGI        :       convert /proc/net/if_inet6 to
  *                                             seq_file.
+ *     YOSHIFUJI Hideaki @USAGI        :       improved source address
+ *                                             selection; consider scope,
+ *                                             status etc.
  */
 
 #include <linux/config.h>
@@ -193,46 +196,51 @@ const struct in6_addr in6addr_any = IN6ADDR_ANY_INIT;
 #endif
 const struct in6_addr in6addr_loopback = IN6ADDR_LOOPBACK_INIT;
 
-int ipv6_addr_type(const struct in6_addr *addr)
+#define IPV6_ADDR_SCOPE_TYPE(scope)    ((scope) << 16)
+
+static inline unsigned ipv6_addr_scope2type(unsigned scope)
+{
+       switch(scope) {
+       case IPV6_ADDR_SCOPE_NODELOCAL:
+               return (IPV6_ADDR_SCOPE_TYPE(IPV6_ADDR_SCOPE_NODELOCAL) |
+                       IPV6_ADDR_LOOPBACK);
+       case IPV6_ADDR_SCOPE_LINKLOCAL:
+               return (IPV6_ADDR_SCOPE_TYPE(IPV6_ADDR_SCOPE_LINKLOCAL) |
+                       IPV6_ADDR_LINKLOCAL);
+       case IPV6_ADDR_SCOPE_SITELOCAL:
+               return (IPV6_ADDR_SCOPE_TYPE(IPV6_ADDR_SCOPE_SITELOCAL) |
+                       IPV6_ADDR_SITELOCAL);
+       }
+       return IPV6_ADDR_SCOPE_TYPE(scope);
+}
+
+int __ipv6_addr_type(const struct in6_addr *addr)
 {
-       int type;
        u32 st;
 
        st = addr->s6_addr32[0];
 
-       if ((st & htonl(0xFF000000)) == htonl(0xFF000000)) {
-               type = IPV6_ADDR_MULTICAST;
-
-               switch((st & htonl(0x00FF0000))) {
-                       case __constant_htonl(0x00010000):
-                               type |= IPV6_ADDR_LOOPBACK;
-                               break;
-
-                       case __constant_htonl(0x00020000):
-                               type |= IPV6_ADDR_LINKLOCAL;
-                               break;
-
-                       case __constant_htonl(0x00050000):
-                               type |= IPV6_ADDR_SITELOCAL;
-                               break;
-               };
-               return type;
-       }
-
-       type = IPV6_ADDR_UNICAST;
-
        /* Consider all addresses with the first three bits different of
-          000 and 111 as finished.
+          000 and 111 as unicasts.
         */
        if ((st & htonl(0xE0000000)) != htonl(0x00000000) &&
            (st & htonl(0xE0000000)) != htonl(0xE0000000))
-               return type;
-       
-       if ((st & htonl(0xFFC00000)) == htonl(0xFE800000))
-               return (IPV6_ADDR_LINKLOCAL | type);
+               return (IPV6_ADDR_UNICAST | 
+                       IPV6_ADDR_SCOPE_TYPE(IPV6_ADDR_SCOPE_GLOBAL));
+
+       if ((st & htonl(0xFF000000)) == htonl(0xFF000000)) {
+               /* multicast */
+               /* addr-select 3.1 */
+               return (IPV6_ADDR_MULTICAST |
+                       ipv6_addr_scope2type(IPV6_ADDR_MC_SCOPE(addr)));
+       }
 
+       if ((st & htonl(0xFFC00000)) == htonl(0xFE800000))
+               return (IPV6_ADDR_LINKLOCAL | IPV6_ADDR_UNICAST | 
+                       IPV6_ADDR_SCOPE_TYPE(IPV6_ADDR_SCOPE_LINKLOCAL));               /* addr-select 3.1 */
        if ((st & htonl(0xFFC00000)) == htonl(0xFEC00000))
-               return (IPV6_ADDR_SITELOCAL | type);
+               return (IPV6_ADDR_SITELOCAL | IPV6_ADDR_UNICAST |
+                       IPV6_ADDR_SCOPE_TYPE(IPV6_ADDR_SCOPE_SITELOCAL));               /* addr-select 3.1 */
 
        if ((addr->s6_addr32[0] | addr->s6_addr32[1]) == 0) {
                if (addr->s6_addr32[2] == 0) {
@@ -240,24 +248,20 @@ int ipv6_addr_type(const struct in6_addr *addr)
                                return IPV6_ADDR_ANY;
 
                        if (addr->s6_addr32[3] == htonl(0x00000001))
-                               return (IPV6_ADDR_LOOPBACK | type);
+                               return (IPV6_ADDR_LOOPBACK | IPV6_ADDR_UNICAST |
+                                       IPV6_ADDR_SCOPE_TYPE(IPV6_ADDR_SCOPE_LINKLOCAL));       /* addr-select 3.4 */
 
-                       return (IPV6_ADDR_COMPATv4 | type);
+                       return (IPV6_ADDR_COMPATv4 | IPV6_ADDR_UNICAST |
+                               IPV6_ADDR_SCOPE_TYPE(IPV6_ADDR_SCOPE_GLOBAL));  /* addr-select 3.3 */
                }
 
                if (addr->s6_addr32[2] == htonl(0x0000ffff))
-                       return IPV6_ADDR_MAPPED;
+                       return (IPV6_ADDR_MAPPED | 
+                               IPV6_ADDR_SCOPE_TYPE(IPV6_ADDR_SCOPE_GLOBAL));  /* addr-select 3.3 */
        }
 
-       st &= htonl(0xFF000000);
-       if (st == 0)
-               return IPV6_ADDR_RESERVED;
-       st &= htonl(0xFE000000);
-       if (st == htonl(0x02000000))
-               return IPV6_ADDR_RESERVED;      /* for NSAP */
-       if (st == htonl(0x04000000))
-               return IPV6_ADDR_RESERVED;      /* for IPX */
-       return type;
+       return (IPV6_ADDR_RESERVED | 
+               IPV6_ADDR_SCOPE_TYPE(IPV6_ADDR_SCOPE_GLOBAL));  /* addr-select 3.4 */
 }
 
 static void addrconf_del_timer(struct inet6_ifaddr *ifp)
@@ -805,138 +809,274 @@ out:
 #endif
 
 /*
- *     Choose an appropriate source address
- *     should do:
- *     i)      get an address with an appropriate scope
- *     ii)     see if there is a specific route for the destination and use
- *             an address of the attached interface 
- *     iii)    don't use deprecated addresses
+ *     Choose an appropriate source address (RFC3484)
  */
-static int inline ipv6_saddr_pref(const struct inet6_ifaddr *ifp, u8 invpref)
+struct ipv6_saddr_score {
+       int             addr_type;
+       unsigned int    attrs;
+       int             matchlen;
+       unsigned int    scope;
+       unsigned int    rule;
+};
+
+#define IPV6_SADDR_SCORE_LOCAL         0x0001
+#define IPV6_SADDR_SCORE_PREFERRED     0x0004
+#define IPV6_SADDR_SCORE_HOA           0x0008
+#define IPV6_SADDR_SCORE_OIF           0x0010
+#define IPV6_SADDR_SCORE_LABEL         0x0020
+#define IPV6_SADDR_SCORE_PRIVACY       0x0040
+
+static int inline ipv6_saddr_preferred(int type)
 {
-       int pref;
-       pref = ifp->flags&IFA_F_DEPRECATED ? 0 : 2;
-#ifdef CONFIG_IPV6_PRIVACY
-       pref |= (ifp->flags^invpref)&IFA_F_TEMPORARY ? 0 : 1;
-#endif
-       return pref;
+       if (type & (IPV6_ADDR_MAPPED|IPV6_ADDR_COMPATv4|
+                   IPV6_ADDR_LOOPBACK|IPV6_ADDR_RESERVED))
+               return 1;
+       return 0;
 }
 
-#ifdef CONFIG_IPV6_PRIVACY
-#define IPV6_GET_SADDR_MAXSCORE(score) ((score) == 3)
-#else
-#define IPV6_GET_SADDR_MAXSCORE(score) (score)
-#endif
+/* static matching label */
+static int inline ipv6_saddr_label(const struct in6_addr *addr, int type)
+{
+ /*
+  *    prefix (longest match)  label
+  *    -----------------------------
+  *    ::1/128                 0
+  *    ::/0                    1
+  *    2002::/16               2
+  *    ::/96                   3
+  *    ::ffff:0:0/96           4
+  */
+       if (type & IPV6_ADDR_LOOPBACK)
+               return 0;
+       else if (type & IPV6_ADDR_COMPATv4)
+               return 3;
+       else if (type & IPV6_ADDR_MAPPED)
+               return 4;
+       else if (addr->s6_addr16[0] == htons(0x2002))
+               return 2;
+       return 1;
+}
 
-int ipv6_dev_get_saddr(struct net_device *dev,
+int ipv6_dev_get_saddr(struct net_device *daddr_dev,
                       struct in6_addr *daddr, struct in6_addr *saddr)
 {
-       struct inet6_ifaddr *ifp = NULL;
-       struct inet6_ifaddr *match = NULL;
-       struct inet6_dev *idev;
-       int scope;
-       int err;
-       int hiscore = -1, score;
+       struct ipv6_saddr_score hiscore;
+       struct inet6_ifaddr *ifa_result = NULL;
+       int daddr_type = __ipv6_addr_type(daddr);
+       int daddr_scope = __ipv6_addr_src_scope(daddr_type);
+       u32 daddr_label = ipv6_saddr_label(daddr, daddr_type);
+       struct net_device *dev;
 
-       scope = ipv6_addr_scope(daddr);
+       memset(&hiscore, 0, sizeof(hiscore));
 
-       /*
-        *      known dev
-        *      search dev and walk through dev addresses
-        */
+       read_lock(&dev_base_lock);
+       read_lock(&addrconf_lock);
 
-       if (dev) {
-               if (dev->flags & IFF_LOOPBACK)
-                       scope = IFA_HOST;
+       for (dev = dev_base; dev; dev=dev->next) {
+               struct inet6_dev *idev;
+               struct inet6_ifaddr *ifa;
+
+               /* Rule 0: Candidate Source Address (section 4)
+                *  - multicast and link-local destination address,
+                *    the set of candidate source address MUST only
+                *    include addresses assigned to interfaces
+                *    belonging to the same link as the outgoing
+                *    interface.
+                * (- For site-local destination addresses, the
+                *    set of candidate source addresses MUST only
+                *    include addresses assigned to interfaces
+                *    belonging to the same site as the outgoing
+                *    interface.)
+                */
+               if ((daddr_type & IPV6_ADDR_MULTICAST ||
+                    daddr_scope <= IPV6_ADDR_SCOPE_LINKLOCAL) &&
+                   daddr_dev && dev != daddr_dev)
+                       continue;
 
-               read_lock(&addrconf_lock);
                idev = __in6_dev_get(dev);
-               if (idev) {
-                       read_lock_bh(&idev->lock);
-                       for (ifp=idev->addr_list; ifp; ifp=ifp->if_next) {
-                               if (ifp->scope == scope) {
-                                       if (ifp->flags&IFA_F_TENTATIVE)
-                                               continue;
-#ifdef CONFIG_IPV6_PRIVACY
-                                       score = ipv6_saddr_pref(ifp, idev->cnf.use_tempaddr > 1 ? IFA_F_TEMPORARY : 0);
-#else
-                                       score = ipv6_saddr_pref(ifp, 0);
-#endif
-                                       if (score <= hiscore)
-                                               continue;
+               if (!idev)
+                       continue;
 
-                                       if (match)
-                                               in6_ifa_put(match);
-                                       match = ifp;
-                                       hiscore = score;
-                                       in6_ifa_hold(ifp);
+               read_lock_bh(&idev->lock);
+               for (ifa = idev->addr_list; ifa; ifa = ifa->if_next) {
+                       struct ipv6_saddr_score score;
 
-                                       if (IPV6_GET_SADDR_MAXSCORE(score)) {
-                                               read_unlock_bh(&idev->lock);
-                                               read_unlock(&addrconf_lock);
-                                               goto out;
-                                       }
+                       score.addr_type = __ipv6_addr_type(&ifa->addr);
+
+                       /* Rule 0: Candidate Source Address (section 4)
+                        *  - In any case, anycast addresses, multicast
+                        *    addresses, and the unspecified address MUST
+                        *    NOT be included in a candidate set.
+                        */
+                       if (unlikely(score.addr_type == IPV6_ADDR_ANY ||
+                                    score.addr_type & IPV6_ADDR_MULTICAST)) {
+                               LIMIT_NETDEBUG(KERN_DEBUG
+                                              "ADDRCONF: unspecified / multicast address"
+                                              "assigned as unicast address on %s",
+                                              dev->name);
+                               continue;
+                       }
+
+                       score.attrs = 0;
+                       score.matchlen = 0;
+                       score.scope = 0;
+                       score.rule = 0;
+
+                       if (ifa_result == NULL) {
+                               /* record it if the first available entry */
+                               goto record_it;
+                       }
+
+                       /* Rule 1: Prefer same address */
+                       if (hiscore.rule < 1) {
+                               if (ipv6_addr_equal(&ifa_result->addr, daddr))
+                                       hiscore.attrs |= IPV6_SADDR_SCORE_LOCAL;
+                               hiscore.rule++;
+                       }
+                       if (ipv6_addr_equal(&ifa->addr, daddr)) {
+                               score.attrs |= IPV6_SADDR_SCORE_LOCAL;
+                               if (!(hiscore.attrs & IPV6_SADDR_SCORE_LOCAL)) {
+                                       score.rule = 1;
+                                       goto record_it;
                                }
+                       } else {
+                               if (hiscore.attrs & IPV6_SADDR_SCORE_LOCAL)
+                                       continue;
                        }
-                       read_unlock_bh(&idev->lock);
-               }
-               read_unlock(&addrconf_lock);
-       }
 
-       if (scope == IFA_LINK)
-               goto out;
+                       /* Rule 2: Prefer appropriate scope */
+                       if (hiscore.rule < 2) {
+                               hiscore.scope = __ipv6_addr_src_scope(hiscore.addr_type);
+                               hiscore.rule++;
+                       }
+                       score.scope = __ipv6_addr_src_scope(score.addr_type);
+                       if (hiscore.scope < score.scope) {
+                               if (hiscore.scope < daddr_scope) {
+                                       score.rule = 2;
+                                       goto record_it;
+                               } else
+                                       continue;
+                       } else if (score.scope < hiscore.scope) {
+                               if (score.scope < daddr_scope)
+                                       continue;
+                               else {
+                                       score.rule = 2;
+                                       goto record_it;
+                               }
+                       }
 
-       /*
-        *      dev == NULL or search failed for specified dev
-        */
+                       /* Rule 3: Avoid deprecated address */
+                       if (hiscore.rule < 3) {
+                               if (ipv6_saddr_preferred(hiscore.addr_type) ||
+                                   !(ifa_result->flags & IFA_F_DEPRECATED))
+                                       hiscore.attrs |= IPV6_SADDR_SCORE_PREFERRED;
+                               hiscore.rule++;
+                       }
+                       if (ipv6_saddr_preferred(score.addr_type) ||
+                           !(ifa->flags & IFA_F_DEPRECATED)) {
+                               score.attrs |= IPV6_SADDR_SCORE_PREFERRED;
+                               if (!(hiscore.attrs & IPV6_SADDR_SCORE_PREFERRED)) {
+                                       score.rule = 3;
+                                       goto record_it;
+                               }
+                       } else {
+                               if (hiscore.attrs & IPV6_SADDR_SCORE_PREFERRED)
+                                       continue;
+                       }
 
-       read_lock(&dev_base_lock);
-       read_lock(&addrconf_lock);
-       for (dev = dev_base; dev; dev=dev->next) {
-               idev = __in6_dev_get(dev);
-               if (idev) {
-                       read_lock_bh(&idev->lock);
-                       for (ifp=idev->addr_list; ifp; ifp=ifp->if_next) {
-                               if (ifp->scope == scope) {
-                                       if (ifp->flags&IFA_F_TENTATIVE)
-                                               continue;
-#ifdef CONFIG_IPV6_PRIVACY
-                                       score = ipv6_saddr_pref(ifp, idev->cnf.use_tempaddr > 1 ? IFA_F_TEMPORARY : 0);
-#else
-                                       score = ipv6_saddr_pref(ifp, 0);
-#endif
-                                       if (score <= hiscore)
-                                               continue;
+                       /* Rule 4: Prefer home address -- not implemented yet */
 
-                                       if (match)
-                                               in6_ifa_put(match);
-                                       match = ifp;
-                                       hiscore = score;
-                                       in6_ifa_hold(ifp);
+                       /* Rule 5: Prefer outgoing interface */
+                       if (hiscore.rule < 5) {
+                               if (daddr_dev == NULL ||
+                                   daddr_dev == ifa_result->idev->dev)
+                                       hiscore.attrs |= IPV6_SADDR_SCORE_OIF;
+                               hiscore.rule++;
+                       }
+                       if (daddr_dev == NULL ||
+                           daddr_dev == ifa->idev->dev) {
+                               score.attrs |= IPV6_SADDR_SCORE_OIF;
+                               if (!(hiscore.attrs & IPV6_SADDR_SCORE_OIF)) {
+                                       score.rule = 5;
+                                       goto record_it;
+                               }
+                       } else {
+                               if (hiscore.attrs & IPV6_SADDR_SCORE_OIF)
+                                       continue;
+                       }
 
-                                       if (IPV6_GET_SADDR_MAXSCORE(score)) {
-                                               read_unlock_bh(&idev->lock);
-                                               goto out_unlock_base;
-                                       }
+                       /* Rule 6: Prefer matching label */
+                       if (hiscore.rule < 6) {
+                               if (ipv6_saddr_label(&ifa_result->addr, hiscore.addr_type) == daddr_label)
+                                       hiscore.attrs |= IPV6_SADDR_SCORE_LABEL;
+                               hiscore.rule++;
+                       }
+                       if (ipv6_saddr_label(&ifa->addr, score.addr_type) == daddr_label) {
+                               score.attrs |= IPV6_SADDR_SCORE_LABEL;
+                               if (!(hiscore.attrs & IPV6_SADDR_SCORE_LABEL)) {
+                                       score.rule = 6;
+                                       goto record_it;
+                               }
+                       } else {
+                               if (hiscore.attrs & IPV6_SADDR_SCORE_LABEL)
+                                       continue;
+                       }
+
+                       /* Rule 7: Prefer public address
+                        * Note: prefer temprary address if use_tempaddr >= 2
+                        */
+                       if (hiscore.rule < 7) {
+                               if ((!(ifa_result->flags & IFA_F_TEMPORARY)) ^
+                                   (ifa_result->idev->cnf.use_tempaddr >= 2))
+                                       hiscore.attrs |= IPV6_SADDR_SCORE_PRIVACY;
+                               hiscore.rule++;
+                       }
+                       if ((!(ifa->flags & IFA_F_TEMPORARY)) ^
+                           (ifa->idev->cnf.use_tempaddr >= 2)) {
+                               score.attrs |= IPV6_SADDR_SCORE_PRIVACY;
+                               if (!(hiscore.attrs & IPV6_SADDR_SCORE_PRIVACY)) {
+                                       score.rule = 7;
+                                       goto record_it;
                                }
+                       } else {
+                               if (hiscore.attrs & IPV6_SADDR_SCORE_PRIVACY)
+                                       continue;
                        }
-                       read_unlock_bh(&idev->lock);
+
+                       /* Rule 8: Use longest matching prefix */
+                       if (hiscore.rule < 8)
+                               hiscore.matchlen = ipv6_addr_diff(&ifa_result->addr, daddr);
+                       score.rule++;
+                       score.matchlen = ipv6_addr_diff(&ifa->addr, daddr);
+                       if (score.matchlen > hiscore.matchlen) {
+                               score.rule = 8;
+                               goto record_it;
+                       }
+#if 0
+                       else if (score.matchlen < hiscore.matchlen)
+                               continue;
+#endif
+
+                       /* Final Rule: choose first available one */
+                       continue;
+record_it:
+                       if (ifa_result)
+                               in6_ifa_put(ifa_result);
+                       in6_ifa_hold(ifa);
+                       ifa_result = ifa;
+                       hiscore = score;
                }
+               read_unlock_bh(&idev->lock);
        }
-
-out_unlock_base:
        read_unlock(&addrconf_lock);
        read_unlock(&dev_base_lock);
 
-out:
-       err = -EADDRNOTAVAIL;
-       if (match) {
-               ipv6_addr_copy(saddr, &match->addr);
-               err = 0;
-               in6_ifa_put(match);
-       }
-
-       return err;
+       if (!ifa_result)
+               return -EADDRNOTAVAIL;
+       
+       ipv6_addr_copy(saddr, &ifa_result->addr);
+       in6_ifa_put(ifa_result);
+       return 0;
 }
 
 
@@ -2950,8 +3090,7 @@ static int inet6_fill_ifinfo(struct sk_buff *skb, struct inet6_dev *idev,
 
 nlmsg_failure:
 rtattr_failure:
-       if (array)
-               kfree(array);
+       kfree(array);
        skb_trim(skb, b - skb->data);
        return -1;
 }
index 4fcc5a7acf6e446ce2715df397d37d78b3b34354..1bf6d9a769e61fa2a54a1838c9f26a0aaf502127 100644 (file)
@@ -127,56 +127,6 @@ static __inline__ int addr_bit_set(void *token, int fn_bit)
        return htonl(1 << ((~fn_bit)&0x1F)) & addr[fn_bit>>5];
 }
 
-/*
- *     find the first different bit between two addresses
- *     length of address must be a multiple of 32bits
- */
-
-static __inline__ int addr_diff(void *token1, void *token2, int addrlen)
-{
-       __u32 *a1 = token1;
-       __u32 *a2 = token2;
-       int i;
-
-       addrlen >>= 2;
-
-       for (i = 0; i < addrlen; i++) {
-               __u32 xb;
-
-               xb = a1[i] ^ a2[i];
-
-               if (xb) {
-                       int j = 31;
-
-                       xb = ntohl(xb);
-
-                       while ((xb & (1 << j)) == 0)
-                               j--;
-
-                       return (i * 32 + 31 - j);
-               }
-       }
-
-       /*
-        *      we should *never* get to this point since that 
-        *      would mean the addrs are equal
-        *
-        *      However, we do get to it 8) And exacly, when
-        *      addresses are equal 8)
-        *
-        *      ip route add 1111::/128 via ...
-        *      ip route add 1111::/64 via ...
-        *      and we are here.
-        *
-        *      Ideally, this function should stop comparison
-        *      at prefix length. It does not, but it is still OK,
-        *      if returned value is greater than prefix length.
-        *                                      --ANK (980803)
-        */
-
-       return addrlen<<5;
-}
-
 static __inline__ struct fib6_node * node_alloc(void)
 {
        struct fib6_node *fn;
@@ -296,11 +246,11 @@ insert_above:
 
        /* find 1st bit in difference between the 2 addrs.
 
-          See comment in addr_diff: bit may be an invalid value,
+          See comment in __ipv6_addr_diff: bit may be an invalid value,
           but if it is >= plen, the value is ignored in any case.
         */
        
-       bit = addr_diff(addr, &key->addr, addrlen);
+       bit = __ipv6_addr_diff(addr, &key->addr, addrlen);
 
        /* 
         *              (intermediate)[in]      
index 614296a920c6ab189b58607726eea55bee4d0426..dbd9767b32e45ee3373e94ae20afee2b5449a83c 100644 (file)
@@ -587,8 +587,7 @@ static int ip6_fragment(struct sk_buff *skb, int (*output)(struct sk_buff *))
                        skb->next = NULL;
                }
 
-               if (tmp_hdr)
-                       kfree(tmp_hdr);
+               kfree(tmp_hdr);
 
                if (err == 0) {
                        IP6_INC_STATS(IPSTATS_MIB_FRAGOKS);
@@ -1186,10 +1185,8 @@ int ip6_push_pending_frames(struct sock *sk)
 
 out:
        inet->cork.flags &= ~IPCORK_OPT;
-       if (np->cork.opt) {
-               kfree(np->cork.opt);
-               np->cork.opt = NULL;
-       }
+       kfree(np->cork.opt);
+       np->cork.opt = NULL;
        if (np->cork.rt) {
                dst_release(&np->cork.rt->u.dst);
                np->cork.rt = NULL;
@@ -1214,10 +1211,8 @@ void ip6_flush_pending_frames(struct sock *sk)
 
        inet->cork.flags &= ~IPCORK_OPT;
 
-       if (np->cork.opt) {
-               kfree(np->cork.opt);
-               np->cork.opt = NULL;
-       }
+       kfree(np->cork.opt);
+       np->cork.opt = NULL;
        if (np->cork.rt) {
                dst_release(&np->cork.rt->u.dst);
                np->cork.rt = NULL;
index cf94372d1af39980b108f3161fd8d94837e0f94c..e6b0e3954c02be114b6bba4f2e14007ff069d1db 100644 (file)
@@ -756,8 +756,7 @@ ip6ip6_tnl_xmit(struct sk_buff *skb, struct net_device *dev)
        }
        ip6_tnl_dst_store(t, dst);
 
-       if (opt)
-               kfree(opt);
+       kfree(opt);
 
        t->recursion--;
        return 0;
@@ -766,8 +765,7 @@ tx_err_link_failure:
        dst_link_failure(skb);
 tx_err_dst_release:
        dst_release(dst);
-       if (opt)
-               kfree(opt);
+       kfree(opt);
 tx_err:
        stats->tx_errors++;
        stats->tx_dropped++;
index 85bfbc69b2c3dc716618f6e528dfcb63658e96b5..55917fb170949cfdcd5dd427dc8baf7201c14a17 100644 (file)
@@ -130,8 +130,7 @@ static int ipcomp6_input(struct xfrm_state *x, struct xfrm_decap_state *decap, s
 out_put_cpu:
        put_cpu();
 out:
-       if (tmp_hdr)
-               kfree(tmp_hdr);
+       kfree(tmp_hdr);
        if (err)
                goto error_out;
        return nexthdr;
index 8567873d0dd85fabd972537eccce7d79d8107611..003fd99ff597d6f4332008c90f6bdcb2b9e80493 100644 (file)
@@ -80,8 +80,7 @@ int ip6_ra_control(struct sock *sk, int sel, void (*destructor)(struct sock *))
                if (ra->sk == sk) {
                        if (sel>=0) {
                                write_unlock_bh(&ip6_ra_lock);
-                               if (new_ra)
-                                       kfree(new_ra);
+                               kfree(new_ra);
                                return -EADDRINUSE;
                        }
 
index 37a4a99c9fe9e1837e5cd82f686ff3736fd94daa..16482785bdfddf322fad974dfe3e407285549ee2 100644 (file)
@@ -7,7 +7,7 @@
 #include <net/ip6_route.h>
 #include <net/xfrm.h>
 
-EXPORT_SYMBOL(ipv6_addr_type);
+EXPORT_SYMBOL(__ipv6_addr_type);
 EXPORT_SYMBOL(icmpv6_send);
 EXPORT_SYMBOL(icmpv6_statistics);
 EXPORT_SYMBOL(icmpv6_err_convert);
index c4ba5fa1446a47da6ba85981cc8c4a7e693e73ad..3fefc822c1c087c2cebd4baadb646ef771442784 100644 (file)
@@ -194,8 +194,7 @@ void irlmp_expire_discoveries(hashbin_t *log, __u32 saddr, int force)
 
                        /* Remove it from the log */
                        curr = hashbin_remove_this(log, (irda_queue_t *) curr);
-                       if (curr)
-                               kfree(curr);
+                       kfree(curr);
                }
        }
 
index 6fec428b45123df937bff9b6bc177a24fa793d41..75f2666e863056d7255875285c5188fee69042cd 100644 (file)
@@ -122,8 +122,7 @@ static void __irias_delete_attrib(struct ias_attrib *attrib)
        IRDA_ASSERT(attrib != NULL, return;);
        IRDA_ASSERT(attrib->magic == IAS_ATTRIB_MAGIC, return;);
 
-       if (attrib->name)
-               kfree(attrib->name);
+       kfree(attrib->name);
 
        irias_delete_value(attrib->value);
        attrib->magic = ~IAS_ATTRIB_MAGIC;
@@ -136,8 +135,7 @@ void __irias_delete_object(struct ias_object *obj)
        IRDA_ASSERT(obj != NULL, return;);
        IRDA_ASSERT(obj->magic == IAS_OBJECT_MAGIC, return;);
 
-       if (obj->name)
-               kfree(obj->name);
+       kfree(obj->name);
 
        hashbin_delete(obj->attribs, (FREE_FUNC) __irias_delete_attrib);
 
@@ -562,14 +560,12 @@ void irias_delete_value(struct ias_value *value)
                /* No need to deallocate */
                break;
        case IAS_STRING:
-               /* If string, deallocate string */
-               if (value->t.string != NULL)
-                       kfree(value->t.string);
+               /* Deallocate string */
+               kfree(value->t.string);
                break;
        case IAS_OCT_SEQ:
-               /* If byte stream, deallocate byte stream */
-                if (value->t.oct_seq != NULL)
-                        kfree(value->t.oct_seq);
+               /* Deallocate byte stream */
+                kfree(value->t.oct_seq);
                 break;
        default:
                IRDA_DEBUG(0, "%s(), Unknown value type!\n", __FUNCTION__);
index b18fe504301944d8514816df8d6eb90f715b048d..8631b65a7312c830d35e4d843163024432bac54e 100644 (file)
@@ -240,8 +240,7 @@ static void rose_remove_neigh(struct rose_neigh *rose_neigh)
        if ((s = rose_neigh_list) == rose_neigh) {
                rose_neigh_list = rose_neigh->next;
                spin_unlock_bh(&rose_neigh_list_lock);
-               if (rose_neigh->digipeat != NULL)
-                       kfree(rose_neigh->digipeat);
+               kfree(rose_neigh->digipeat);
                kfree(rose_neigh);
                return;
        }
@@ -250,8 +249,7 @@ static void rose_remove_neigh(struct rose_neigh *rose_neigh)
                if (s->next == rose_neigh) {
                        s->next = rose_neigh->next;
                        spin_unlock_bh(&rose_neigh_list_lock);
-                       if (rose_neigh->digipeat != NULL)
-                               kfree(rose_neigh->digipeat);
+                       kfree(rose_neigh->digipeat);
                        kfree(rose_neigh);
                        return;
                }
index 29d8b9a4d162f2aa72b38f3df3f68e9f1ffe625e..75470486e4050edb23e4db439a3228adfbfc170e 100644 (file)
@@ -298,8 +298,7 @@ static int fw_change(struct tcf_proto *tp, unsigned long base,
        return 0;
 
 errout:
-       if (f)
-               kfree(f);
+       kfree(f);
        return err;
 }
 
index 02996ac05c75d11b738649fd3069abeb17b82bdd..520ff716dab2f0d744845747366f320dd83f9434 100644 (file)
@@ -525,8 +525,7 @@ reinsert:
        return 0;
 
 errout:
-       if (f)
-               kfree(f);
+       kfree(f);
        return err;
 }
 
index 006168d6937654d7ece5493fad1b96cad9e0806b..572f06be3b02a181447c1e125056a833687ef017 100644 (file)
@@ -555,8 +555,7 @@ insert:
        goto insert;
 
 errout:
-       if (f)
-               kfree(f);
+       kfree(f);
 errout2:
        tcf_exts_destroy(tp, &e);
        return err;
index 404d9d83a7fab040efab32341db2732b31626cf9..9f921174c8ab39d33e9544c9b78051b3b8a12cdf 100644 (file)
@@ -194,8 +194,7 @@ found:
        }
        tcf_unbind_filter(tp, &r->res);
        tcf_exts_destroy(tp, &r->exts);
-       if (f)
-               kfree(f);
+       kfree(f);
        return 0;
 }
 
@@ -442,10 +441,8 @@ static void tcindex_destroy(struct tcf_proto *tp)
        walker.skip = 0;
        walker.fn = &tcindex_destroy_element;
        tcindex_walk(tp,&walker);
-       if (p->perfect)
-               kfree(p->perfect);
-       if (p->h)
-               kfree(p->h);
+       kfree(p->perfect);
+       kfree(p->h);
        kfree(p);
        tp->root = NULL;
 }
index 364b87d86455dc8671d17d8fbeceb4ae9d1d51e8..2b670479dde1d68ea192e641dbe69ffb754bf9f4 100644 (file)
@@ -347,7 +347,7 @@ static int u32_destroy_key(struct tcf_proto *tp, struct tc_u_knode *n)
        if (n->ht_down)
                n->ht_down->refcnt--;
 #ifdef CONFIG_CLS_U32_PERF
-       if (n && (NULL != n->pf))
+       if (n)
                kfree(n->pf);
 #endif
        kfree(n);
@@ -680,7 +680,7 @@ static int u32_change(struct tcf_proto *tp, unsigned long base, u32 handle,
                return 0;
        }
 #ifdef CONFIG_CLS_U32_PERF
-       if (n && (NULL != n->pf))
+       if (n)
                kfree(n->pf);
 #endif
        kfree(n);
index cf68a59fdc5a4d4d6ac2bfbd5b63f99cd4574cee..700844d49d795d36acffd22815b5fb4f15ec3ce9 100644 (file)
@@ -561,8 +561,7 @@ static int meta_var_change(struct meta_value *dst, struct rtattr *rta)
 
 static void meta_var_destroy(struct meta_value *v)
 {
-       if (v->val)
-               kfree((void *) v->val);
+       kfree((void *) v->val);
 }
 
 static void meta_var_apply_extras(struct meta_value *v,
index ebfe2e7d21bdff98494baf479c2cca37c4175b99..64b047c65568cafe0912b92f7bb18b7e56031c25 100644 (file)
@@ -298,6 +298,11 @@ int tcf_em_tree_validate(struct tcf_proto *tp, struct rtattr *rta,
        struct tcf_ematch_tree_hdr *tree_hdr;
        struct tcf_ematch *em;
 
+       if (!rta) {
+               memset(tree, 0, sizeof(*tree));
+               return 0;
+       }
+
        if (rtattr_parse_nested(tb, TCA_EMATCH_TREE_MAX, rta) < 0)
                goto errout;
 
index 12b0f582a66b29707941da349b3f63582e5c0407..8c8ddf7f9b61c7c9ca7a804f8cbf8101fc151aa9 100644 (file)
@@ -344,9 +344,7 @@ void sctp_association_free(struct sctp_association *asoc)
        }
 
        /* Free peer's cached cookie. */
-       if (asoc->peer.cookie) {
-               kfree(asoc->peer.cookie);
-       }
+       kfree(asoc->peer.cookie);
 
        /* Release the transport structures. */
        list_for_each_safe(pos, temp, &asoc->peer.transport_addr_list) {
index 660c61bdf16423c883dff5291fd60e2067b552d9..f9573eba5c7aa2f5507c12c0ff55a75e0e700490 100644 (file)
@@ -254,8 +254,7 @@ struct sctp_chunk *sctp_make_init(const struct sctp_association *asoc,
        aiparam.adaption_ind = htonl(sp->adaption_ind);
        sctp_addto_chunk(retval, sizeof(aiparam), &aiparam);
 nodata:
-       if (addrs.v)
-               kfree(addrs.v);
+       kfree(addrs.v);
        return retval;
 }
 
@@ -347,8 +346,7 @@ struct sctp_chunk *sctp_make_init_ack(const struct sctp_association *asoc,
 nomem_chunk:
        kfree(cookie);
 nomem_cookie:
-       if (addrs.v)
-               kfree(addrs.v);
+       kfree(addrs.v);
        return retval;
 }
 
index 13f8ae9794542d436f82274bff2e38c0a7724f18..d0dfdfd5e79efa926140d23e10ecba89e16cc381 100644 (file)
@@ -143,6 +143,6 @@ gss_get_mic_kerberos(struct gss_ctx *gss_ctx, struct xdr_buf *text,
 
        return ((ctx->endtime < now) ? GSS_S_CONTEXT_EXPIRED : GSS_S_COMPLETE);
 out_err:
-       if (md5cksum.data) kfree(md5cksum.data);
+       kfree(md5cksum.data);
        return GSS_S_FAILURE;
 }
index 2030475d98ed26b22632a6dc6f01068ef6f92947..db055fd7d7789c22ef62e4e8faab7ebac7cafebd 100644 (file)
@@ -176,6 +176,6 @@ gss_verify_mic_kerberos(struct gss_ctx *gss_ctx,
 
        ret = GSS_S_COMPLETE;
 out:
-       if (md5cksum.data) kfree(md5cksum.data);
+       kfree(md5cksum.data);
        return ret;
 }
index b048bf672da2bbffbe35953b3e47a57b7e2383d3..f8bac6ccd524008a669c4e603d8526b9dabb006b 100644 (file)
@@ -60,8 +60,7 @@ gss_mech_free(struct gss_api_mech *gm)
 
        for (i = 0; i < gm->gm_pf_num; i++) {
                pf = &gm->gm_pfs[i];
-               if (pf->auth_domain_name)
-                       kfree(pf->auth_domain_name);
+               kfree(pf->auth_domain_name);
                pf->auth_domain_name = NULL;
        }
 }
index 148201e929d08de77ca44f6b6dfbe8da20ab7e04..d1e12b25d6e21f2b4e205c49b3ddd0d0fb7580b6 100644 (file)
@@ -122,8 +122,7 @@ spkm3_make_token(struct spkm3_ctx *ctx,
 
        return  GSS_S_COMPLETE;
 out_err:
-       if (md5cksum.data) 
-               kfree(md5cksum.data);
+       kfree(md5cksum.data);
        token->data = NULL;
        token->len = 0;
        return GSS_S_FAILURE;
index 46c08a0710f62e147f0a4c6b4e6502be5a89ebbd..1f824578d773691c17c67daa6f76e9096730a789 100644 (file)
@@ -259,8 +259,7 @@ spkm3_verify_mic_token(unsigned char **tokp, int *mic_hdrlen, unsigned char **ck
 
        ret = GSS_S_COMPLETE;
 out:
-       if (spkm3_ctx_id.data)
-               kfree(spkm3_ctx_id.data);
+       kfree(spkm3_ctx_id.data);
        return ret;
 }
 
index c3c0d95861039958305e89f437174b8c3bc13272..241d5b30dfcbcfb851093856f88b79698da35a81 100644 (file)
@@ -120,9 +120,7 @@ spkm3_read_token(struct spkm3_ctx *ctx,
        /* XXX: need to add expiration and sequencing */
        ret = GSS_S_COMPLETE;
 out:
-       if (md5cksum.data) 
-               kfree(md5cksum.data);
-       if (wire_cksum.data) 
-               kfree(wire_cksum.data);
+       kfree(md5cksum.data);
+       kfree(wire_cksum.data);
        return ret;
 }
index 4f188d0a5d11c2d51dd3c6b7b65a7ccd2e21d2c2..81e00a6c19def97230e09f0302029c5ef04f82e9 100644 (file)
@@ -603,7 +603,7 @@ rpc_lookup_negative(char *path, struct nameidata *nd)
                return ERR_PTR(error);
        dir = nd->dentry->d_inode;
        down(&dir->i_sem);
-       dentry = lookup_hash(&nd->last, nd->dentry);
+       dentry = lookup_hash(nd);
        if (IS_ERR(dentry))
                goto out_err;
        if (dentry->d_inode) {
@@ -665,7 +665,7 @@ rpc_rmdir(char *path)
                return error;
        dir = nd.dentry->d_inode;
        down(&dir->i_sem);
-       dentry = lookup_hash(&nd.last, nd.dentry);
+       dentry = lookup_hash(&nd);
        if (IS_ERR(dentry)) {
                error = PTR_ERR(dentry);
                goto out_release;
@@ -726,7 +726,7 @@ rpc_unlink(char *path)
                return error;
        dir = nd.dentry->d_inode;
        down(&dir->i_sem);
-       dentry = lookup_hash(&nd.last, nd.dentry);
+       dentry = lookup_hash(&nd);
        if (IS_ERR(dentry)) {
                error = PTR_ERR(dentry);
                goto out_release;
index 5a220b2bb376f4669ecf4d267d1fa261d0b5b847..e4296c8b861eba85fead5bf1d839aa212e59ac7c 100644 (file)
@@ -196,12 +196,9 @@ svc_exit_thread(struct svc_rqst *rqstp)
        struct svc_serv *serv = rqstp->rq_server;
 
        svc_release_buffer(rqstp);
-       if (rqstp->rq_resp)
-               kfree(rqstp->rq_resp);
-       if (rqstp->rq_argp)
-               kfree(rqstp->rq_argp);
-       if (rqstp->rq_auth_data)
-               kfree(rqstp->rq_auth_data);
+       kfree(rqstp->rq_resp);
+       kfree(rqstp->rq_argp);
+       kfree(rqstp->rq_auth_data);
        kfree(rqstp);
 
        /* Release the server */
index 32df43372ee97cc277ed54d058f77667c8985160..aaf08cdd19f09fad9b9a36e7cdd8041606dbfd6e 100644 (file)
@@ -992,8 +992,7 @@ xdr_xcode_array2(struct xdr_buf *buf, unsigned int base,
        err = 0;
 
 out:
-       if (elem)
-               kfree(elem);
+       kfree(elem);
        if (ppages)
                kunmap(*ppages);
        return err;
index 41feca3bef86346f3890f8c428c795ff7316abf5..acc73ba8bade52770d1babc0bbf19e8abfe1cbef 100644 (file)
@@ -676,7 +676,7 @@ static struct sock *unix_find_other(struct sockaddr_un *sunname, int len,
                err = path_lookup(sunname->sun_path, LOOKUP_FOLLOW, &nd);
                if (err)
                        goto fail;
-               err = permission(nd.dentry->d_inode,MAY_WRITE, &nd);
+               err = vfs_permission(&nd, MAY_WRITE);
                if (err)
                        goto put_fail;
 
index 596cb96e5f471227c348ce214d46dce63f5cf4a7..59fec59b2132df1ab43e782d2a469a84bf373dd0 100644 (file)
@@ -1099,7 +1099,7 @@ static void release_driver(struct sock *sk)
        sock_reset_flag(sk, SOCK_ZAPPED);
        wp = wp_sk(sk);
 
-       if (wp && wp->mbox) {
+       if (wp) {
                kfree(wp->mbox);
                wp->mbox = NULL;
        }
@@ -1186,10 +1186,8 @@ static void wanpipe_kill_sock_timer (unsigned long data)
                return;
        }
 
-       if (wp_sk(sk)) {
-               kfree(wp_sk(sk));
-               wp_sk(sk) = NULL;
-       }
+       kfree(wp_sk(sk));
+       wp_sk(sk) = NULL;
 
        if (atomic_read(&sk->sk_refcnt) != 1) {
                atomic_set(&sk->sk_refcnt, 1);
@@ -1219,10 +1217,8 @@ static void wanpipe_kill_sock_accept (struct sock *sk)
        sk->sk_socket = NULL;
 
 
-       if (wp_sk(sk)) {
-               kfree(wp_sk(sk));
-               wp_sk(sk) = NULL;
-       }
+       kfree(wp_sk(sk));
+       wp_sk(sk) = NULL;
 
        if (atomic_read(&sk->sk_refcnt) != 1) {
                atomic_set(&sk->sk_refcnt, 1);
@@ -1243,10 +1239,8 @@ static void wanpipe_kill_sock_irq (struct sock *sk)
 
        sk->sk_socket = NULL;
 
-       if (wp_sk(sk)) {
-               kfree(wp_sk(sk));
-               wp_sk(sk) = NULL;
-       }
+       kfree(wp_sk(sk));
+       wp_sk(sk) = NULL;
 
        if (atomic_read(&sk->sk_refcnt) != 1) {
                atomic_set(&sk->sk_refcnt, 1);
index 13b650ad22e21a6a6bec891d5bfe8ce4efb52236..bcf7b3faa76a4020d6308f5998fead39cce7b961 100644 (file)
@@ -714,10 +714,8 @@ static int wanrouter_device_new_if(struct wan_device *wandev,
        }
 
        /* This code has moved from del_if() function */
-       if (dev->priv) {
-               kfree(dev->priv);
-               dev->priv = NULL;
-       }
+       kfree(dev->priv);
+       dev->priv = NULL;
 
 #ifdef CONFIG_WANPIPE_MULTPPP
        if (cnf->config_id == WANCONFIG_MPPP)
@@ -851,10 +849,8 @@ static int wanrouter_delete_interface(struct wan_device *wandev, char *name)
 
        /* Due to new interface linking method using dev->priv,
         * this code has moved from del_if() function.*/
-       if (dev->priv){
-               kfree(dev->priv);
-               dev->priv=NULL;
-       }
+       kfree(dev->priv);
+       dev->priv=NULL;
 
        unregister_netdev(dev);
 
index 8b9a4747417d00bbf4c6b9050f59f7ca4eb24951..7cf48aa6c95bdb48a9438c6c4a3159fefe403869 100644 (file)
@@ -62,14 +62,10 @@ static void xfrm_state_gc_destroy(struct xfrm_state *x)
 {
        if (del_timer(&x->timer))
                BUG();
-       if (x->aalg)
-               kfree(x->aalg);
-       if (x->ealg)
-               kfree(x->ealg);
-       if (x->calg)
-               kfree(x->calg);
-       if (x->encap)
-               kfree(x->encap);
+       kfree(x->aalg);
+       kfree(x->ealg);
+       kfree(x->calg);
+       kfree(x->encap);
        if (x->type) {
                x->type->destructor(x);
                xfrm_put_type(x->type);
index c65c435c4923b52de56e8d024d773a53a01848d2..9d67782b812fba60f1e44d2e30c1e8ad6e68dfd8 100644 (file)
@@ -114,7 +114,7 @@ gconf-objs  := gconf.o kconfig_load.o zconf.tab.o
 endif
 
 clean-files    := lkc_defs.h qconf.moc .tmp_qtcheck \
-                  .tmp_gtkcheck zconf.tab.c zconf.tab.h lex.zconf.c
+                  .tmp_gtkcheck zconf.tab.c lex.zconf.c zconf.hash.c
 
 # Needed for systems without gettext
 KBUILD_HAVE_NLS := $(shell \
@@ -136,12 +136,6 @@ HOSTLOADLIBES_gconf        = `pkg-config gtk+-2.0 gmodule-2.0 libglade-2.0 --libs`
 HOSTCFLAGS_gconf.o     = `pkg-config gtk+-2.0 gmodule-2.0 libglade-2.0 --cflags` \
                           -D LKC_DIRECT_LINK
 
-$(obj)/conf.o $(obj)/mconf.o $(obj)/qconf.o $(obj)/gconf.o $(obj)/kxgettext: $(obj)/zconf.tab.h
-
-$(obj)/zconf.tab.h: $(src)/zconf.tab.h_shipped
-$(obj)/zconf.tab.c: $(src)/zconf.tab.c_shipped
-$(obj)/lex.zconf.c: $(src)/lex.zconf.c_shipped
-
 $(obj)/qconf.o: $(obj)/.tmp_qtcheck
 
 ifeq ($(qconf-target),1)
@@ -207,7 +201,7 @@ $(obj)/.tmp_gtkcheck:
        fi
 endif
 
-$(obj)/zconf.tab.o: $(obj)/lex.zconf.c
+$(obj)/zconf.tab.o: $(obj)/lex.zconf.c $(obj)/zconf.hash.c
 
 $(obj)/kconfig_load.o: $(obj)/lkc_defs.h
 
@@ -223,20 +217,27 @@ $(obj)/lkc_defs.h: $(src)/lkc_proto.h
 
 
 ###
-# The following requires flex/bison
+# The following requires flex/bison/gperf
 # By default we use the _shipped versions, uncomment the following line if
 # you are modifying the flex/bison src.
 # LKC_GENPARSER := 1
 
 ifdef LKC_GENPARSER
 
-$(obj)/zconf.tab.c: $(obj)/zconf.y 
-$(obj)/zconf.tab.h: $(obj)/zconf.tab.c
+$(obj)/zconf.tab.c: $(src)/zconf.y
+$(obj)/lex.zconf.c: $(src)/zconf.l
+$(obj)/zconf.hash.c: $(src)/zconf.gperf
 
 %.tab.c: %.y
-       bison -t -d -v -b $* -p $(notdir $*) $<
+       bison -l -b $* -p $(notdir $*) $<
+       cp $@ $@_shipped
 
 lex.%.c: %.l
-       flex -P$(notdir $*) -o$@ $<
+       flex -L -P$(notdir $*) -o$@ $<
+       cp $@ $@_shipped
+
+%.hash.c: %.gperf
+       gperf < $< > $@
+       cp $@ $@_shipped
 
 endif
index bc20cab9d0d6b184d9c3479d3b20584ac386b4d5..8ba5d29d3d42d1221b2fdc1b6e137ca750513da8 100644 (file)
@@ -82,6 +82,15 @@ static void conf_askvalue(struct symbol *sym, const char *def)
        }
 
        switch (input_mode) {
+       case set_no:
+       case set_mod:
+       case set_yes:
+       case set_random:
+               if (sym_has_value(sym)) {
+                       printf("%s\n", def);
+                       return;
+               }
+               break;
        case ask_new:
        case ask_silent:
                if (sym_has_value(sym)) {
@@ -467,15 +476,14 @@ static void check_conf(struct menu *menu)
                return;
 
        sym = menu->sym;
-       if (sym) {
-               if (sym_is_changable(sym) && !sym_has_value(sym)) {
+       if (sym && !sym_has_value(sym)) {
+               if (sym_is_changable(sym) ||
+                   (sym_is_choice(sym) && sym_get_tristate_value(sym) == yes)) {
                        if (!conf_cnt++)
                                printf(_("*\n* Restart config...\n*\n"));
                        rootEntry = menu_get_parent_menu(menu);
                        conf(rootEntry);
                }
-               if (sym_is_choice(sym) && sym_get_tristate_value(sym) != mod)
-                       return;
        }
 
        for (child = menu->list; child; child = child->next)
@@ -559,6 +567,27 @@ int main(int ac, char **av)
        case ask_new:
                conf_read(NULL);
                break;
+       case set_no:
+       case set_mod:
+       case set_yes:
+       case set_random:
+               name = getenv("KCONFIG_ALLCONFIG");
+               if (name && !stat(name, &tmpstat)) {
+                       conf_read_simple(name);
+                       break;
+               }
+               switch (input_mode) {
+               case set_no:     name = "allno.config"; break;
+               case set_mod:    name = "allmod.config"; break;
+               case set_yes:    name = "allyes.config"; break;
+               case set_random: name = "allrandom.config"; break;
+               default: break;
+               }
+               if (!stat(name, &tmpstat))
+                       conf_read_simple(name);
+               else if (!stat("all.config", &tmpstat))
+                       conf_read_simple("all.config");
+               break;
        default:
                break;
        }
index 02f670cc6bb9350f6db1ea2ecd14513565ca3746..ccd45130c482cd1d682cd77be590cf023f510f37 100644 (file)
 #define LKC_DIRECT_LINK
 #include "lkc.h"
 
+static void conf_warning(const char *fmt, ...)
+       __attribute__ ((format (printf, 1, 2)));
+
+static const char *conf_filename;
+static int conf_lineno, conf_warnings, conf_unsaved;
+
 const char conf_def_filename[] = ".config";
 
 const char conf_defname[] = "arch/$ARCH/defconfig";
@@ -27,6 +33,17 @@ const char *conf_confnames[] = {
        NULL,
 };
 
+static void conf_warning(const char *fmt, ...)
+{
+       va_list ap;
+       va_start(ap, fmt);
+       fprintf(stderr, "%s:%d:warning: ", conf_filename, conf_lineno);
+       vfprintf(stderr, fmt, ap);
+       fprintf(stderr, "\n");
+       va_end(ap);
+       conf_warnings++;
+}
+
 static char *conf_expand_value(const char *in)
 {
        struct symbol *sym;
@@ -69,15 +86,12 @@ char *conf_get_default_confname(void)
        return name;
 }
 
-int conf_read(const char *name)
+int conf_read_simple(const char *name)
 {
        FILE *in = NULL;
        char line[1024];
        char *p, *p2;
-       int lineno = 0;
        struct symbol *sym;
-       struct property *prop;
-       struct expr *e;
        int i;
 
        if (name) {
@@ -95,12 +109,18 @@ int conf_read(const char *name)
                        }
                }
        }
-
        if (!in)
                return 1;
 
+       conf_filename = name;
+       conf_lineno = 0;
+       conf_warnings = 0;
+       conf_unsaved = 0;
+
        for_all_symbols(i, sym) {
                sym->flags |= SYMBOL_NEW | SYMBOL_CHANGED;
+               if (sym_is_choice(sym))
+                       sym->flags &= ~SYMBOL_NEW;
                sym->flags &= ~SYMBOL_VALID;
                switch (sym->type) {
                case S_INT:
@@ -115,7 +135,7 @@ int conf_read(const char *name)
        }
 
        while (fgets(line, sizeof(line), in)) {
-               lineno++;
+               conf_lineno++;
                sym = NULL;
                switch (line[0]) {
                case '#':
@@ -129,7 +149,10 @@ int conf_read(const char *name)
                                continue;
                        sym = sym_find(line + 9);
                        if (!sym) {
-                               fprintf(stderr, "%s:%d: trying to assign nonexistent symbol %s\n", name, lineno, line + 9);
+                               conf_warning("trying to assign nonexistent symbol %s", line + 9);
+                               break;
+                       } else if (!(sym->flags & SYMBOL_NEW)) {
+                               conf_warning("trying to reassign symbol %s", sym->name);
                                break;
                        }
                        switch (sym->type) {
@@ -143,8 +166,10 @@ int conf_read(const char *name)
                        }
                        break;
                case 'C':
-                       if (memcmp(line, "CONFIG_", 7))
+                       if (memcmp(line, "CONFIG_", 7)) {
+                               conf_warning("unexpected data");
                                continue;
+                       }
                        p = strchr(line + 7, '=');
                        if (!p)
                                continue;
@@ -154,7 +179,10 @@ int conf_read(const char *name)
                                *p2 = 0;
                        sym = sym_find(line + 7);
                        if (!sym) {
-                               fprintf(stderr, "%s:%d: trying to assign nonexistent symbol %s\n", name, lineno, line + 7);
+                               conf_warning("trying to assign nonexistent symbol %s", line + 7);
+                               break;
+                       } else if (!(sym->flags & SYMBOL_NEW)) {
+                               conf_warning("trying to reassign symbol %s", sym->name);
                                break;
                        }
                        switch (sym->type) {
@@ -175,6 +203,7 @@ int conf_read(const char *name)
                                        sym->flags &= ~SYMBOL_NEW;
                                        break;
                                }
+                               conf_warning("symbol value '%s' invalid for %s", p, sym->name);
                                break;
                        case S_STRING:
                                if (*p++ != '"')
@@ -187,8 +216,8 @@ int conf_read(const char *name)
                                        memmove(p2, p2 + 1, strlen(p2));
                                }
                                if (!p2) {
-                                       fprintf(stderr, "%s:%d: invalid string found\n", name, lineno);
-                                       exit(1);
+                                       conf_warning("invalid string found");
+                                       continue;
                                }
                        case S_INT:
                        case S_HEX:
@@ -196,8 +225,8 @@ int conf_read(const char *name)
                                        sym->user.val = strdup(p);
                                        sym->flags &= ~SYMBOL_NEW;
                                } else {
-                                       fprintf(stderr, "%s:%d: symbol value '%s' invalid for %s\n", name, lineno, p, sym->name);
-                                       exit(1);
+                                       conf_warning("symbol value '%s' invalid for %s", p, sym->name);
+                                       continue;
                                }
                                break;
                        default:
@@ -207,6 +236,7 @@ int conf_read(const char *name)
                case '\n':
                        break;
                default:
+                       conf_warning("unexpected data");
                        continue;
                }
                if (sym && sym_is_choice_value(sym)) {
@@ -215,25 +245,63 @@ int conf_read(const char *name)
                        case no:
                                break;
                        case mod:
-                               if (cs->user.tri == yes)
-                                       /* warn? */;
+                               if (cs->user.tri == yes) {
+                                       conf_warning("%s creates inconsistent choice state", sym->name);
+                                       cs->flags |= SYMBOL_NEW;
+                               }
                                break;
                        case yes:
-                               if (cs->user.tri != no)
-                                       /* warn? */;
-                               cs->user.val = sym;
+                               if (cs->user.tri != no) {
+                                       conf_warning("%s creates inconsistent choice state", sym->name);
+                                       cs->flags |= SYMBOL_NEW;
+                               } else
+                                       cs->user.val = sym;
                                break;
                        }
                        cs->user.tri = E_OR(cs->user.tri, sym->user.tri);
-                       cs->flags &= ~SYMBOL_NEW;
                }
        }
        fclose(in);
 
        if (modules_sym)
                sym_calc_value(modules_sym);
+       return 0;
+}
+
+int conf_read(const char *name)
+{
+       struct symbol *sym;
+       struct property *prop;
+       struct expr *e;
+       int i;
+
+       if (conf_read_simple(name))
+               return 1;
+
        for_all_symbols(i, sym) {
                sym_calc_value(sym);
+               if (sym_is_choice(sym) || (sym->flags & SYMBOL_AUTO))
+                       goto sym_ok;
+               if (sym_has_value(sym) && (sym->flags & SYMBOL_WRITE)) {
+                       /* check that calculated value agrees with saved value */
+                       switch (sym->type) {
+                       case S_BOOLEAN:
+                       case S_TRISTATE:
+                               if (sym->user.tri != sym_get_tristate_value(sym))
+                                       break;
+                               if (!sym_is_choice(sym))
+                                       goto sym_ok;
+                       default:
+                               if (!strcmp(sym->curr.val, sym->user.val))
+                                       goto sym_ok;
+                               break;
+                       }
+               } else if (!sym_has_value(sym) && !(sym->flags & SYMBOL_WRITE))
+                       /* no previous value and not saved */
+                       goto sym_ok;
+               conf_unsaved++;
+               /* maybe print value in verbose mode... */
+       sym_ok:
                if (sym_has_value(sym) && !sym_is_choice_value(sym)) {
                        if (sym->visible == no)
                                sym->flags |= SYMBOL_NEW;
@@ -241,8 +309,10 @@ int conf_read(const char *name)
                        case S_STRING:
                        case S_INT:
                        case S_HEX:
-                               if (!sym_string_within_range(sym, sym->user.val))
+                               if (!sym_string_within_range(sym, sym->user.val)) {
                                        sym->flags |= SYMBOL_NEW;
+                                       sym->flags &= ~SYMBOL_VALID;
+                               }
                        default:
                                break;
                        }
@@ -255,7 +325,7 @@ int conf_read(const char *name)
                                sym->flags |= e->right.sym->flags & SYMBOL_NEW;
        }
 
-       sym_change_count = 1;
+       sym_change_count = conf_warnings && conf_unsaved;
 
        return 0;
 }
index 7d39ff43e6e1facd64d6267cd443919b3d1c7381..1b36ef18c48d2ea04ac65d6cd9733b334b5ec621 100644 (file)
@@ -93,7 +93,6 @@ struct symbol {
 #define SYMBOL_NEW             0x0800
 #define SYMBOL_AUTO            0x1000
 #define SYMBOL_CHECKED         0x2000
-#define SYMBOL_CHECK_DONE      0x4000
 #define SYMBOL_WARNED          0x8000
 
 #define SYMBOL_MAXLENGTH       256
index 22dda11f758b4fa052def4f76a4f5921a7314baa..24e3c8cbb7ac379fe853c24600ad0f839e1516ce 100644 (file)
@@ -1,5 +1,5 @@
 
-#line 3 "lex.zconf.c"
+#line 3 "scripts/kconfig/lex.zconf.c"
 
 #define  YY_INT_ALIGNED short int
 
@@ -323,7 +323,7 @@ void zconffree (void *  );
 
 /* Begin user sect3 */
 
-#define zconfwrap(n) 1
+#define zconfwrap() 1
 #define YY_SKIP_YYWRAP
 
 typedef unsigned char YY_CHAR;
@@ -338,1567 +338,323 @@ int zconflineno = 1;
 
 extern char *zconftext;
 #define yytext_ptr zconftext
-static yyconst flex_int16_t yy_nxt[][38] =
+static yyconst flex_int16_t yy_nxt[][17] =
     {
     {
         0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
-        0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
-        0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
-        0,    0,    0,    0,    0,    0,    0,    0
-    },
-
-    {
-       11,   12,   13,   14,   12,   12,   15,   12,   12,   12,
-       12,   12,   12,   12,   12,   12,   12,   12,   12,   12,
-       12,   12,   12,   12,   12,   12,   12,   12,   12,   12,
-       12,   12,   12,   12,   12,   12,   12,   12
-    },
-
-    {
-       11,   12,   13,   14,   12,   12,   15,   12,   12,   12,
-       12,   12,   12,   12,   12,   12,   12,   12,   12,   12,
-
-       12,   12,   12,   12,   12,   12,   12,   12,   12,   12,
-       12,   12,   12,   12,   12,   12,   12,   12
-    },
-
-    {
-       11,   16,   16,   17,   16,   16,   16,   16,   16,   16,
-       16,   16,   16,   18,   16,   16,   18,   18,   19,   20,
-       21,   22,   18,   18,   23,   24,   18,   25,   18,   26,
-       27,   18,   28,   29,   30,   18,   18,   16
-    },
-
-    {
-       11,   16,   16,   17,   16,   16,   16,   16,   16,   16,
-       16,   16,   16,   18,   16,   16,   18,   18,   19,   20,
-       21,   22,   18,   18,   23,   24,   18,   25,   18,   26,
-       27,   18,   28,   29,   30,   18,   18,   16
-
-    },
-
-    {
-       11,   31,   32,   33,   31,   31,   31,   31,   31,   31,
-       31,   31,   31,   31,   31,   31,   31,   31,   31,   31,
-       31,   31,   31,   31,   31,   31,   31,   31,   31,   31,
-       31,   31,   31,   31,   31,   31,   31,   31
-    },
-
-    {
-       11,   31,   32,   33,   31,   31,   31,   31,   31,   31,
-       31,   31,   31,   31,   31,   31,   31,   31,   31,   31,
-       31,   31,   31,   31,   31,   31,   31,   31,   31,   31,
-       31,   31,   31,   31,   31,   31,   31,   31
-    },
-
-    {
-       11,   34,   34,   35,   34,   36,   34,   34,   36,   34,
-       34,   34,   34,   34,   34,   37,   34,   34,   34,   34,
-
-       34,   34,   34,   34,   34,   34,   34,   34,   34,   34,
-       34,   34,   34,   34,   34,   34,   34,   34
-    },
-
-    {
-       11,   34,   34,   35,   34,   36,   34,   34,   36,   34,
-       34,   34,   34,   34,   34,   37,   34,   34,   34,   34,
-       34,   34,   34,   34,   34,   34,   34,   34,   34,   34,
-       34,   34,   34,   34,   34,   34,   34,   34
-    },
-
-    {
-       11,   38,   38,   39,   40,   41,   42,   43,   41,   44,
-       45,   46,   47,   47,   48,   49,   47,   47,   47,   47,
-       47,   47,   47,   47,   47,   50,   47,   47,   47,   51,
-       47,   47,   47,   47,   47,   47,   47,   52
-
-    },
-
-    {
-       11,   38,   38,   39,   40,   41,   42,   43,   41,   44,
-       45,   46,   47,   47,   48,   49,   47,   47,   47,   47,
-       47,   47,   47,   47,   47,   50,   47,   47,   47,   51,
-       47,   47,   47,   47,   47,   47,   47,   52
-    },
-
-    {
-      -11,  -11,  -11,  -11,  -11,  -11,  -11,  -11,  -11,  -11,
-      -11,  -11,  -11,  -11,  -11,  -11,  -11,  -11,  -11,  -11,
-      -11,  -11,  -11,  -11,  -11,  -11,  -11,  -11,  -11,  -11,
-      -11,  -11,  -11,  -11,  -11,  -11,  -11,  -11
-    },
-
-    {
-       11,  -12,  -12,  -12,  -12,  -12,  -12,  -12,  -12,  -12,
-      -12,  -12,  -12,  -12,  -12,  -12,  -12,  -12,  -12,  -12,
-
-      -12,  -12,  -12,  -12,  -12,  -12,  -12,  -12,  -12,  -12,
-      -12,  -12,  -12,  -12,  -12,  -12,  -12,  -12
-    },
-
-    {
-       11,  -13,   53,   54,  -13,  -13,   55,  -13,  -13,  -13,
-      -13,  -13,  -13,  -13,  -13,  -13,  -13,  -13,  -13,  -13,
-      -13,  -13,  -13,  -13,  -13,  -13,  -13,  -13,  -13,  -13,
-      -13,  -13,  -13,  -13,  -13,  -13,  -13,  -13
-    },
-
-    {
-       11,  -14,  -14,  -14,  -14,  -14,  -14,  -14,  -14,  -14,
-      -14,  -14,  -14,  -14,  -14,  -14,  -14,  -14,  -14,  -14,
-      -14,  -14,  -14,  -14,  -14,  -14,  -14,  -14,  -14,  -14,
-      -14,  -14,  -14,  -14,  -14,  -14,  -14,  -14
-
-    },
-
-    {
-       11,   56,   56,   57,   56,   56,   56,   56,   56,   56,
-       56,   56,   56,   56,   56,   56,   56,   56,   56,   56,
-       56,   56,   56,   56,   56,   56,   56,   56,   56,   56,
-       56,   56,   56,   56,   56,   56,   56,   56
-    },
-
-    {
-       11,  -16,  -16,  -16,  -16,  -16,  -16,  -16,  -16,  -16,
-      -16,  -16,  -16,  -16,  -16,  -16,  -16,  -16,  -16,  -16,
-      -16,  -16,  -16,  -16,  -16,  -16,  -16,  -16,  -16,  -16,
-      -16,  -16,  -16,  -16,  -16,  -16,  -16,  -16
-    },
-
-    {
-       11,  -17,  -17,  -17,  -17,  -17,  -17,  -17,  -17,  -17,
-      -17,  -17,  -17,  -17,  -17,  -17,  -17,  -17,  -17,  -17,
-
-      -17,  -17,  -17,  -17,  -17,  -17,  -17,  -17,  -17,  -17,
-      -17,  -17,  -17,  -17,  -17,  -17,  -17,  -17
-    },
-
-    {
-       11,  -18,  -18,  -18,  -18,  -18,  -18,  -18,  -18,  -18,
-      -18,  -18,  -18,   58,  -18,  -18,   58,   58,   58,   58,
-       58,   58,   58,   58,   58,   58,   58,   58,   58,   58,
-       58,   58,   58,   58,   58,   58,   58,  -18
-    },
-
-    {
-       11,  -19,  -19,  -19,  -19,  -19,  -19,  -19,  -19,  -19,
-      -19,  -19,  -19,   58,  -19,  -19,   58,   58,   58,   58,
-       58,   58,   58,   58,   58,   58,   58,   58,   58,   59,
-       58,   58,   58,   58,   58,   58,   58,  -19
-
-    },
-
-    {
-       11,  -20,  -20,  -20,  -20,  -20,  -20,  -20,  -20,  -20,
-      -20,  -20,  -20,   58,  -20,  -20,   58,   58,   58,   58,
-       58,   58,   58,   58,   60,   58,   58,   58,   58,   61,
-       58,   58,   58,   58,   58,   58,   58,  -20
-    },
-
-    {
-       11,  -21,  -21,  -21,  -21,  -21,  -21,  -21,  -21,  -21,
-      -21,  -21,  -21,   58,  -21,  -21,   58,   58,   58,   58,
-       58,   62,   58,   58,   58,   58,   58,   58,   58,   58,
-       58,   58,   58,   58,   58,   58,   58,  -21
-    },
-
-    {
-       11,  -22,  -22,  -22,  -22,  -22,  -22,  -22,  -22,  -22,
-      -22,  -22,  -22,   58,  -22,  -22,   58,   58,   58,   58,
-
-       58,   58,   58,   58,   58,   58,   58,   58,   63,   58,
-       58,   58,   58,   58,   58,   58,   58,  -22
-    },
-
-    {
-       11,  -23,  -23,  -23,  -23,  -23,  -23,  -23,  -23,  -23,
-      -23,  -23,  -23,   58,  -23,  -23,   58,   58,   58,   58,
-       58,   64,   58,   58,   58,   58,   58,   58,   58,   58,
-       58,   58,   58,   58,   58,   58,   58,  -23
-    },
-
-    {
-       11,  -24,  -24,  -24,  -24,  -24,  -24,  -24,  -24,  -24,
-      -24,  -24,  -24,   58,  -24,  -24,   58,   58,   58,   58,
-       58,   58,   65,   58,   58,   58,   58,   58,   66,   58,
-       58,   58,   58,   58,   58,   58,   58,  -24
-
-    },
-
-    {
-       11,  -25,  -25,  -25,  -25,  -25,  -25,  -25,  -25,  -25,
-      -25,  -25,  -25,   58,  -25,  -25,   58,   67,   58,   58,
-       58,   68,   58,   58,   58,   58,   58,   58,   58,   58,
-       58,   58,   58,   58,   58,   58,   58,  -25
-    },
-
-    {
-       11,  -26,  -26,  -26,  -26,  -26,  -26,  -26,  -26,  -26,
-      -26,  -26,  -26,   58,  -26,  -26,   58,   58,   58,   58,
-       58,   58,   58,   58,   58,   58,   58,   58,   58,   58,
-       69,   58,   58,   58,   58,   58,   58,  -26
-    },
-
-    {
-       11,  -27,  -27,  -27,  -27,  -27,  -27,  -27,  -27,  -27,
-      -27,  -27,  -27,   58,  -27,  -27,   58,   58,   58,   58,
-
-       58,   58,   58,   58,   58,   58,   58,   58,   58,   58,
-       58,   58,   70,   58,   58,   58,   58,  -27
-    },
-
-    {
-       11,  -28,  -28,  -28,  -28,  -28,  -28,  -28,  -28,  -28,
-      -28,  -28,  -28,   58,  -28,  -28,   58,   71,   58,   58,
-       58,   72,   58,   58,   58,   58,   58,   58,   58,   58,
-       58,   58,   58,   58,   58,   58,   58,  -28
-    },
-
-    {
-       11,  -29,  -29,  -29,  -29,  -29,  -29,  -29,  -29,  -29,
-      -29,  -29,  -29,   58,  -29,  -29,   58,   58,   58,   58,
-       58,   73,   58,   58,   58,   58,   58,   58,   58,   74,
-       58,   58,   58,   58,   75,   58,   58,  -29
-
-    },
-
-    {
-       11,  -30,  -30,  -30,  -30,  -30,  -30,  -30,  -30,  -30,
-      -30,  -30,  -30,   58,  -30,  -30,   58,   58,   58,   58,
-       58,   58,   58,   58,   58,   58,   58,   58,   58,   58,
-       58,   58,   76,   58,   58,   58,   58,  -30
-    },
-
-    {
-       11,   77,   77,  -31,   77,   77,   77,   77,   77,   77,
-       77,   77,   77,   77,   77,   77,   77,   77,   77,   77,
-       77,   77,   77,   77,   77,   77,   77,   77,   77,   77,
-       77,   77,   77,   77,   77,   77,   77,   77
-    },
-
-    {
-       11,  -32,   78,   79,  -32,  -32,  -32,  -32,  -32,  -32,
-      -32,  -32,  -32,  -32,  -32,  -32,  -32,  -32,  -32,  -32,
-
-      -32,  -32,  -32,  -32,  -32,  -32,  -32,  -32,  -32,  -32,
-      -32,  -32,  -32,  -32,  -32,  -32,  -32,  -32
-    },
-
-    {
-       11,   80,  -33,  -33,   80,   80,   80,   80,   80,   80,
-       80,   80,   80,   80,   80,   80,   80,   80,   80,   80,
-       80,   80,   80,   80,   80,   80,   80,   80,   80,   80,
-       80,   80,   80,   80,   80,   80,   80,   80
-    },
-
-    {
-       11,   81,   81,   82,   81,  -34,   81,   81,  -34,   81,
-       81,   81,   81,   81,   81,  -34,   81,   81,   81,   81,
-       81,   81,   81,   81,   81,   81,   81,   81,   81,   81,
-       81,   81,   81,   81,   81,   81,   81,   81
-
-    },
-
-    {
-       11,  -35,  -35,  -35,  -35,  -35,  -35,  -35,  -35,  -35,
-      -35,  -35,  -35,  -35,  -35,  -35,  -35,  -35,  -35,  -35,
-      -35,  -35,  -35,  -35,  -35,  -35,  -35,  -35,  -35,  -35,
-      -35,  -35,  -35,  -35,  -35,  -35,  -35,  -35
-    },
-
-    {
-       11,  -36,  -36,  -36,  -36,  -36,  -36,  -36,  -36,  -36,
-      -36,  -36,  -36,  -36,  -36,  -36,  -36,  -36,  -36,  -36,
-      -36,  -36,  -36,  -36,  -36,  -36,  -36,  -36,  -36,  -36,
-      -36,  -36,  -36,  -36,  -36,  -36,  -36,  -36
-    },
-
-    {
-       11,   83,   83,   84,   83,   83,   83,   83,   83,   83,
-       83,   83,   83,   83,   83,   83,   83,   83,   83,   83,
-
-       83,   83,   83,   83,   83,   83,   83,   83,   83,   83,
-       83,   83,   83,   83,   83,   83,   83,   83
-    },
-
-    {
-       11,  -38,  -38,  -38,  -38,  -38,  -38,  -38,  -38,  -38,
-      -38,  -38,  -38,  -38,  -38,  -38,  -38,  -38,  -38,  -38,
-      -38,  -38,  -38,  -38,  -38,  -38,  -38,  -38,  -38,  -38,
-      -38,  -38,  -38,  -38,  -38,  -38,  -38,  -38
-    },
-
-    {
-       11,  -39,  -39,  -39,  -39,  -39,  -39,  -39,  -39,  -39,
-      -39,  -39,  -39,  -39,  -39,  -39,  -39,  -39,  -39,  -39,
-      -39,  -39,  -39,  -39,  -39,  -39,  -39,  -39,  -39,  -39,
-      -39,  -39,  -39,  -39,  -39,  -39,  -39,  -39
-
-    },
-
-    {
-       11,  -40,  -40,  -40,  -40,  -40,  -40,  -40,  -40,  -40,
-      -40,  -40,  -40,  -40,   85,  -40,  -40,  -40,  -40,  -40,
-      -40,  -40,  -40,  -40,  -40,  -40,  -40,  -40,  -40,  -40,
-      -40,  -40,  -40,  -40,  -40,  -40,  -40,  -40
-    },
-
-    {
-       11,  -41,  -41,  -41,  -41,  -41,  -41,  -41,  -41,  -41,
-      -41,  -41,  -41,  -41,  -41,  -41,  -41,  -41,  -41,  -41,
-      -41,  -41,  -41,  -41,  -41,  -41,  -41,  -41,  -41,  -41,
-      -41,  -41,  -41,  -41,  -41,  -41,  -41,  -41
-    },
-
-    {
-       11,   86,   86,  -42,   86,   86,   86,   86,   86,   86,
-       86,   86,   86,   86,   86,   86,   86,   86,   86,   86,
-
-       86,   86,   86,   86,   86,   86,   86,   86,   86,   86,
-       86,   86,   86,   86,   86,   86,   86,   86
-    },
-
-    {
-       11,  -43,  -43,  -43,  -43,  -43,  -43,   87,  -43,  -43,
-      -43,  -43,  -43,  -43,  -43,  -43,  -43,  -43,  -43,  -43,
-      -43,  -43,  -43,  -43,  -43,  -43,  -43,  -43,  -43,  -43,
-      -43,  -43,  -43,  -43,  -43,  -43,  -43,  -43
-    },
-
-    {
-       11,  -44,  -44,  -44,  -44,  -44,  -44,  -44,  -44,  -44,
-      -44,  -44,  -44,  -44,  -44,  -44,  -44,  -44,  -44,  -44,
-      -44,  -44,  -44,  -44,  -44,  -44,  -44,  -44,  -44,  -44,
-      -44,  -44,  -44,  -44,  -44,  -44,  -44,  -44
-
-    },
-
-    {
-       11,  -45,  -45,  -45,  -45,  -45,  -45,  -45,  -45,  -45,
-      -45,  -45,  -45,  -45,  -45,  -45,  -45,  -45,  -45,  -45,
-      -45,  -45,  -45,  -45,  -45,  -45,  -45,  -45,  -45,  -45,
-      -45,  -45,  -45,  -45,  -45,  -45,  -45,  -45
-    },
-
-    {
-       11,  -46,  -46,  -46,  -46,  -46,  -46,  -46,  -46,  -46,
-      -46,   88,   89,   89,  -46,  -46,   89,   89,   89,   89,
-       89,   89,   89,   89,   89,   89,   89,   89,   89,   89,
-       89,   89,   89,   89,   89,   89,   89,  -46
-    },
-
-    {
-       11,  -47,  -47,  -47,  -47,  -47,  -47,  -47,  -47,  -47,
-      -47,   89,   89,   89,  -47,  -47,   89,   89,   89,   89,
-
-       89,   89,   89,   89,   89,   89,   89,   89,   89,   89,
-       89,   89,   89,   89,   89,   89,   89,  -47
-    },
-
-    {
-       11,  -48,  -48,  -48,  -48,  -48,  -48,  -48,  -48,  -48,
-      -48,  -48,  -48,  -48,  -48,  -48,  -48,  -48,  -48,  -48,
-      -48,  -48,  -48,  -48,  -48,  -48,  -48,  -48,  -48,  -48,
-      -48,  -48,  -48,  -48,  -48,  -48,  -48,  -48
-    },
-
-    {
-       11,  -49,  -49,   90,  -49,  -49,  -49,  -49,  -49,  -49,
-      -49,  -49,  -49,  -49,  -49,  -49,  -49,  -49,  -49,  -49,
-      -49,  -49,  -49,  -49,  -49,  -49,  -49,  -49,  -49,  -49,
-      -49,  -49,  -49,  -49,  -49,  -49,  -49,  -49
-
-    },
-
-    {
-       11,  -50,  -50,  -50,  -50,  -50,  -50,  -50,  -50,  -50,
-      -50,   89,   89,   89,  -50,  -50,   89,   89,   89,   89,
-       89,   89,   91,   89,   89,   89,   89,   89,   89,   89,
-       89,   89,   89,   89,   89,   89,   89,  -50
-    },
-
-    {
-       11,  -51,  -51,  -51,  -51,  -51,  -51,  -51,  -51,  -51,
-      -51,   89,   89,   89,  -51,  -51,   89,   89,   89,   89,
-       89,   89,   89,   89,   89,   89,   89,   89,   92,   89,
-       89,   89,   89,   89,   89,   89,   89,  -51
-    },
-
-    {
-       11,  -52,  -52,  -52,  -52,  -52,  -52,  -52,  -52,  -52,
-      -52,  -52,  -52,  -52,  -52,  -52,  -52,  -52,  -52,  -52,
-
-      -52,  -52,  -52,  -52,  -52,  -52,  -52,  -52,  -52,  -52,
-      -52,  -52,  -52,  -52,  -52,  -52,  -52,   93
-    },
-
-    {
-       11,  -53,   53,   54,  -53,  -53,   55,  -53,  -53,  -53,
-      -53,  -53,  -53,  -53,  -53,  -53,  -53,  -53,  -53,  -53,
-      -53,  -53,  -53,  -53,  -53,  -53,  -53,  -53,  -53,  -53,
-      -53,  -53,  -53,  -53,  -53,  -53,  -53,  -53
-    },
-
-    {
-       11,  -54,  -54,  -54,  -54,  -54,  -54,  -54,  -54,  -54,
-      -54,  -54,  -54,  -54,  -54,  -54,  -54,  -54,  -54,  -54,
-      -54,  -54,  -54,  -54,  -54,  -54,  -54,  -54,  -54,  -54,
-      -54,  -54,  -54,  -54,  -54,  -54,  -54,  -54
-
-    },
-
-    {
-       11,   56,   56,   57,   56,   56,   56,   56,   56,   56,
-       56,   56,   56,   56,   56,   56,   56,   56,   56,   56,
-       56,   56,   56,   56,   56,   56,   56,   56,   56,   56,
-       56,   56,   56,   56,   56,   56,   56,   56
-    },
-
-    {
-       11,   56,   56,   57,   56,   56,   56,   56,   56,   56,
-       56,   56,   56,   56,   56,   56,   56,   56,   56,   56,
-       56,   56,   56,   56,   56,   56,   56,   56,   56,   56,
-       56,   56,   56,   56,   56,   56,   56,   56
-    },
-
-    {
-       11,  -57,  -57,  -57,  -57,  -57,  -57,  -57,  -57,  -57,
-      -57,  -57,  -57,  -57,  -57,  -57,  -57,  -57,  -57,  -57,
-
-      -57,  -57,  -57,  -57,  -57,  -57,  -57,  -57,  -57,  -57,
-      -57,  -57,  -57,  -57,  -57,  -57,  -57,  -57
-    },
-
-    {
-       11,  -58,  -58,  -58,  -58,  -58,  -58,  -58,  -58,  -58,
-      -58,  -58,  -58,   58,  -58,  -58,   58,   58,   58,   58,
-       58,   58,   58,   58,   58,   58,   58,   58,   58,   58,
-       58,   58,   58,   58,   58,   58,   58,  -58
-    },
-
-    {
-       11,  -59,  -59,  -59,  -59,  -59,  -59,  -59,  -59,  -59,
-      -59,  -59,  -59,   58,  -59,  -59,   58,   58,   58,   58,
-       58,   58,   58,   58,   58,   58,   58,   58,   58,   94,
-       58,   58,   58,   58,   58,   58,   58,  -59
-
-    },
-
-    {
-       11,  -60,  -60,  -60,  -60,  -60,  -60,  -60,  -60,  -60,
-      -60,  -60,  -60,   58,  -60,  -60,   58,   58,   58,   58,
-       58,   58,   58,   58,   58,   58,   58,   58,   58,   95,
-       58,   58,   58,   58,   58,   58,   58,  -60
-    },
-
-    {
-       11,  -61,  -61,  -61,  -61,  -61,  -61,  -61,  -61,  -61,
-      -61,  -61,  -61,   58,  -61,  -61,   58,   58,   58,   58,
-       58,   58,   58,   58,   58,   58,   58,   96,   97,   58,
-       58,   58,   58,   58,   58,   58,   58,  -61
-    },
-
-    {
-       11,  -62,  -62,  -62,  -62,  -62,  -62,  -62,  -62,  -62,
-      -62,  -62,  -62,   58,  -62,  -62,   58,   58,   58,   58,
-
-       58,   58,   98,   58,   58,   58,   58,   58,   58,   58,
-       99,   58,   58,   58,   58,   58,   58,  -62
-    },
-
-    {
-       11,  -63,  -63,  -63,  -63,  -63,  -63,  -63,  -63,  -63,
-      -63,  -63,  -63,   58,  -63,  -63,   58,  100,   58,   58,
-      101,   58,   58,   58,   58,   58,   58,   58,   58,   58,
-       58,   58,   58,   58,   58,   58,   58,  -63
-    },
-
-    {
-       11,  -64,  -64,  -64,  -64,  -64,  -64,  -64,  -64,  -64,
-      -64,  -64,  -64,   58,  -64,  -64,   58,   58,   58,   58,
-       58,   58,   58,   58,   58,   58,  102,   58,   58,   58,
-       58,   58,   58,   58,   58,   58,  103,  -64
-
-    },
-
-    {
-       11,  -65,  -65,  -65,  -65,  -65,  -65,  -65,  -65,  -65,
-      -65,  -65,  -65,   58,  -65,  -65,   58,   58,   58,   58,
-       58,   58,   58,   58,   58,   58,   58,   58,   58,   58,
-       58,   58,   58,   58,   58,   58,   58,  -65
-    },
-
-    {
-       11,  -66,  -66,  -66,  -66,  -66,  -66,  -66,  -66,  -66,
-      -66,  -66,  -66,   58,  -66,  -66,   58,   58,   58,   58,
-       58,   58,   58,   58,   58,   58,   58,   58,   58,   58,
-       58,   58,   58,   58,  104,   58,   58,  -66
-    },
-
-    {
-       11,  -67,  -67,  -67,  -67,  -67,  -67,  -67,  -67,  -67,
-      -67,  -67,  -67,   58,  -67,  -67,   58,   58,   58,   58,
-
-       58,   58,   58,   58,   58,  105,   58,   58,   58,   58,
-       58,   58,   58,   58,   58,   58,   58,  -67
-    },
-
-    {
-       11,  -68,  -68,  -68,  -68,  -68,  -68,  -68,  -68,  -68,
-      -68,  -68,  -68,   58,  -68,  -68,   58,   58,   58,   58,
-       58,   58,   58,   58,   58,   58,   58,   58,  106,   58,
-       58,   58,   58,   58,   58,   58,   58,  -68
-    },
-
-    {
-       11,  -69,  -69,  -69,  -69,  -69,  -69,  -69,  -69,  -69,
-      -69,  -69,  -69,   58,  -69,  -69,   58,   58,   58,   58,
-       58,   58,   58,   58,   58,   58,   58,   58,   58,   58,
-       58,   58,   58,   58,  107,   58,   58,  -69
-
-    },
-
-    {
-       11,  -70,  -70,  -70,  -70,  -70,  -70,  -70,  -70,  -70,
-      -70,  -70,  -70,   58,  -70,  -70,   58,   58,   58,   58,
-       58,   58,   58,   58,   58,   58,   58,   58,   58,  108,
-       58,   58,   58,   58,   58,   58,   58,  -70
-    },
-
-    {
-       11,  -71,  -71,  -71,  -71,  -71,  -71,  -71,  -71,  -71,
-      -71,  -71,  -71,   58,  -71,  -71,   58,   58,   58,   58,
-       58,   58,   58,   58,   58,   58,   58,   58,  109,   58,
-       58,   58,   58,   58,   58,   58,   58,  -71
-    },
-
-    {
-       11,  -72,  -72,  -72,  -72,  -72,  -72,  -72,  -72,  -72,
-      -72,  -72,  -72,   58,  -72,  -72,   58,   58,   58,   58,
-
-       58,   58,   58,   58,   58,   58,   58,   58,   58,   58,
-       58,  110,   58,   58,   58,   58,   58,  -72
-    },
-
-    {
-       11,  -73,  -73,  -73,  -73,  -73,  -73,  -73,  -73,  -73,
-      -73,  -73,  -73,   58,  -73,  -73,   58,   58,   58,   58,
-       58,   58,   58,   58,   58,   58,  111,   58,   58,   58,
-       58,   58,   58,   58,   58,   58,   58,  -73
-    },
-
-    {
-       11,  -74,  -74,  -74,  -74,  -74,  -74,  -74,  -74,  -74,
-      -74,  -74,  -74,   58,  -74,  -74,   58,   58,   58,   58,
-       58,   58,   58,   58,   58,   58,   58,   58,   58,   58,
-       58,   58,   58,   58,   58,  112,   58,  -74
-
-    },
-
-    {
-       11,  -75,  -75,  -75,  -75,  -75,  -75,  -75,  -75,  -75,
-      -75,  -75,  -75,   58,  -75,  -75,   58,   58,   58,   58,
-       58,   58,   58,   58,   58,   58,   58,   58,   58,   58,
-       58,   58,  113,   58,   58,   58,   58,  -75
-    },
-
-    {
-       11,  -76,  -76,  -76,  -76,  -76,  -76,  -76,  -76,  -76,
-      -76,  -76,  -76,   58,  -76,  -76,   58,   58,   58,   58,
-       58,   58,   58,   58,   58,  114,   58,   58,   58,   58,
-       58,   58,   58,   58,   58,   58,   58,  -76
-    },
-
-    {
-       11,   77,   77,  -77,   77,   77,   77,   77,   77,   77,
-       77,   77,   77,   77,   77,   77,   77,   77,   77,   77,
-
-       77,   77,   77,   77,   77,   77,   77,   77,   77,   77,
-       77,   77,   77,   77,   77,   77,   77,   77
-    },
-
-    {
-       11,  -78,   78,   79,  -78,  -78,  -78,  -78,  -78,  -78,
-      -78,  -78,  -78,  -78,  -78,  -78,  -78,  -78,  -78,  -78,
-      -78,  -78,  -78,  -78,  -78,  -78,  -78,  -78,  -78,  -78,
-      -78,  -78,  -78,  -78,  -78,  -78,  -78,  -78
-    },
-
-    {
-       11,   80,  -79,  -79,   80,   80,   80,   80,   80,   80,
-       80,   80,   80,   80,   80,   80,   80,   80,   80,   80,
-       80,   80,   80,   80,   80,   80,   80,   80,   80,   80,
-       80,   80,   80,   80,   80,   80,   80,   80
-
-    },
-
-    {
-       11,  -80,  -80,  -80,  -80,  -80,  -80,  -80,  -80,  -80,
-      -80,  -80,  -80,  -80,  -80,  -80,  -80,  -80,  -80,  -80,
-      -80,  -80,  -80,  -80,  -80,  -80,  -80,  -80,  -80,  -80,
-      -80,  -80,  -80,  -80,  -80,  -80,  -80,  -80
-    },
-
-    {
-       11,   81,   81,   82,   81,  -81,   81,   81,  -81,   81,
-       81,   81,   81,   81,   81,  -81,   81,   81,   81,   81,
-       81,   81,   81,   81,   81,   81,   81,   81,   81,   81,
-       81,   81,   81,   81,   81,   81,   81,   81
-    },
-
-    {
-       11,  -82,  -82,  -82,  -82,  -82,  -82,  -82,  -82,  -82,
-      -82,  -82,  -82,  -82,  -82,  -82,  -82,  -82,  -82,  -82,
-
-      -82,  -82,  -82,  -82,  -82,  -82,  -82,  -82,  -82,  -82,
-      -82,  -82,  -82,  -82,  -82,  -82,  -82,  -82
-    },
-
-    {
-       11,  -83,  -83,   84,  -83,  -83,  -83,  -83,  -83,  -83,
-      -83,  -83,  -83,  -83,  -83,  -83,  -83,  -83,  -83,  -83,
-      -83,  -83,  -83,  -83,  -83,  -83,  -83,  -83,  -83,  -83,
-      -83,  -83,  -83,  -83,  -83,  -83,  -83,  -83
-    },
-
-    {
-       11,  -84,  -84,  -84,  -84,  -84,  -84,  -84,  -84,  -84,
-      -84,  -84,  -84,  -84,  -84,  -84,  -84,  -84,  -84,  -84,
-      -84,  -84,  -84,  -84,  -84,  -84,  -84,  -84,  -84,  -84,
-      -84,  -84,  -84,  -84,  -84,  -84,  -84,  -84
-
-    },
-
-    {
-       11,  -85,  -85,  -85,  -85,  -85,  -85,  -85,  -85,  -85,
-      -85,  -85,  -85,  -85,  -85,  -85,  -85,  -85,  -85,  -85,
-      -85,  -85,  -85,  -85,  -85,  -85,  -85,  -85,  -85,  -85,
-      -85,  -85,  -85,  -85,  -85,  -85,  -85,  -85
-    },
-
-    {
-       11,   86,   86,  -86,   86,   86,   86,   86,   86,   86,
-       86,   86,   86,   86,   86,   86,   86,   86,   86,   86,
-       86,   86,   86,   86,   86,   86,   86,   86,   86,   86,
-       86,   86,   86,   86,   86,   86,   86,   86
-    },
-
-    {
-       11,  -87,  -87,  -87,  -87,  -87,  -87,  -87,  -87,  -87,
-      -87,  -87,  -87,  -87,  -87,  -87,  -87,  -87,  -87,  -87,
-
-      -87,  -87,  -87,  -87,  -87,  -87,  -87,  -87,  -87,  -87,
-      -87,  -87,  -87,  -87,  -87,  -87,  -87,  -87
-    },
-
-    {
-       11,  -88,  -88,  -88,  -88,  -88,  -88,  -88,  -88,  -88,
-      -88,  115,   89,   89,  -88,  -88,   89,   89,   89,   89,
-       89,   89,   89,   89,   89,   89,   89,   89,   89,   89,
-       89,   89,   89,   89,   89,   89,   89,  -88
-    },
-
-    {
-       11,  -89,  -89,  -89,  -89,  -89,  -89,  -89,  -89,  -89,
-      -89,   89,   89,   89,  -89,  -89,   89,   89,   89,   89,
-       89,   89,   89,   89,   89,   89,   89,   89,   89,   89,
-       89,   89,   89,   89,   89,   89,   89,  -89
-
-    },
-
-    {
-       11,  -90,  -90,  -90,  -90,  -90,  -90,  -90,  -90,  -90,
-      -90,  -90,  -90,  -90,  -90,  -90,  -90,  -90,  -90,  -90,
-      -90,  -90,  -90,  -90,  -90,  -90,  -90,  -90,  -90,  -90,
-      -90,  -90,  -90,  -90,  -90,  -90,  -90,  -90
-    },
-
-    {
-       11,  -91,  -91,  -91,  -91,  -91,  -91,  -91,  -91,  -91,
-      -91,   89,   89,   89,  -91,  -91,   89,   89,   89,   89,
-       89,   89,   89,   89,   89,   89,   89,   89,   89,   89,
-       89,   89,   89,   89,   89,   89,   89,  -91
-    },
-
-    {
-       11,  -92,  -92,  -92,  -92,  -92,  -92,  -92,  -92,  -92,
-      -92,   89,   89,   89,  -92,  -92,   89,   89,   89,   89,
-
-       89,   89,   89,   89,   89,   89,   89,   89,   89,   89,
-       89,   89,   89,   89,   89,   89,   89,  -92
-    },
-
-    {
-       11,  -93,  -93,  -93,  -93,  -93,  -93,  -93,  -93,  -93,
-      -93,  -93,  -93,  -93,  -93,  -93,  -93,  -93,  -93,  -93,
-      -93,  -93,  -93,  -93,  -93,  -93,  -93,  -93,  -93,  -93,
-      -93,  -93,  -93,  -93,  -93,  -93,  -93,  -93
-    },
-
-    {
-       11,  -94,  -94,  -94,  -94,  -94,  -94,  -94,  -94,  -94,
-      -94,  -94,  -94,   58,  -94,  -94,   58,   58,   58,   58,
-       58,   58,   58,   58,   58,   58,  116,   58,   58,   58,
-       58,   58,   58,   58,   58,   58,   58,  -94
-
-    },
-
-    {
-       11,  -95,  -95,  -95,  -95,  -95,  -95,  -95,  -95,  -95,
-      -95,  -95,  -95,   58,  -95,  -95,   58,   58,   58,   58,
-       58,   58,   58,   58,   58,  117,   58,   58,   58,   58,
-       58,   58,   58,   58,   58,   58,   58,  -95
-    },
-
-    {
-       11,  -96,  -96,  -96,  -96,  -96,  -96,  -96,  -96,  -96,
-      -96,  -96,  -96,   58,  -96,  -96,   58,   58,   58,   58,
-       58,   58,   58,   58,   58,   58,   58,  118,   58,   58,
-       58,   58,   58,   58,   58,   58,   58,  -96
-    },
-
-    {
-       11,  -97,  -97,  -97,  -97,  -97,  -97,  -97,  -97,  -97,
-      -97,  -97,  -97,   58,  -97,  -97,   58,   58,   58,   58,
-
-       58,   58,  119,   58,   58,   58,   58,   58,   58,   58,
-       58,   58,   58,   58,   58,   58,   58,  -97
-    },
-
-    {
-       11,  -98,  -98,  -98,  -98,  -98,  -98,  -98,  -98,  -98,
-      -98,  -98,  -98,   58,  -98,  -98,  120,  121,   58,   58,
-       58,   58,   58,   58,   58,   58,   58,   58,   58,   58,
-       58,   58,   58,   58,   58,   58,   58,  -98
-    },
-
-    {
-       11,  -99,  -99,  -99,  -99,  -99,  -99,  -99,  -99,  -99,
-      -99,  -99,  -99,   58,  -99,  -99,   58,   58,   58,   58,
-       58,  122,   58,   58,   58,   58,   58,   58,   58,   58,
-       58,   58,   58,   58,   58,   58,   58,  -99
-
-    },
-
-    {
-       11, -100, -100, -100, -100, -100, -100, -100, -100, -100,
-     -100, -100, -100,   58, -100, -100,   58,   58,  123,   58,
-       58,   58,   58,   58,   58,   58,   58,   58,   58,   58,
-       58,   58,   58,   58,   58,   58,   58, -100
-    },
-
-    {
-       11, -101, -101, -101, -101, -101, -101, -101, -101, -101,
-     -101, -101, -101,   58, -101, -101,   58,   58,   58,  124,
-       58,   58,   58,   58,   58,  125,   58,  126,   58,   58,
-       58,   58,   58,   58,   58,   58,   58, -101
-    },
-
-    {
-       11, -102, -102, -102, -102, -102, -102, -102, -102, -102,
-     -102, -102, -102,   58, -102, -102,   58,   58,   58,   58,
-
-       58,   58,   58,   58,   58,   58,   58,   58,   58,   58,
-      127,   58,   58,   58,   58,   58,   58, -102
-    },
-
-    {
-       11, -103, -103, -103, -103, -103, -103, -103, -103, -103,
-     -103, -103, -103,   58, -103, -103,   58,   58,   58,   58,
-       58,   58,   58,   58,   58,   58,   58,   58,   58,   58,
-       58,   58,   58,   58,   58,   58,   58, -103
-    },
-
-    {
-       11, -104, -104, -104, -104, -104, -104, -104, -104, -104,
-     -104, -104, -104,   58, -104, -104,   58,   58,   58,   58,
-       58,   58,   58,   58,   58,   58,   58,   58,   58,   58,
-       58,   58,   58,   58,   58,   58,   58, -104
-
-    },
-
-    {
-       11, -105, -105, -105, -105, -105, -105, -105, -105, -105,
-     -105, -105, -105,   58, -105, -105,   58,   58,   58,   58,
-       58,   58,   58,   58,   58,   58,   58,   58,  128,   58,
-       58,   58,   58,   58,   58,   58,   58, -105
-    },
-
-    {
-       11, -106, -106, -106, -106, -106, -106, -106, -106, -106,
-     -106, -106, -106,   58, -106, -106,   58,   58,   58,   58,
-       58,   58,   58,   58,   58,   58,   58,   58,   58,   58,
-       58,   58,   58,   58,   58,  129,   58, -106
-    },
-
-    {
-       11, -107, -107, -107, -107, -107, -107, -107, -107, -107,
-     -107, -107, -107,   58, -107, -107,   58,   58,   58,   58,
-
-       58,   58,   58,   58,   58,  130,   58,   58,   58,   58,
-       58,   58,   58,   58,   58,   58,   58, -107
-    },
-
-    {
-       11, -108, -108, -108, -108, -108, -108, -108, -108, -108,
-     -108, -108, -108,   58, -108, -108,   58,   58,   58,   58,
-       58,   58,   58,   58,   58,   58,   58,  131,   58,   58,
-       58,   58,   58,   58,   58,   58,   58, -108
-    },
-
-    {
-       11, -109, -109, -109, -109, -109, -109, -109, -109, -109,
-     -109, -109, -109,   58, -109, -109,   58,   58,   58,   58,
-       58,   58,   58,  132,   58,   58,   58,   58,   58,   58,
-       58,   58,   58,   58,   58,   58,   58, -109
-
-    },
-
-    {
-       11, -110, -110, -110, -110, -110, -110, -110, -110, -110,
-     -110, -110, -110,   58, -110, -110,   58,   58,   58,   58,
-       58,   58,   58,   58,   58,   58,   58,   58,   58,   58,
-       58,   58,   58,   58,   58,  133,   58, -110
-    },
-
-    {
-       11, -111, -111, -111, -111, -111, -111, -111, -111, -111,
-     -111, -111, -111,   58, -111, -111,   58,   58,   58,   58,
-       58,  134,   58,   58,   58,   58,   58,   58,   58,   58,
-       58,   58,   58,   58,   58,   58,   58, -111
-    },
-
-    {
-       11, -112, -112, -112, -112, -112, -112, -112, -112, -112,
-     -112, -112, -112,   58, -112, -112,   58,   58,   58,   58,
-
-       58,   58,   58,   58,   58,   58,   58,   58,   58,   58,
-       58,   58,  135,   58,   58,   58,   58, -112
-    },
-
-    {
-       11, -113, -113, -113, -113, -113, -113, -113, -113, -113,
-     -113, -113, -113,   58, -113, -113,   58,   58,   58,   58,
-       58,   58,   58,   58,   58,  136,   58,   58,   58,   58,
-       58,   58,   58,   58,   58,   58,   58, -113
-    },
-
-    {
-       11, -114, -114, -114, -114, -114, -114, -114, -114, -114,
-     -114, -114, -114,   58, -114, -114,   58,   58,   58,   58,
-       58,   58,   58,   58,   58,   58,   58,   58,   58,   58,
-       58,   58,   58,  137,   58,   58,   58, -114
-
-    },
-
-    {
-       11, -115, -115, -115, -115, -115, -115, -115, -115, -115,
-     -115,   89,   89,   89, -115, -115,   89,   89,   89,   89,
-       89,   89,   89,   89,   89,   89,   89,   89,   89,   89,
-       89,   89,   89,   89,   89,   89,   89, -115
-    },
-
-    {
-       11, -116, -116, -116, -116, -116, -116, -116, -116, -116,
-     -116, -116, -116,   58, -116, -116,   58,   58,   58,   58,
-       58,  138,   58,   58,   58,   58,   58,   58,   58,   58,
-       58,   58,   58,   58,   58,   58,   58, -116
-    },
-
-    {
-       11, -117, -117, -117, -117, -117, -117, -117, -117, -117,
-     -117, -117, -117,   58, -117, -117,   58,   58,   58,  139,
-
-       58,   58,   58,   58,   58,   58,   58,   58,   58,   58,
-       58,   58,   58,   58,   58,   58,   58, -117
-    },
-
-    {
-       11, -118, -118, -118, -118, -118, -118, -118, -118, -118,
-     -118, -118, -118,   58, -118, -118,   58,   58,   58,   58,
-       58,  140,   58,   58,   58,   58,   58,   58,   58,   58,
-       58,   58,   58,   58,   58,   58,   58, -118
-    },
-
-    {
-       11, -119, -119, -119, -119, -119, -119, -119, -119, -119,
-     -119, -119, -119,   58, -119, -119,   58,   58,   58,   58,
-       58,   58,   58,   58,   58,  141,   58,   58,   58,   58,
-       58,   58,   58,   58,   58,   58,   58, -119
-
-    },
-
-    {
-       11, -120, -120, -120, -120, -120, -120, -120, -120, -120,
-     -120, -120, -120,   58, -120, -120,   58,   58,  142,   58,
-       58,   58,   58,   58,   58,   58,   58,   58,   58,   58,
-       58,   58,   58,   58,  143,   58,   58, -120
-    },
-
-    {
-       11, -121, -121, -121, -121, -121, -121, -121, -121, -121,
-     -121, -121, -121,   58, -121, -121,   58,   58,   58,   58,
-       58,   58,   58,   58,   58,   58,   58,   58,   58,   58,
-       58,   58,   58,   58,   58,  144,   58, -121
-    },
-
-    {
-       11, -122, -122, -122, -122, -122, -122, -122, -122, -122,
-     -122, -122, -122,   58, -122, -122,   58,   58,   58,   58,
-
-       58,   58,   58,   58,   58,   58,   58,   58,  145,   58,
-       58,   58,   58,   58,   58,   58,   58, -122
-    },
-
-    {
-       11, -123, -123, -123, -123, -123, -123, -123, -123, -123,
-     -123, -123, -123,   58, -123, -123,   58,   58,   58,   58,
-       58,   58,   58,   58,   58,   58,  146,   58,   58,   58,
-       58,   58,   58,   58,   58,   58,   58, -123
-    },
-
-    {
-       11, -124, -124, -124, -124, -124, -124, -124, -124, -124,
-     -124, -124, -124,   58, -124, -124,   58,   58,   58,   58,
-       58,   58,   58,   58,  147,   58,   58,   58,   58,   58,
-       58,   58,   58,   58,   58,   58,   58, -124
-
-    },
-
-    {
-       11, -125, -125, -125, -125, -125, -125, -125, -125, -125,
-     -125, -125, -125,   58, -125, -125,   58,   58,   58,   58,
-       58,   58,  148,   58,   58,   58,   58,   58,   58,   58,
-       58,   58,   58,   58,   58,   58,   58, -125
-    },
-
-    {
-       11, -126, -126, -126, -126, -126, -126, -126, -126, -126,
-     -126, -126, -126,   58, -126, -126,   58,   58,   58,   58,
-       58,  149,   58,   58,   58,   58,   58,   58,   58,   58,
-       58,   58,   58,   58,   58,   58,   58, -126
-    },
-
-    {
-       11, -127, -127, -127, -127, -127, -127, -127, -127, -127,
-     -127, -127, -127,   58, -127, -127,   58,   58,   58,   58,
-
-       58,   58,   58,   58,   58,   58,   58,   58,   58,   58,
-       58,   58,   58,   58,   58,   58,   58, -127
-    },
-
-    {
-       11, -128, -128, -128, -128, -128, -128, -128, -128, -128,
-     -128, -128, -128,   58, -128, -128,   58,   58,   58,   58,
-       58,   58,   58,   58,   58,   58,   58,  150,   58,   58,
-       58,   58,   58,   58,   58,   58,   58, -128
-    },
-
-    {
-       11, -129, -129, -129, -129, -129, -129, -129, -129, -129,
-     -129, -129, -129,   58, -129, -129,   58,   58,   58,  151,
-       58,   58,   58,   58,   58,   58,   58,   58,   58,   58,
-       58,   58,   58,   58,   58,   58,   58, -129
-
-    },
-
-    {
-       11, -130, -130, -130, -130, -130, -130, -130, -130, -130,
-     -130, -130, -130,   58, -130, -130,   58,   58,   58,   58,
-       58,   58,   58,   58,   58,   58,   58,   58,   58,  152,
-       58,   58,   58,   58,   58,   58,   58, -130
-    },
-
-    {
-       11, -131, -131, -131, -131, -131, -131, -131, -131, -131,
-     -131, -131, -131,   58, -131, -131,   58,   58,   58,   58,
-       58,   58,   58,   58,   58,   58,   58,   58,   58,   58,
-      153,   58,   58,   58,   58,   58,   58, -131
-    },
-
-    {
-       11, -132, -132, -132, -132, -132, -132, -132, -132, -132,
-     -132, -132, -132,   58, -132, -132,   58,   58,   58,   58,
-
-       58,  154,   58,   58,   58,   58,   58,   58,   58,   58,
-       58,   58,   58,   58,   58,   58,   58, -132
-    },
-
-    {
-       11, -133, -133, -133, -133, -133, -133, -133, -133, -133,
-     -133, -133, -133,   58, -133, -133,   58,   58,   58,   58,
-       58,   58,   58,   58,   58,  155,   58,   58,   58,   58,
-       58,   58,   58,   58,   58,   58,   58, -133
-    },
-
-    {
-       11, -134, -134, -134, -134, -134, -134, -134, -134, -134,
-     -134, -134, -134,   58, -134, -134,   58,   58,   58,  156,
-       58,   58,   58,   58,   58,   58,   58,   58,   58,   58,
-       58,   58,   58,   58,   58,   58,   58, -134
-
-    },
-
-    {
-       11, -135, -135, -135, -135, -135, -135, -135, -135, -135,
-     -135, -135, -135,   58, -135, -135,   58,   58,   58,  157,
-       58,   58,   58,   58,   58,   58,   58,   58,   58,   58,
-       58,   58,   58,   58,   58,   58,   58, -135
-    },
-
-    {
-       11, -136, -136, -136, -136, -136, -136, -136, -136, -136,
-     -136, -136, -136,   58, -136, -136,   58,   58,   58,   58,
-       58,   58,   58,   58,   58,   58,   58,   58,  158,   58,
-       58,   58,   58,   58,   58,   58,   58, -136
-    },
-
-    {
-       11, -137, -137, -137, -137, -137, -137, -137, -137, -137,
-     -137, -137, -137,   58, -137, -137,   58,   58,   58,   58,
-
-       58,   58,   58,   58,   58,   58,   58,   58,   58,   58,
-       58,   58,   58,   58,  159,   58,   58, -137
-    },
-
-    {
-       11, -138, -138, -138, -138, -138, -138, -138, -138, -138,
-     -138, -138, -138,   58, -138, -138,   58,  160,   58,   58,
-       58,   58,   58,   58,   58,   58,   58,   58,   58,   58,
-       58,   58,   58,   58,   58,   58,   58, -138
-    },
-
-    {
-       11, -139, -139, -139, -139, -139, -139, -139, -139, -139,
-     -139, -139, -139,   58, -139, -139,   58,   58,   58,   58,
-       58,  161,   58,   58,   58,   58,   58,   58,   58,   58,
-       58,   58,   58,   58,   58,   58,   58, -139
-
-    },
-
-    {
-       11, -140, -140, -140, -140, -140, -140, -140, -140, -140,
-     -140, -140, -140,   58, -140, -140,   58,   58,   58,   58,
-       58,   58,   58,   58,   58,   58,   58,   58,  162,   58,
-       58,   58,   58,   58,   58,   58,   58, -140
-    },
-
-    {
-       11, -141, -141, -141, -141, -141, -141, -141, -141, -141,
-     -141, -141, -141,   58, -141, -141,   58,   58,   58,   58,
-       58,   58,   58,  163,   58,   58,   58,   58,   58,   58,
-       58,   58,   58,   58,   58,   58,   58, -141
-    },
-
-    {
-       11, -142, -142, -142, -142, -142, -142, -142, -142, -142,
-     -142, -142, -142,   58, -142, -142,   58,   58,   58,   58,
-
-       58,   58,   58,   58,   58,   58,   58,   58,   58,  164,
-       58,   58,   58,   58,   58,   58,   58, -142
-    },
-
-    {
-       11, -143, -143, -143, -143, -143, -143, -143, -143, -143,
-     -143, -143, -143,   58, -143, -143,   58,   58,   58,   58,
-       58,   58,   58,   58,   58,   58,   58,   58,   58,   58,
-       58,   58,  165,   58,   58,   58,   58, -143
-    },
-
-    {
-       11, -144, -144, -144, -144, -144, -144, -144, -144, -144,
-     -144, -144, -144,   58, -144, -144,   58,   58,   58,   58,
-       58,   58,   58,   58,   58,   58,  166,   58,   58,   58,
-       58,   58,   58,   58,   58,   58,   58, -144
-
-    },
-
-    {
-       11, -145, -145, -145, -145, -145, -145, -145, -145, -145,
-     -145, -145, -145,   58, -145, -145,   58,   58,   58,   58,
-      167,   58,   58,   58,   58,   58,   58,   58,   58,   58,
-       58,   58,   58,   58,   58,   58,   58, -145
-    },
-
-    {
-       11, -146, -146, -146, -146, -146, -146, -146, -146, -146,
-     -146, -146, -146,   58, -146, -146,   58,   58,   58,   58,
-       58,  168,   58,   58,   58,   58,   58,   58,   58,   58,
-       58,   58,   58,   58,   58,   58,   58, -146
-    },
-
-    {
-       11, -147, -147, -147, -147, -147, -147, -147, -147, -147,
-     -147, -147, -147,   58, -147, -147,   58,   58,   58,   58,
-
-       58,   58,   58,   58,   58,   58,   58,   58,   58,  169,
-       58,   58,   58,   58,   58,   58,   58, -147
-    },
-
-    {
-       11, -148, -148, -148, -148, -148, -148, -148, -148, -148,
-     -148, -148, -148,   58, -148, -148,   58,   58,   58,   58,
-       58,   58,   58,   58,   58,   58,   58,   58,   58,   58,
-       58,   58,   58,   58,   58,   58,   58, -148
-    },
-
-    {
-       11, -149, -149, -149, -149, -149, -149, -149, -149, -149,
-     -149, -149, -149,   58, -149, -149,   58,   58,   58,   58,
-       58,   58,   58,   58,   58,   58,   58,   58,  170,   58,
-       58,   58,   58,   58,   58,   58,   58, -149
-
-    },
-
-    {
-       11, -150, -150, -150, -150, -150, -150, -150, -150, -150,
-     -150, -150, -150,   58, -150, -150,   58,   58,   58,   58,
-       58,  171,   58,   58,   58,   58,   58,   58,   58,   58,
-       58,   58,   58,   58,   58,   58,   58, -150
+        0,    0,    0,    0,    0,    0,    0
     },
 
     {
-       11, -151, -151, -151, -151, -151, -151, -151, -151, -151,
-     -151, -151, -151,   58, -151, -151,   58,   58,   58,   58,
-       58,   58,   58,   58,   58,   58,   58,   58,   58,  172,
-       58,   58,   58,   58,   58,   58,   58, -151
+       11,   12,   13,   14,   12,   12,   15,   12,   12,   12,
+       12,   12,   12,   12,   12,   12,   12
     },
 
     {
-       11, -152, -152, -152, -152, -152, -152, -152, -152, -152,
-     -152, -152, -152,   58, -152, -152,   58,   58,   58,   58,
-
-       58,   58,   58,   58,   58,   58,   58,   58,  173,   58,
-       58,   58,   58,   58,   58,   58,   58, -152
+       11,   12,   13,   14,   12,   12,   15,   12,   12,   12,
+       12,   12,   12,   12,   12,   12,   12
     },
 
     {
-       11, -153, -153, -153, -153, -153, -153, -153, -153, -153,
-     -153, -153, -153,   58, -153, -153,   58,   58,   58,   58,
-       58,   58,   58,   58,   58,   58,   58,   58,   58,   58,
-       58,   58,   58,   58,  174,   58,   58, -153
+       11,   16,   16,   17,   16,   16,   16,   16,   16,   16,
+       16,   16,   16,   18,   16,   16,   16
     },
 
     {
-       11, -154, -154, -154, -154, -154, -154, -154, -154, -154,
-     -154, -154, -154,   58, -154, -154,   58,   58,   58,   58,
-       58,   58,   58,   58,   58,   58,   58,   58,   58,   58,
-       58,   58,   58,   58,   58,   58,   58, -154
+       11,   16,   16,   17,   16,   16,   16,   16,   16,   16,
+       16,   16,   16,   18,   16,   16,   16
 
     },
 
     {
-       11, -155, -155, -155, -155, -155, -155, -155, -155, -155,
-     -155, -155, -155,   58, -155, -155,   58,   58,   58,   58,
-       58,   58,   58,   58,   58,   58,   58,   58,   58,   58,
-       58,   58,  175,   58,   58,   58,   58, -155
+       11,   19,   20,   21,   19,   19,   19,   19,   19,   19,
+       19,   19,   19,   19,   19,   19,   19
     },
 
     {
-       11, -156, -156, -156, -156, -156, -156, -156, -156, -156,
-     -156, -156, -156,   58, -156, -156,   58,   58,   58,   58,
-       58,   58,   58,   58,   58,   58,   58,   58,   58,   58,
-       58,   58,   58,   58,  176,   58,   58, -156
+       11,   19,   20,   21,   19,   19,   19,   19,   19,   19,
+       19,   19,   19,   19,   19,   19,   19
     },
 
     {
-       11, -157, -157, -157, -157, -157, -157, -157, -157, -157,
-     -157, -157, -157,   58, -157, -157,   58,   58,   58,   58,
-
-       58,  177,   58,   58,   58,   58,   58,   58,   58,   58,
-       58,   58,   58,   58,   58,   58,   58, -157
+       11,   22,   22,   23,   22,   24,   22,   22,   24,   22,
+       22,   22,   22,   22,   22,   25,   22
     },
 
     {
-       11, -158, -158, -158, -158, -158, -158, -158, -158, -158,
-     -158, -158, -158,   58, -158, -158,   58,   58,   58,   58,
-       58,   58,   58,  178,   58,   58,   58,   58,   58,   58,
-       58,   58,   58,   58,   58,   58,   58, -158
+       11,   22,   22,   23,   22,   24,   22,   22,   24,   22,
+       22,   22,   22,   22,   22,   25,   22
     },
 
     {
-       11, -159, -159, -159, -159, -159, -159, -159, -159, -159,
-     -159, -159, -159,   58, -159, -159,   58,  179,   58,   58,
-       58,   58,   58,   58,   58,   58,   58,   58,   58,   58,
-       58,   58,   58,   58,   58,   58,   58, -159
+       11,   26,   26,   27,   28,   29,   30,   31,   29,   32,
+       33,   34,   35,   35,   36,   37,   38
 
     },
 
     {
-       11, -160, -160, -160, -160, -160, -160, -160, -160, -160,
-     -160, -160, -160,   58, -160, -160,   58,   58,   58,   58,
-       58,   58,   58,   58,   58,   58,   58,   58,  180,   58,
-       58,   58,   58,   58,   58,   58,   58, -160
+       11,   26,   26,   27,   28,   29,   30,   31,   29,   32,
+       33,   34,   35,   35,   36,   37,   38
     },
 
     {
-       11, -161, -161, -161, -161, -161, -161, -161, -161, -161,
-     -161, -161, -161,   58, -161, -161,   58,   58,   58,   58,
-       58,   58,   58,   58,   58,   58,   58,   58,   58,   58,
-       58,   58,   58,   58,   58,   58,   58, -161
+      -11,  -11,  -11,  -11,  -11,  -11,  -11,  -11,  -11,  -11,
+      -11,  -11,  -11,  -11,  -11,  -11,  -11
     },
 
     {
-       11, -162, -162, -162, -162, -162, -162, -162, -162, -162,
-     -162, -162, -162,   58, -162, -162,   58,   58,   58,   58,
-
-       58,   58,   58,   58,   58,   58,   58,   58,   58,   58,
-       58,   58,   58,   58,  181,   58,   58, -162
+       11,  -12,  -12,  -12,  -12,  -12,  -12,  -12,  -12,  -12,
+      -12,  -12,  -12,  -12,  -12,  -12,  -12
     },
 
     {
-       11, -163, -163, -163, -163, -163, -163, -163, -163, -163,
-     -163, -163, -163,   58, -163, -163,   58,   58,   58,   58,
-       58,   58,   58,   58,   58,   58,   58,   58,   58,   58,
-       58,   58,   58,   58,   58,   58,   58, -163
+       11,  -13,   39,   40,  -13,  -13,   41,  -13,  -13,  -13,
+      -13,  -13,  -13,  -13,  -13,  -13,  -13
     },
 
     {
-       11, -164, -164, -164, -164, -164, -164, -164, -164, -164,
-     -164, -164, -164,   58, -164, -164,   58,   58,   58,   58,
-       58,   58,   58,   58,   58,   58,   58,   58,   58,  182,
-       58,   58,   58,   58,   58,   58,   58, -164
+       11,  -14,  -14,  -14,  -14,  -14,  -14,  -14,  -14,  -14,
+      -14,  -14,  -14,  -14,  -14,  -14,  -14
 
     },
 
     {
-       11, -165, -165, -165, -165, -165, -165, -165, -165, -165,
-     -165, -165, -165,   58, -165, -165,   58,   58,   58,   58,
-       58,   58,   58,   58,   58,  183,   58,   58,   58,   58,
-       58,   58,   58,   58,   58,   58,   58, -165
+       11,   42,   42,   43,   42,   42,   42,   42,   42,   42,
+       42,   42,   42,   42,   42,   42,   42
     },
 
     {
-       11, -166, -166, -166, -166, -166, -166, -166, -166, -166,
-     -166, -166, -166,   58, -166, -166,   58,   58,   58,   58,
-       58,   58,   58,   58,   58,   58,   58,   58,   58,   58,
-       58,   58,   58,   58,  184,   58,   58, -166
+       11,  -16,  -16,  -16,  -16,  -16,  -16,  -16,  -16,  -16,
+      -16,  -16,  -16,  -16,  -16,  -16,  -16
     },
 
     {
-       11, -167, -167, -167, -167, -167, -167, -167, -167, -167,
-     -167, -167, -167,   58, -167, -167,   58,   58,   58,   58,
-
-       58,   58,   58,   58,   58,   58,   58,   58,   58,   58,
-       58,   58,   58,  185,   58,   58,   58, -167
+       11,  -17,  -17,  -17,  -17,  -17,  -17,  -17,  -17,  -17,
+      -17,  -17,  -17,  -17,  -17,  -17,  -17
     },
 
     {
-       11, -168, -168, -168, -168, -168, -168, -168, -168, -168,
-     -168, -168, -168,   58, -168, -168,   58,   58,   58,   58,
-       58,   58,   58,   58,   58,   58,   58,   58,   58,   58,
-       58,   58,   58,   58,   58,   58,   58, -168
+       11,  -18,  -18,  -18,  -18,  -18,  -18,  -18,  -18,  -18,
+      -18,  -18,  -18,   44,  -18,  -18,  -18
     },
 
     {
-       11, -169, -169, -169, -169, -169, -169, -169, -169, -169,
-     -169, -169, -169,   58, -169, -169,   58,   58,   58,   58,
-       58,   58,   58,   58,   58,  186,   58,   58,   58,   58,
-       58,   58,   58,   58,   58,   58,   58, -169
+       11,   45,   45,  -19,   45,   45,   45,   45,   45,   45,
+       45,   45,   45,   45,   45,   45,   45
 
     },
 
     {
-       11, -170, -170, -170, -170, -170, -170, -170, -170, -170,
-     -170, -170, -170,   58, -170, -170,   58,   58,   58,   58,
-       58,   58,   58,   58,   58,   58,   58,   58,   58,   58,
-       58,   58,   58,   58,   58,  187,   58, -170
+       11,  -20,   46,   47,  -20,  -20,  -20,  -20,  -20,  -20,
+      -20,  -20,  -20,  -20,  -20,  -20,  -20
     },
 
     {
-       11, -171, -171, -171, -171, -171, -171, -171, -171, -171,
-     -171, -171, -171,   58, -171, -171,   58,   58,   58,   58,
-       58,   58,   58,   58,   58,   58,   58,   58,  188,   58,
-       58,   58,   58,   58,   58,   58,   58, -171
+       11,   48,  -21,  -21,   48,   48,   48,   48,   48,   48,
+       48,   48,   48,   48,   48,   48,   48
     },
 
     {
-       11, -172, -172, -172, -172, -172, -172, -172, -172, -172,
-     -172, -172, -172,   58, -172, -172,   58,   58,   58,   58,
-
-       58,   58,   58,   58,   58,   58,   58,   58,  189,   58,
-       58,   58,   58,   58,   58,   58,   58, -172
+       11,   49,   49,   50,   49,  -22,   49,   49,  -22,   49,
+       49,   49,   49,   49,   49,  -22,   49
     },
 
     {
-       11, -173, -173, -173, -173, -173, -173, -173, -173, -173,
-     -173, -173, -173,   58, -173, -173,   58,  190,   58,   58,
-       58,   58,   58,   58,   58,   58,   58,   58,   58,   58,
-       58,   58,   58,   58,   58,   58,   58, -173
+       11,  -23,  -23,  -23,  -23,  -23,  -23,  -23,  -23,  -23,
+      -23,  -23,  -23,  -23,  -23,  -23,  -23
     },
 
     {
-       11, -174, -174, -174, -174, -174, -174, -174, -174, -174,
-     -174, -174, -174,   58, -174, -174,   58,   58,   58,   58,
-       58,   58,   58,   58,   58,   58,   58,   58,   58,   58,
-       58,   58,   58,   58,   58,   58,   58, -174
+       11,  -24,  -24,  -24,  -24,  -24,  -24,  -24,  -24,  -24,
+      -24,  -24,  -24,  -24,  -24,  -24,  -24
 
     },
 
     {
-       11, -175, -175, -175, -175, -175, -175, -175, -175, -175,
-     -175, -175, -175,   58, -175, -175,   58,   58,   58,   58,
-       58,  191,   58,   58,   58,   58,   58,   58,   58,   58,
-       58,   58,   58,   58,   58,   58,   58, -175
+       11,   51,   51,   52,   51,   51,   51,   51,   51,   51,
+       51,   51,   51,   51,   51,   51,   51
     },
 
     {
-       11, -176, -176, -176, -176, -176, -176, -176, -176, -176,
-     -176, -176, -176,   58, -176, -176,   58,   58,   58,   58,
-       58,   58,   58,   58,   58,   58,   58,   58,   58,   58,
-       58,   58,   58,   58,   58,   58,   58, -176
+       11,  -26,  -26,  -26,  -26,  -26,  -26,  -26,  -26,  -26,
+      -26,  -26,  -26,  -26,  -26,  -26,  -26
     },
 
     {
-       11, -177, -177, -177, -177, -177, -177, -177, -177, -177,
-     -177, -177, -177,   58, -177, -177,   58,   58,   58,   58,
-
-       58,   58,   58,   58,   58,   58,   58,   58,   58,   58,
-       58,   58,   58,   58,   58,   58,   58, -177
+       11,  -27,  -27,  -27,  -27,  -27,  -27,  -27,  -27,  -27,
+      -27,  -27,  -27,  -27,  -27,  -27,  -27
     },
 
     {
-       11, -178, -178, -178, -178, -178, -178, -178, -178, -178,
-     -178, -178, -178,   58, -178, -178,   58,   58,   58,   58,
-       58,   58,   58,   58,   58,   58,   58,   58,   58,   58,
-       58,   58,   58,   58,   58,   58,   58, -178
+       11,  -28,  -28,  -28,  -28,  -28,  -28,  -28,  -28,  -28,
+      -28,  -28,  -28,  -28,   53,  -28,  -28
     },
 
     {
-       11, -179, -179, -179, -179, -179, -179, -179, -179, -179,
-     -179, -179, -179,   58, -179, -179,   58,   58,   58,   58,
-       58,   58,   58,   58,   58,   58,   58,   58,   58,   58,
-       58,   58,   58,   58,  192,   58,   58, -179
+       11,  -29,  -29,  -29,  -29,  -29,  -29,  -29,  -29,  -29,
+      -29,  -29,  -29,  -29,  -29,  -29,  -29
 
     },
 
     {
-       11, -180, -180, -180, -180, -180, -180, -180, -180, -180,
-     -180, -180, -180,   58, -180, -180,   58,   58,   58,   58,
-       58,   58,   58,   58,   58,   58,   58,   58,   58,   58,
-       58,   58,   58,   58,   58,   58,   58, -180
+       11,   54,   54,  -30,   54,   54,   54,   54,   54,   54,
+       54,   54,   54,   54,   54,   54,   54
     },
 
     {
-       11, -181, -181, -181, -181, -181, -181, -181, -181, -181,
-     -181, -181, -181,   58, -181, -181,   58,   58,   58,   58,
-       58,   58,   58,   58,   58,   58,   58,   58,   58,   58,
-       58,   58,   58,   58,   58,   58,   58, -181
+       11,  -31,  -31,  -31,  -31,  -31,  -31,   55,  -31,  -31,
+      -31,  -31,  -31,  -31,  -31,  -31,  -31
     },
 
     {
-       11, -182, -182, -182, -182, -182, -182, -182, -182, -182,
-     -182, -182, -182,   58, -182, -182,   58,   58,   58,   58,
-
-       58,   58,   58,   58,   58,   58,  193,   58,   58,   58,
-       58,   58,   58,   58,   58,   58,   58, -182
+       11,  -32,  -32,  -32,  -32,  -32,  -32,  -32,  -32,  -32,
+      -32,  -32,  -32,  -32,  -32,  -32,  -32
     },
 
     {
-       11, -183, -183, -183, -183, -183, -183, -183, -183, -183,
-     -183, -183, -183,   58, -183, -183,   58,   58,   58,   58,
-       58,   58,   58,   58,   58,   58,   58,   58,   58,   58,
-       58,   58,   58,  194,   58,   58,   58, -183
+       11,  -33,  -33,  -33,  -33,  -33,  -33,  -33,  -33,  -33,
+      -33,  -33,  -33,  -33,  -33,  -33,  -33
     },
 
     {
-       11, -184, -184, -184, -184, -184, -184, -184, -184, -184,
-     -184, -184, -184,   58, -184, -184,   58,   58,   58,   58,
-       58,   58,   58,   58,   58,   58,   58,   58,   58,   58,
-       58,   58,   58,   58,   58,   58,   58, -184
+       11,  -34,  -34,  -34,  -34,  -34,  -34,  -34,  -34,  -34,
+      -34,   56,   57,   57,  -34,  -34,  -34
 
     },
 
     {
-       11, -185, -185, -185, -185, -185, -185, -185, -185, -185,
-     -185, -185, -185,   58, -185, -185,   58,   58,   58,   58,
-       58,   58,   58,   58,   58,   58,   58,   58,   58,   58,
-       58,   58,   58,   58,   58,   58,   58, -185
+       11,  -35,  -35,  -35,  -35,  -35,  -35,  -35,  -35,  -35,
+      -35,   57,   57,   57,  -35,  -35,  -35
     },
 
     {
-       11, -186, -186, -186, -186, -186, -186, -186, -186, -186,
-     -186, -186, -186,   58, -186, -186,   58,   58,   58,  195,
-       58,   58,   58,   58,   58,   58,   58,   58,   58,   58,
-       58,   58,   58,   58,   58,   58,   58, -186
+       11,  -36,  -36,  -36,  -36,  -36,  -36,  -36,  -36,  -36,
+      -36,  -36,  -36,  -36,  -36,  -36,  -36
     },
 
     {
-       11, -187, -187, -187, -187, -187, -187, -187, -187, -187,
-     -187, -187, -187,   58, -187, -187,   58,   58,   58,   58,
-
-       58,   58,   58,   58,   58,   58,   58,   58,   58,   58,
-       58,   58,   58,   58,   58,   58,   58, -187
+       11,  -37,  -37,   58,  -37,  -37,  -37,  -37,  -37,  -37,
+      -37,  -37,  -37,  -37,  -37,  -37,  -37
     },
 
     {
-       11, -188, -188, -188, -188, -188, -188, -188, -188, -188,
-     -188, -188, -188,   58, -188, -188,   58,   58,   58,   58,
-       58,   58,   58,   58,   58,   58,   58,   58,   58,   58,
-       58,   58,   58,   58,   58,  196,   58, -188
+       11,  -38,  -38,  -38,  -38,  -38,  -38,  -38,  -38,  -38,
+      -38,  -38,  -38,  -38,  -38,  -38,   59
     },
 
     {
-       11, -189, -189, -189, -189, -189, -189, -189, -189, -189,
-     -189, -189, -189,   58, -189, -189,   58,   58,   58,   58,
-       58,   58,  197,   58,   58,   58,   58,   58,   58,   58,
-       58,   58,   58,   58,   58,   58,   58, -189
+       11,  -39,   39,   40,  -39,  -39,   41,  -39,  -39,  -39,
+      -39,  -39,  -39,  -39,  -39,  -39,  -39
 
     },
 
     {
-       11, -190, -190, -190, -190, -190, -190, -190, -190, -190,
-     -190, -190, -190,   58, -190, -190,   58,   58,   58,   58,
-       58,   58,   58,   58,   58,   58,  198,   58,   58,   58,
-       58,   58,   58,   58,   58,   58,   58, -190
+       11,  -40,  -40,  -40,  -40,  -40,  -40,  -40,  -40,  -40,
+      -40,  -40,  -40,  -40,  -40,  -40,  -40
     },
 
     {
-       11, -191, -191, -191, -191, -191, -191, -191, -191, -191,
-     -191, -191, -191,   58, -191, -191,   58,   58,   58,   58,
-       58,   58,   58,   58,   58,   58,   58,   58,   58,   58,
-       58,   58,   58,  199,   58,   58,   58, -191
+       11,   42,   42,   43,   42,   42,   42,   42,   42,   42,
+       42,   42,   42,   42,   42,   42,   42
     },
 
     {
-       11, -192, -192, -192, -192, -192, -192, -192, -192, -192,
-     -192, -192, -192,   58, -192, -192,   58,   58,   58,   58,
-
-       58,  200,   58,   58,   58,   58,   58,   58,   58,   58,
-       58,   58,   58,   58,   58,   58,   58, -192
+       11,   42,   42,   43,   42,   42,   42,   42,   42,   42,
+       42,   42,   42,   42,   42,   42,   42
     },
 
     {
-       11, -193, -193, -193, -193, -193, -193, -193, -193, -193,
-     -193, -193, -193,   58, -193, -193,   58,   58,   58,   58,
-       58,  201,   58,   58,   58,   58,   58,   58,   58,   58,
-       58,   58,   58,   58,   58,   58,   58, -193
+       11,  -43,  -43,  -43,  -43,  -43,  -43,  -43,  -43,  -43,
+      -43,  -43,  -43,  -43,  -43,  -43,  -43
     },
 
     {
-       11, -194, -194, -194, -194, -194, -194, -194, -194, -194,
-     -194, -194, -194,   58, -194, -194,   58,   58,   58,   58,
-       58,   58,   58,   58,   58,   58,   58,   58,   58,   58,
-       58,   58,   58,   58,  202,   58,   58, -194
+       11,  -44,  -44,  -44,  -44,  -44,  -44,  -44,  -44,  -44,
+      -44,  -44,  -44,   44,  -44,  -44,  -44
 
     },
 
     {
-       11, -195, -195, -195, -195, -195, -195, -195, -195, -195,
-     -195, -195, -195,   58, -195, -195,   58,   58,   58,   58,
-       58,  203,   58,   58,   58,   58,   58,   58,   58,   58,
-       58,   58,   58,   58,   58,   58,   58, -195
+       11,   45,   45,  -45,   45,   45,   45,   45,   45,   45,
+       45,   45,   45,   45,   45,   45,   45
     },
 
     {
-       11, -196, -196, -196, -196, -196, -196, -196, -196, -196,
-     -196, -196, -196,   58, -196, -196,   58,   58,   58,   58,
-       58,   58,   58,   58,   58,   58,   58,   58,   58,   58,
-       58,   58,   58,   58,   58,   58,   58, -196
+       11,  -46,   46,   47,  -46,  -46,  -46,  -46,  -46,  -46,
+      -46,  -46,  -46,  -46,  -46,  -46,  -46
     },
 
     {
-       11, -197, -197, -197, -197, -197, -197, -197, -197, -197,
-     -197, -197, -197,   58, -197, -197,   58,   58,   58,   58,
-
-       58,   58,   58,   58,   58,  204,   58,   58,   58,   58,
-       58,   58,   58,   58,   58,   58,   58, -197
+       11,   48,  -47,  -47,   48,   48,   48,   48,   48,   48,
+       48,   48,   48,   48,   48,   48,   48
     },
 
     {
-       11, -198, -198, -198, -198, -198, -198, -198, -198, -198,
-     -198, -198, -198,   58, -198, -198,   58,   58,   58,   58,
-       58,   58,   58,   58,   58,   58,   58,   58,   58,   58,
-       58,   58,   58,   58,   58,   58,   58, -198
+       11,  -48,  -48,  -48,  -48,  -48,  -48,  -48,  -48,  -48,
+      -48,  -48,  -48,  -48,  -48,  -48,  -48
     },
 
     {
-       11, -199, -199, -199, -199, -199, -199, -199, -199, -199,
-     -199, -199, -199,   58, -199, -199,   58,   58,   58,   58,
-       58,   58,   58,   58,   58,   58,   58,   58,   58,   58,
-       58,   58,   58,   58,   58,   58,   58, -199
+       11,   49,   49,   50,   49,  -49,   49,   49,  -49,   49,
+       49,   49,   49,   49,   49,  -49,   49
 
     },
 
     {
-       11, -200, -200, -200, -200, -200, -200, -200, -200, -200,
-     -200, -200, -200,   58, -200, -200,   58,   58,   58,   58,
-       58,   58,   58,   58,   58,   58,   58,   58,   58,   58,
-       58,   58,   58,   58,   58,   58,   58, -200
+       11,  -50,  -50,  -50,  -50,  -50,  -50,  -50,  -50,  -50,
+      -50,  -50,  -50,  -50,  -50,  -50,  -50
     },
 
     {
-       11, -201, -201, -201, -201, -201, -201, -201, -201, -201,
-     -201, -201, -201,   58, -201, -201,   58,  205,   58,   58,
-       58,   58,   58,   58,   58,   58,   58,   58,   58,   58,
-       58,   58,   58,   58,   58,   58,   58, -201
+       11,  -51,  -51,   52,  -51,  -51,  -51,  -51,  -51,  -51,
+      -51,  -51,  -51,  -51,  -51,  -51,  -51
     },
 
     {
-       11, -202, -202, -202, -202, -202, -202, -202, -202, -202,
-     -202, -202, -202,   58, -202, -202,   58,  206,   58,   58,
-
-       58,   58,   58,   58,   58,   58,   58,   58,   58,   58,
-       58,   58,   58,   58,   58,   58,   58, -202
+       11,  -52,  -52,  -52,  -52,  -52,  -52,  -52,  -52,  -52,
+      -52,  -52,  -52,  -52,  -52,  -52,  -52
     },
 
     {
-       11, -203, -203, -203, -203, -203, -203, -203, -203, -203,
-     -203, -203, -203,   58, -203, -203,   58,   58,   58,   58,
-       58,   58,   58,   58,   58,   58,   58,   58,   58,   58,
-       58,   58,   58,   58,   58,   58,   58, -203
+       11,  -53,  -53,  -53,  -53,  -53,  -53,  -53,  -53,  -53,
+      -53,  -53,  -53,  -53,  -53,  -53,  -53
     },
 
     {
-       11, -204, -204, -204, -204, -204, -204, -204, -204, -204,
-     -204, -204, -204,   58, -204, -204,   58,   58,   58,   58,
-       58,   58,   58,  207,   58,   58,   58,   58,   58,   58,
-       58,   58,   58,   58,   58,   58,   58, -204
+       11,   54,   54,  -54,   54,   54,   54,   54,   54,   54,
+       54,   54,   54,   54,   54,   54,   54
 
     },
 
     {
-       11, -205, -205, -205, -205, -205, -205, -205, -205, -205,
-     -205, -205, -205,   58, -205, -205,   58,   58,   58,   58,
-       58,   58,   58,   58,   58,   58,   58,   58,  208,   58,
-       58,   58,   58,   58,   58,   58,   58, -205
+       11,  -55,  -55,  -55,  -55,  -55,  -55,  -55,  -55,  -55,
+      -55,  -55,  -55,  -55,  -55,  -55,  -55
     },
 
     {
-       11, -206, -206, -206, -206, -206, -206, -206, -206, -206,
-     -206, -206, -206,   58, -206, -206,   58,   58,   58,   58,
-       58,   58,   58,   58,   58,   58,   58,   58,   58,   58,
-       58,   58,   58,   58,  209,   58,   58, -206
+       11,  -56,  -56,  -56,  -56,  -56,  -56,  -56,  -56,  -56,
+      -56,   60,   57,   57,  -56,  -56,  -56
     },
 
     {
-       11, -207, -207, -207, -207, -207, -207, -207, -207, -207,
-     -207, -207, -207,   58, -207, -207,   58,   58,   58,   58,
-
-       58,   58,   58,   58,   58,   58,   58,   58,   58,   58,
-       58,   58,   58,   58,   58,   58,   58, -207
+       11,  -57,  -57,  -57,  -57,  -57,  -57,  -57,  -57,  -57,
+      -57,   57,   57,   57,  -57,  -57,  -57
     },
 
     {
-       11, -208, -208, -208, -208, -208, -208, -208, -208, -208,
-     -208, -208, -208,   58, -208, -208,   58,   58,   58,   58,
-       58,   58,   58,   58,   58,   58,   58,   58,   58,   58,
-       58,   58,   58,   58,   58,   58,   58, -208
+       11,  -58,  -58,  -58,  -58,  -58,  -58,  -58,  -58,  -58,
+      -58,  -58,  -58,  -58,  -58,  -58,  -58
     },
 
     {
-       11, -209, -209, -209, -209, -209, -209, -209, -209, -209,
-     -209, -209, -209,   58, -209, -209,   58,   58,   58,   58,
-       58,  210,   58,   58,   58,   58,   58,   58,   58,   58,
-       58,   58,   58,   58,   58,   58,   58, -209
+       11,  -59,  -59,  -59,  -59,  -59,  -59,  -59,  -59,  -59,
+      -59,  -59,  -59,  -59,  -59,  -59,  -59
 
     },
 
     {
-       11, -210, -210, -210, -210, -210, -210, -210, -210, -210,
-     -210, -210, -210,   58, -210, -210,   58,   58,   58,   58,
-       58,   58,   58,   58,   58,   58,   58,   58,   58,   58,
-       58,   58,   58,   58,   58,   58,   58, -210
+       11,  -60,  -60,  -60,  -60,  -60,  -60,  -60,  -60,  -60,
+      -60,   57,   57,   57,  -60,  -60,  -60
     },
 
     } ;
@@ -1918,8 +674,8 @@ static void yy_fatal_error (yyconst char msg[]  );
        *yy_cp = '\0'; \
        (yy_c_buf_p) = yy_cp;
 
-#define YY_NUM_RULES 64
-#define YY_END_OF_BUFFER 65
+#define YY_NUM_RULES 33
+#define YY_END_OF_BUFFER 34
 /* This struct is not used in this scanner,
    but its presence is necessary. */
 struct yy_trans_info
@@ -1927,31 +683,14 @@ struct yy_trans_info
        flex_int32_t yy_verify;
        flex_int32_t yy_nxt;
        };
-static yyconst flex_int16_t yy_accept[211] =
+static yyconst flex_int16_t yy_accept[61] =
     {   0,
         0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
-       65,    5,    4,    3,    2,   36,   37,   35,   35,   35,
-       35,   35,   35,   35,   35,   35,   35,   35,   35,   35,
-       63,   60,   62,   55,   59,   58,   57,   53,   48,   42,
-       47,   51,   53,   40,   41,   50,   50,   43,   53,   50,
-       50,   53,    4,    3,    2,    2,    1,   35,   35,   35,
-       35,   35,   35,   35,   16,   35,   35,   35,   35,   35,
-       35,   35,   35,   35,   35,   35,   63,   60,   62,   61,
-       55,   54,   57,   56,   44,   51,   38,   50,   50,   52,
-       45,   46,   39,   35,   35,   35,   35,   35,   35,   35,
-
-       35,   35,   30,   29,   35,   35,   35,   35,   35,   35,
-       35,   35,   35,   35,   49,   25,   35,   35,   35,   35,
-       35,   35,   35,   35,   35,   35,   15,   35,    7,   35,
-       35,   35,   35,   35,   35,   35,   35,   35,   35,   35,
-       35,   35,   35,   35,   35,   35,   35,   17,   35,   35,
-       35,   35,   35,   34,   35,   35,   35,   35,   35,   35,
-       10,   35,   13,   35,   35,   35,   35,   33,   35,   35,
-       35,   35,   35,   22,   35,   32,    9,   31,   35,   26,
-       12,   35,   35,   21,   18,   35,    8,   35,   35,   35,
-       35,   35,   27,   35,   35,    6,   35,   20,   19,   23,
-
-       35,   35,   11,   35,   35,   35,   14,   28,   35,   24
+       34,    5,    4,    2,    3,    7,    8,    6,   32,   29,
+       31,   24,   28,   27,   26,   22,   17,   13,   16,   20,
+       22,   11,   12,   19,   19,   14,   22,   22,    4,    2,
+        3,    3,    1,    6,   32,   29,   31,   30,   24,   23,
+       26,   25,   15,   20,    9,   19,   19,   21,   10,   18
     } ;
 
 static yyconst flex_int32_t yy_ec[256] =
@@ -1965,11 +704,11 @@ static yyconst flex_int32_t yy_ec[256] =
        14,    1,    1,    1,   13,   13,   13,   13,   13,   13,
        13,   13,   13,   13,   13,   13,   13,   13,   13,   13,
        13,   13,   13,   13,   13,   13,   13,   13,   13,   13,
-        1,   15,    1,    1,   16,    1,   17,   18,   19,   20,
+        1,   15,    1,    1,   13,    1,   13,   13,   13,   13,
 
-       21,   22,   23,   24,   25,   13,   13,   26,   27,   28,
-       29,   30,   31,   32,   33,   34,   35,   13,   13,   36,
-       13,   13,    1,   37,    1,    1,    1,    1,    1,    1,
+       13,   13,   13,   13,   13,   13,   13,   13,   13,   13,
+       13,   13,   13,   13,   13,   13,   13,   13,   13,   13,
+       13,   13,    1,   16,    1,    1,    1,    1,    1,    1,
         1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
         1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
         1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
@@ -2014,8 +753,12 @@ char *zconftext;
 
 #define START_STRSIZE  16
 
-char *text;
-static char *text_ptr;
+static struct {
+       struct file *file;
+       int lineno;
+} current_pos;
+
+static char *text;
 static int text_size, text_asize;
 
 struct buffer {
@@ -2028,29 +771,28 @@ struct buffer *current_buf;
 static int last_ts, first_ts;
 
 static void zconf_endhelp(void);
-static struct buffer *zconf_endfile(void);
+static void zconf_endfile(void);
 
 void new_string(void)
 {
        text = malloc(START_STRSIZE);
        text_asize = START_STRSIZE;
-       text_ptr = text;
        text_size = 0;
-       *text_ptr = 0;
+       *text = 0;
 }
 
 void append_string(const char *str, int size)
 {
        int new_size = text_size + size + 1;
        if (new_size > text_asize) {
+               new_size += START_STRSIZE - 1;
+               new_size &= -START_STRSIZE;
                text = realloc(text, new_size);
                text_asize = new_size;
-               text_ptr = text + text_size;
        }
-       memcpy(text_ptr, str, size);
-       text_ptr += size;
+       memcpy(text + text_size, str, size);
        text_size += size;
-       *text_ptr = 0;
+       text[text_size] = 0;
 }
 
 void alloc_string(const char *str, int size)
@@ -2066,11 +808,13 @@ void alloc_string(const char *str, int size)
 #define STRING 3
 #define PARAM 4
 
+#ifndef YY_NO_UNISTD_H
 /* Special case for "unistd.h", since it is non-ANSI. We include it way
  * down here because we want the user's section 1 to have been scanned first.
  * The user has a chance to override it with an option.
  */
 #include <unistd.h>
+#endif
 
 #ifndef YY_EXTRA_TYPE
 #define YY_EXTRA_TYPE void *
@@ -2254,17 +998,17 @@ do_action:       /* This label is used only to access EOF actions. */
        { /* beginning of action switch */
 case 1:
 /* rule 1 can match eol */
-YY_RULE_SETUP
-current_file->lineno++;
-       YY_BREAK
 case 2:
+/* rule 2 can match eol */
 YY_RULE_SETUP
-
+{
+       current_file->lineno++;
+       return T_EOL;
+}
        YY_BREAK
 case 3:
-/* rule 3 can match eol */
 YY_RULE_SETUP
-current_file->lineno++; return T_EOL;
+
        YY_BREAK
 case 4:
 YY_RULE_SETUP
@@ -2282,175 +1026,63 @@ YY_RULE_SETUP
 
 case 6:
 YY_RULE_SETUP
-BEGIN(PARAM); return T_MAINMENU;
-       YY_BREAK
-case 7:
-YY_RULE_SETUP
-BEGIN(PARAM); return T_MENU;
-       YY_BREAK
-case 8:
-YY_RULE_SETUP
-BEGIN(PARAM); return T_ENDMENU;
-       YY_BREAK
-case 9:
-YY_RULE_SETUP
-BEGIN(PARAM); return T_SOURCE;
-       YY_BREAK
-case 10:
-YY_RULE_SETUP
-BEGIN(PARAM); return T_CHOICE;
-       YY_BREAK
-case 11:
-YY_RULE_SETUP
-BEGIN(PARAM); return T_ENDCHOICE;
-       YY_BREAK
-case 12:
-YY_RULE_SETUP
-BEGIN(PARAM); return T_COMMENT;
-       YY_BREAK
-case 13:
-YY_RULE_SETUP
-BEGIN(PARAM); return T_CONFIG;
-       YY_BREAK
-case 14:
-YY_RULE_SETUP
-BEGIN(PARAM); return T_MENUCONFIG;
-       YY_BREAK
-case 15:
-YY_RULE_SETUP
-BEGIN(PARAM); return T_HELP;
-       YY_BREAK
-case 16:
-YY_RULE_SETUP
-BEGIN(PARAM); return T_IF;
-       YY_BREAK
-case 17:
-YY_RULE_SETUP
-BEGIN(PARAM); return T_ENDIF;
-       YY_BREAK
-case 18:
-YY_RULE_SETUP
-BEGIN(PARAM); return T_DEPENDS;
-       YY_BREAK
-case 19:
-YY_RULE_SETUP
-BEGIN(PARAM); return T_REQUIRES;
-       YY_BREAK
-case 20:
-YY_RULE_SETUP
-BEGIN(PARAM); return T_OPTIONAL;
-       YY_BREAK
-case 21:
-YY_RULE_SETUP
-BEGIN(PARAM); return T_DEFAULT;
-       YY_BREAK
-case 22:
-YY_RULE_SETUP
-BEGIN(PARAM); return T_PROMPT;
-       YY_BREAK
-case 23:
-YY_RULE_SETUP
-BEGIN(PARAM); return T_TRISTATE;
-       YY_BREAK
-case 24:
-YY_RULE_SETUP
-BEGIN(PARAM); return T_DEF_TRISTATE;
-       YY_BREAK
-case 25:
-YY_RULE_SETUP
-BEGIN(PARAM); return T_BOOLEAN;
-       YY_BREAK
-case 26:
-YY_RULE_SETUP
-BEGIN(PARAM); return T_BOOLEAN;
-       YY_BREAK
-case 27:
-YY_RULE_SETUP
-BEGIN(PARAM); return T_DEF_BOOLEAN;
-       YY_BREAK
-case 28:
-YY_RULE_SETUP
-BEGIN(PARAM); return T_DEF_BOOLEAN;
-       YY_BREAK
-case 29:
-YY_RULE_SETUP
-BEGIN(PARAM); return T_INT;
-       YY_BREAK
-case 30:
-YY_RULE_SETUP
-BEGIN(PARAM); return T_HEX;
-       YY_BREAK
-case 31:
-YY_RULE_SETUP
-BEGIN(PARAM); return T_STRING;
-       YY_BREAK
-case 32:
-YY_RULE_SETUP
-BEGIN(PARAM); return T_SELECT;
-       YY_BREAK
-case 33:
-YY_RULE_SETUP
-BEGIN(PARAM); return T_SELECT;
-       YY_BREAK
-case 34:
-YY_RULE_SETUP
-BEGIN(PARAM); return T_RANGE;
-       YY_BREAK
-case 35:
-YY_RULE_SETUP
 {
+               struct kconf_id *id = kconf_id_lookup(zconftext, zconfleng);
+               BEGIN(PARAM);
+               current_pos.file = current_file;
+               current_pos.lineno = current_file->lineno;
+               if (id && id->flags & TF_COMMAND) {
+                       zconflval.id = id;
+                       return id->token;
+               }
                alloc_string(zconftext, zconfleng);
                zconflval.string = text;
                return T_WORD;
        }
        YY_BREAK
-case 36:
+case 7:
 YY_RULE_SETUP
 
        YY_BREAK
-case 37:
-/* rule 37 can match eol */
+case 8:
+/* rule 8 can match eol */
 YY_RULE_SETUP
-current_file->lineno++; BEGIN(INITIAL);
+{
+               BEGIN(INITIAL);
+               current_file->lineno++;
+               return T_EOL;
+       }
        YY_BREAK
 
-case 38:
+case 9:
 YY_RULE_SETUP
 return T_AND;
        YY_BREAK
-case 39:
+case 10:
 YY_RULE_SETUP
 return T_OR;
        YY_BREAK
-case 40:
+case 11:
 YY_RULE_SETUP
 return T_OPEN_PAREN;
        YY_BREAK
-case 41:
+case 12:
 YY_RULE_SETUP
 return T_CLOSE_PAREN;
        YY_BREAK
-case 42:
+case 13:
 YY_RULE_SETUP
 return T_NOT;
        YY_BREAK
-case 43:
+case 14:
 YY_RULE_SETUP
 return T_EQUAL;
        YY_BREAK
-case 44:
+case 15:
 YY_RULE_SETUP
 return T_UNEQUAL;
        YY_BREAK
-case 45:
-YY_RULE_SETUP
-return T_IF;
-       YY_BREAK
-case 46:
-YY_RULE_SETUP
-return T_ON;
-       YY_BREAK
-case 47:
+case 16:
 YY_RULE_SETUP
 {
                str = zconftext[0];
@@ -2458,33 +1090,38 @@ YY_RULE_SETUP
                BEGIN(STRING);
        }
        YY_BREAK
-case 48:
-/* rule 48 can match eol */
+case 17:
+/* rule 17 can match eol */
 YY_RULE_SETUP
 BEGIN(INITIAL); current_file->lineno++; return T_EOL;
        YY_BREAK
-case 49:
+case 18:
 YY_RULE_SETUP
 /* ignore */
        YY_BREAK
-case 50:
+case 19:
 YY_RULE_SETUP
 {
+               struct kconf_id *id = kconf_id_lookup(zconftext, zconfleng);
+               if (id && id->flags & TF_PARAM) {
+                       zconflval.id = id;
+                       return id->token;
+               }
                alloc_string(zconftext, zconfleng);
                zconflval.string = text;
                return T_WORD;
        }
        YY_BREAK
-case 51:
+case 20:
 YY_RULE_SETUP
 /* comment */
        YY_BREAK
-case 52:
-/* rule 52 can match eol */
+case 21:
+/* rule 21 can match eol */
 YY_RULE_SETUP
 current_file->lineno++;
        YY_BREAK
-case 53:
+case 22:
 YY_RULE_SETUP
 
        YY_BREAK
@@ -2494,8 +1131,8 @@ case YY_STATE_EOF(PARAM):
        }
        YY_BREAK
 
-case 54:
-/* rule 54 can match eol */
+case 23:
+/* rule 23 can match eol */
 *yy_cp = (yy_hold_char); /* undo effects of setting up zconftext */
 (yy_c_buf_p) = yy_cp -= 1;
 YY_DO_BEFORE_ACTION; /* set up zconftext again */
@@ -2506,14 +1143,14 @@ YY_RULE_SETUP
                return T_WORD_QUOTE;
        }
        YY_BREAK
-case 55:
+case 24:
 YY_RULE_SETUP
 {
                append_string(zconftext, zconfleng);
        }
        YY_BREAK
-case 56:
-/* rule 56 can match eol */
+case 25:
+/* rule 25 can match eol */
 *yy_cp = (yy_hold_char); /* undo effects of setting up zconftext */
 (yy_c_buf_p) = yy_cp -= 1;
 YY_DO_BEFORE_ACTION; /* set up zconftext again */
@@ -2524,13 +1161,13 @@ YY_RULE_SETUP
                return T_WORD_QUOTE;
        }
        YY_BREAK
-case 57:
+case 26:
 YY_RULE_SETUP
 {
                append_string(zconftext + 1, zconfleng - 1);
        }
        YY_BREAK
-case 58:
+case 27:
 YY_RULE_SETUP
 {
                if (str == zconftext[0]) {
@@ -2541,8 +1178,8 @@ YY_RULE_SETUP
                        append_string(zconftext, 1);
        }
        YY_BREAK
-case 59:
-/* rule 59 can match eol */
+case 28:
+/* rule 28 can match eol */
 YY_RULE_SETUP
 {
                printf("%s:%d:warning: multi-line strings not supported\n", zconf_curname(), zconf_lineno());
@@ -2557,7 +1194,7 @@ case YY_STATE_EOF(STRING):
        }
        YY_BREAK
 
-case 60:
+case 29:
 YY_RULE_SETUP
 {
                ts = 0;
@@ -2582,8 +1219,8 @@ YY_RULE_SETUP
                }
        }
        YY_BREAK
-case 61:
-/* rule 61 can match eol */
+case 30:
+/* rule 30 can match eol */
 *yy_cp = (yy_hold_char); /* undo effects of setting up zconftext */
 (yy_c_buf_p) = yy_cp -= 1;
 YY_DO_BEFORE_ACTION; /* set up zconftext again */
@@ -2594,15 +1231,15 @@ YY_RULE_SETUP
                return T_HELPTEXT;
        }
        YY_BREAK
-case 62:
-/* rule 62 can match eol */
+case 31:
+/* rule 31 can match eol */
 YY_RULE_SETUP
 {
                current_file->lineno++;
                append_string("\n", 1);
        }
        YY_BREAK
-case 63:
+case 32:
 YY_RULE_SETUP
 {
                append_string(zconftext, zconfleng);
@@ -2620,15 +1257,15 @@ case YY_STATE_EOF(HELP):
 case YY_STATE_EOF(INITIAL):
 case YY_STATE_EOF(COMMAND):
 {
-       if (current_buf) {
+       if (current_file) {
                zconf_endfile();
-               return T_EOF;
+               return T_EOL;
        }
        fclose(zconfin);
        yyterminate();
 }
        YY_BREAK
-case 64:
+case 33:
 YY_RULE_SETUP
 YY_FATAL_ERROR( "flex scanner jammed" );
        YY_BREAK
@@ -3332,16 +1969,16 @@ YY_BUFFER_STATE zconf_scan_buffer  (char * base, yy_size_t  size )
 
 /** Setup the input buffer state to scan a string. The next call to zconflex() will
  * scan from a @e copy of @a str.
- * @param str a NUL-terminated string to scan
+ * @param yy_str a NUL-terminated string to scan
  * 
  * @return the newly allocated buffer state object.
  * @note If you want to scan bytes that may contain NUL values, then use
  *       zconf_scan_bytes() instead.
  */
-YY_BUFFER_STATE zconf_scan_string (yyconst char * str )
+YY_BUFFER_STATE zconf_scan_string (yyconst char * yy_str )
 {
     
-       return zconf_scan_bytes(str,strlen(str) );
+       return zconf_scan_bytes(yy_str,strlen(yy_str) );
 }
 
 /** Setup the input buffer state to scan the given bytes. The next call to zconflex() will
@@ -3650,7 +2287,7 @@ void zconf_nextfile(const char *name)
        current_file = file;
 }
 
-static struct buffer *zconf_endfile(void)
+static void zconf_endfile(void)
 {
        struct buffer *parent;
 
@@ -3666,23 +2303,15 @@ static struct buffer *zconf_endfile(void)
        }
        free(current_buf);
        current_buf = parent;
-
-       return parent;
 }
 
 int zconf_lineno(void)
 {
-       if (current_buf)
-               return current_file->lineno - 1;
-       else
-               return 0;
+       return current_pos.lineno;
 }
 
 char *zconf_curname(void)
 {
-       if (current_buf)
-               return current_file->name;
-       else
-               return "<none>";
+       return current_pos.file ? current_pos.file->name : "<none>";
 }
 
index 5fba1feff2a813cdee2b8126b981ce898f854a0e..527f60c99c50a4ac4b597aff3eeae5de1136d12e 100644 (file)
@@ -37,6 +37,17 @@ extern "C" {
 #define _(text) gettext(text)
 #define N_(text) (text)
 
+
+#define TF_COMMAND     0x0001
+#define TF_PARAM       0x0002
+
+struct kconf_id {
+       int name;
+       int token;
+       unsigned int flags;
+       enum symbol_type stype;
+};
+
 int zconfparse(void);
 void zconfdump(FILE *out);
 
@@ -50,7 +61,6 @@ char *zconf_curname(void);
 
 /* confdata.c */
 extern const char conf_def_filename[];
-extern char conf_filename[];
 
 char *conf_get_default_confname(void);
 
@@ -59,7 +69,7 @@ void kconfig_load(void);
 
 /* menu.c */
 void menu_init(void);
-void menu_add_menu(void);
+struct menu *menu_add_menu(void);
 void menu_end_menu(void);
 void menu_add_entry(struct symbol *sym);
 void menu_end_entry(void);
index 6dc6d0c48e7ac8e617e1010ac97e572db9328423..b6a389c5fcbde1ca9f4e25b05a1813b056f7c632 100644 (file)
@@ -2,6 +2,7 @@
 /* confdata.c */
 P(conf_parse,void,(const char *name));
 P(conf_read,int,(const char *name));
+P(conf_read_simple,int,(const char *name));
 P(conf_write,int,(const char *name));
 
 /* menu.c */
index 5cfa6c405cf074f369b8ea1766ea549287560279..0fce20cb7f3c38a931d9f78c14144d2272b9e809 100644 (file)
@@ -61,10 +61,11 @@ void menu_end_entry(void)
 {
 }
 
-void menu_add_menu(void)
+struct menu *menu_add_menu(void)
 {
-       current_menu = current_entry;
+       menu_end_entry();
        last_entry_ptr = &current_entry->list;
+       return current_menu = current_entry;
 }
 
 void menu_end_menu(void)
@@ -151,6 +152,12 @@ void menu_add_symbol(enum prop_type type, struct symbol *sym, struct expr *dep)
        menu_add_prop(type, NULL, expr_alloc_symbol(sym), dep);
 }
 
+static int menu_range_valid_sym(struct symbol *sym, struct symbol *sym2)
+{
+       return sym2->type == S_INT || sym2->type == S_HEX ||
+              (sym2->type == S_UNKNOWN && sym_string_valid(sym, sym2->name));
+}
+
 void sym_check_prop(struct symbol *sym)
 {
        struct property *prop;
@@ -185,8 +192,8 @@ void sym_check_prop(struct symbol *sym)
                        if (sym->type != S_INT && sym->type != S_HEX)
                                prop_warn(prop, "range is only allowed "
                                                "for int or hex symbols");
-                       if (!sym_string_valid(sym, prop->expr->left.sym->name) ||
-                           !sym_string_valid(sym, prop->expr->right.sym->name))
+                       if (!menu_range_valid_sym(sym, prop->expr->left.sym) ||
+                           !menu_range_valid_sym(sym, prop->expr->right.sym))
                                prop_warn(prop, "range is invalid");
                        break;
                default:
index affa52f5c651365d77b0866df06d81dd89a15619..69c2549c0baa772fc74a46076d75add586f703d6 100644 (file)
@@ -141,6 +141,55 @@ struct property *sym_get_range_prop(struct symbol *sym)
        return NULL;
 }
 
+static int sym_get_range_val(struct symbol *sym, int base)
+{
+       sym_calc_value(sym);
+       switch (sym->type) {
+       case S_INT:
+               base = 10;
+               break;
+       case S_HEX:
+               base = 16;
+               break;
+       default:
+               break;
+       }
+       return strtol(sym->curr.val, NULL, base);
+}
+
+static void sym_validate_range(struct symbol *sym)
+{
+       struct property *prop;
+       int base, val, val2;
+       char str[64];
+
+       switch (sym->type) {
+       case S_INT:
+               base = 10;
+               break;
+       case S_HEX:
+               base = 16;
+               break;
+       default:
+               return;
+       }
+       prop = sym_get_range_prop(sym);
+       if (!prop)
+               return;
+       val = strtol(sym->curr.val, NULL, base);
+       val2 = sym_get_range_val(prop->expr->left.sym, base);
+       if (val >= val2) {
+               val2 = sym_get_range_val(prop->expr->right.sym, base);
+               if (val <= val2)
+                       return;
+       }
+       if (sym->type == S_INT)
+               sprintf(str, "%d", val2);
+       else
+               sprintf(str, "0x%x", val2);
+       sym->curr.val = strdup(str);
+}
+
 static void sym_calc_visibility(struct symbol *sym)
 {
        struct property *prop;
@@ -301,6 +350,7 @@ void sym_calc_value(struct symbol *sym)
        sym->curr = newval;
        if (sym_is_choice(sym) && newval.tri == yes)
                sym->curr.val = sym_calc_choice(sym);
+       sym_validate_range(sym);
 
        if (memcmp(&oldval, &sym->curr, sizeof(oldval)))
                sym_set_changed(sym);
@@ -380,11 +430,22 @@ bool sym_set_tristate_value(struct symbol *sym, tristate val)
                sym->flags &= ~SYMBOL_NEW;
                sym_set_changed(sym);
        }
+       /*
+        * setting a choice value also resets the new flag of the choice
+        * symbol and all other choice values.
+        */
        if (sym_is_choice_value(sym) && val == yes) {
                struct symbol *cs = prop_get_symbol(sym_get_choice_prop(sym));
+               struct property *prop;
+               struct expr *e;
 
                cs->user.val = sym;
                cs->flags &= ~SYMBOL_NEW;
+               prop = sym_get_choice_prop(cs);
+               for (e = prop->expr; e; e = e->left.expr) {
+                       if (e->right.sym->visible != no)
+                               e->right.sym->flags &= ~SYMBOL_NEW;
+               }
        }
 
        sym->user.tri = val;
@@ -478,8 +539,8 @@ bool sym_string_within_range(struct symbol *sym, const char *str)
                if (!prop)
                        return true;
                val = strtol(str, NULL, 10);
-               return val >= strtol(prop->expr->left.sym->name, NULL, 10) &&
-                      val <= strtol(prop->expr->right.sym->name, NULL, 10);
+               return val >= sym_get_range_val(prop->expr->left.sym, 10) &&
+                      val <= sym_get_range_val(prop->expr->right.sym, 10);
        case S_HEX:
                if (!sym_string_valid(sym, str))
                        return false;
@@ -487,8 +548,8 @@ bool sym_string_within_range(struct symbol *sym, const char *str)
                if (!prop)
                        return true;
                val = strtol(str, NULL, 16);
-               return val >= strtol(prop->expr->left.sym->name, NULL, 16) &&
-                      val <= strtol(prop->expr->right.sym->name, NULL, 16);
+               return val >= sym_get_range_val(prop->expr->left.sym, 16) &&
+                      val <= sym_get_range_val(prop->expr->right.sym, 16);
        case S_BOOLEAN:
        case S_TRISTATE:
                switch (str[0]) {
@@ -731,12 +792,12 @@ struct symbol *sym_check_deps(struct symbol *sym)
        struct symbol *sym2;
        struct property *prop;
 
-       if (sym->flags & SYMBOL_CHECK_DONE)
-               return NULL;
        if (sym->flags & SYMBOL_CHECK) {
                printf("Warning! Found recursive dependency: %s", sym->name);
                return sym;
        }
+       if (sym->flags & SYMBOL_CHECKED)
+               return NULL;
 
        sym->flags |= (SYMBOL_CHECK | SYMBOL_CHECKED);
        sym2 = sym_check_expr_deps(sym->rev_dep.expr);
@@ -756,8 +817,13 @@ struct symbol *sym_check_deps(struct symbol *sym)
                        goto out;
        }
 out:
-       if (sym2)
+       if (sym2) {
                printf(" %s", sym->name);
+               if (sym2 == sym) {
+                       printf("\n");
+                       sym2 = NULL;
+               }
+       }
        sym->flags &= ~SYMBOL_CHECK;
        return sym2;
 }
diff --git a/scripts/kconfig/zconf.gperf b/scripts/kconfig/zconf.gperf
new file mode 100644 (file)
index 0000000..b032206
--- /dev/null
@@ -0,0 +1,43 @@
+%language=ANSI-C
+%define hash-function-name kconf_id_hash
+%define lookup-function-name kconf_id_lookup
+%define string-pool-name kconf_id_strings
+%compare-strncmp
+%enum
+%pic
+%struct-type
+
+struct kconf_id;
+
+%%
+mainmenu,      T_MAINMENU,     TF_COMMAND
+menu,          T_MENU,         TF_COMMAND
+endmenu,       T_ENDMENU,      TF_COMMAND
+source,                T_SOURCE,       TF_COMMAND
+choice,                T_CHOICE,       TF_COMMAND
+endchoice,     T_ENDCHOICE,    TF_COMMAND
+comment,       T_COMMENT,      TF_COMMAND
+config,                T_CONFIG,       TF_COMMAND
+menuconfig,    T_MENUCONFIG,   TF_COMMAND
+help,          T_HELP,         TF_COMMAND
+if,            T_IF,           TF_COMMAND|TF_PARAM
+endif,         T_ENDIF,        TF_COMMAND
+depends,       T_DEPENDS,      TF_COMMAND
+requires,      T_REQUIRES,     TF_COMMAND
+optional,      T_OPTIONAL,     TF_COMMAND
+default,       T_DEFAULT,      TF_COMMAND, S_UNKNOWN
+prompt,                T_PROMPT,       TF_COMMAND
+tristate,      T_TYPE,         TF_COMMAND, S_TRISTATE
+def_tristate,  T_DEFAULT,      TF_COMMAND, S_TRISTATE
+bool,          T_TYPE,         TF_COMMAND, S_BOOLEAN
+boolean,       T_TYPE,         TF_COMMAND, S_BOOLEAN
+def_bool,      T_DEFAULT,      TF_COMMAND, S_BOOLEAN
+def_boolean,   T_DEFAULT,      TF_COMMAND, S_BOOLEAN
+int,           T_TYPE,         TF_COMMAND, S_INT
+hex,           T_TYPE,         TF_COMMAND, S_HEX
+string,                T_TYPE,         TF_COMMAND, S_STRING
+select,                T_SELECT,       TF_COMMAND
+enable,                T_SELECT,       TF_COMMAND
+range,         T_RANGE,        TF_COMMAND
+on,            T_ON,           TF_PARAM
+%%
diff --git a/scripts/kconfig/zconf.hash.c_shipped b/scripts/kconfig/zconf.hash.c_shipped
new file mode 100644 (file)
index 0000000..345f0fc
--- /dev/null
@@ -0,0 +1,231 @@
+/* ANSI-C code produced by gperf version 3.0.1 */
+/* Command-line: gperf  */
+/* Computed positions: -k'1,3' */
+
+#if !((' ' == 32) && ('!' == 33) && ('"' == 34) && ('#' == 35) \
+      && ('%' == 37) && ('&' == 38) && ('\'' == 39) && ('(' == 40) \
+      && (')' == 41) && ('*' == 42) && ('+' == 43) && (',' == 44) \
+      && ('-' == 45) && ('.' == 46) && ('/' == 47) && ('0' == 48) \
+      && ('1' == 49) && ('2' == 50) && ('3' == 51) && ('4' == 52) \
+      && ('5' == 53) && ('6' == 54) && ('7' == 55) && ('8' == 56) \
+      && ('9' == 57) && (':' == 58) && (';' == 59) && ('<' == 60) \
+      && ('=' == 61) && ('>' == 62) && ('?' == 63) && ('A' == 65) \
+      && ('B' == 66) && ('C' == 67) && ('D' == 68) && ('E' == 69) \
+      && ('F' == 70) && ('G' == 71) && ('H' == 72) && ('I' == 73) \
+      && ('J' == 74) && ('K' == 75) && ('L' == 76) && ('M' == 77) \
+      && ('N' == 78) && ('O' == 79) && ('P' == 80) && ('Q' == 81) \
+      && ('R' == 82) && ('S' == 83) && ('T' == 84) && ('U' == 85) \
+      && ('V' == 86) && ('W' == 87) && ('X' == 88) && ('Y' == 89) \
+      && ('Z' == 90) && ('[' == 91) && ('\\' == 92) && (']' == 93) \
+      && ('^' == 94) && ('_' == 95) && ('a' == 97) && ('b' == 98) \
+      && ('c' == 99) && ('d' == 100) && ('e' == 101) && ('f' == 102) \
+      && ('g' == 103) && ('h' == 104) && ('i' == 105) && ('j' == 106) \
+      && ('k' == 107) && ('l' == 108) && ('m' == 109) && ('n' == 110) \
+      && ('o' == 111) && ('p' == 112) && ('q' == 113) && ('r' == 114) \
+      && ('s' == 115) && ('t' == 116) && ('u' == 117) && ('v' == 118) \
+      && ('w' == 119) && ('x' == 120) && ('y' == 121) && ('z' == 122) \
+      && ('{' == 123) && ('|' == 124) && ('}' == 125) && ('~' == 126))
+/* The character set is not based on ISO-646.  */
+#error "gperf generated tables don't work with this execution character set. Please report a bug to <bug-gnu-gperf@gnu.org>."
+#endif
+
+struct kconf_id;
+/* maximum key range = 45, duplicates = 0 */
+
+#ifdef __GNUC__
+__inline
+#else
+#ifdef __cplusplus
+inline
+#endif
+#endif
+static unsigned int
+kconf_id_hash (register const char *str, register unsigned int len)
+{
+  static unsigned char asso_values[] =
+    {
+      47, 47, 47, 47, 47, 47, 47, 47, 47, 47,
+      47, 47, 47, 47, 47, 47, 47, 47, 47, 47,
+      47, 47, 47, 47, 47, 47, 47, 47, 47, 47,
+      47, 47, 47, 47, 47, 47, 47, 47, 47, 47,
+      47, 47, 47, 47, 47, 47, 47, 47, 47, 47,
+      47, 47, 47, 47, 47, 47, 47, 47, 47, 47,
+      47, 47, 47, 47, 47, 47, 47, 47, 47, 47,
+      47, 47, 47, 47, 47, 47, 47, 47, 47, 47,
+      47, 47, 47, 47, 47, 47, 47, 47, 47, 47,
+      47, 47, 47, 47, 47, 47, 47, 25, 10, 15,
+       0,  0,  5, 47,  0,  0, 47, 47,  0, 10,
+       0, 20, 20, 20,  5,  0,  0, 20, 47, 47,
+      20, 47, 47, 47, 47, 47, 47, 47, 47, 47,
+      47, 47, 47, 47, 47, 47, 47, 47, 47, 47,
+      47, 47, 47, 47, 47, 47, 47, 47, 47, 47,
+      47, 47, 47, 47, 47, 47, 47, 47, 47, 47,
+      47, 47, 47, 47, 47, 47, 47, 47, 47, 47,
+      47, 47, 47, 47, 47, 47, 47, 47, 47, 47,
+      47, 47, 47, 47, 47, 47, 47, 47, 47, 47,
+      47, 47, 47, 47, 47, 47, 47, 47, 47, 47,
+      47, 47, 47, 47, 47, 47, 47, 47, 47, 47,
+      47, 47, 47, 47, 47, 47, 47, 47, 47, 47,
+      47, 47, 47, 47, 47, 47, 47, 47, 47, 47,
+      47, 47, 47, 47, 47, 47, 47, 47, 47, 47,
+      47, 47, 47, 47, 47, 47, 47, 47, 47, 47,
+      47, 47, 47, 47, 47, 47
+    };
+  register int hval = len;
+
+  switch (hval)
+    {
+      default:
+        hval += asso_values[(unsigned char)str[2]];
+      /*FALLTHROUGH*/
+      case 2:
+      case 1:
+        hval += asso_values[(unsigned char)str[0]];
+        break;
+    }
+  return hval;
+}
+
+struct kconf_id_strings_t
+  {
+    char kconf_id_strings_str2[sizeof("if")];
+    char kconf_id_strings_str3[sizeof("int")];
+    char kconf_id_strings_str4[sizeof("help")];
+    char kconf_id_strings_str5[sizeof("endif")];
+    char kconf_id_strings_str6[sizeof("select")];
+    char kconf_id_strings_str7[sizeof("endmenu")];
+    char kconf_id_strings_str8[sizeof("tristate")];
+    char kconf_id_strings_str9[sizeof("endchoice")];
+    char kconf_id_strings_str10[sizeof("range")];
+    char kconf_id_strings_str11[sizeof("string")];
+    char kconf_id_strings_str12[sizeof("default")];
+    char kconf_id_strings_str13[sizeof("def_bool")];
+    char kconf_id_strings_str14[sizeof("menu")];
+    char kconf_id_strings_str16[sizeof("def_boolean")];
+    char kconf_id_strings_str17[sizeof("def_tristate")];
+    char kconf_id_strings_str18[sizeof("mainmenu")];
+    char kconf_id_strings_str20[sizeof("menuconfig")];
+    char kconf_id_strings_str21[sizeof("config")];
+    char kconf_id_strings_str22[sizeof("on")];
+    char kconf_id_strings_str23[sizeof("hex")];
+    char kconf_id_strings_str26[sizeof("source")];
+    char kconf_id_strings_str27[sizeof("depends")];
+    char kconf_id_strings_str28[sizeof("optional")];
+    char kconf_id_strings_str31[sizeof("enable")];
+    char kconf_id_strings_str32[sizeof("comment")];
+    char kconf_id_strings_str33[sizeof("requires")];
+    char kconf_id_strings_str34[sizeof("bool")];
+    char kconf_id_strings_str37[sizeof("boolean")];
+    char kconf_id_strings_str41[sizeof("choice")];
+    char kconf_id_strings_str46[sizeof("prompt")];
+  };
+static struct kconf_id_strings_t kconf_id_strings_contents =
+  {
+    "if",
+    "int",
+    "help",
+    "endif",
+    "select",
+    "endmenu",
+    "tristate",
+    "endchoice",
+    "range",
+    "string",
+    "default",
+    "def_bool",
+    "menu",
+    "def_boolean",
+    "def_tristate",
+    "mainmenu",
+    "menuconfig",
+    "config",
+    "on",
+    "hex",
+    "source",
+    "depends",
+    "optional",
+    "enable",
+    "comment",
+    "requires",
+    "bool",
+    "boolean",
+    "choice",
+    "prompt"
+  };
+#define kconf_id_strings ((const char *) &kconf_id_strings_contents)
+#ifdef __GNUC__
+__inline
+#endif
+struct kconf_id *
+kconf_id_lookup (register const char *str, register unsigned int len)
+{
+  enum
+    {
+      TOTAL_KEYWORDS = 30,
+      MIN_WORD_LENGTH = 2,
+      MAX_WORD_LENGTH = 12,
+      MIN_HASH_VALUE = 2,
+      MAX_HASH_VALUE = 46
+    };
+
+  static struct kconf_id wordlist[] =
+    {
+      {-1}, {-1},
+      {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str2,            T_IF,           TF_COMMAND|TF_PARAM},
+      {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str3,            T_TYPE,         TF_COMMAND, S_INT},
+      {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str4,            T_HELP,         TF_COMMAND},
+      {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str5,            T_ENDIF,        TF_COMMAND},
+      {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str6,            T_SELECT,       TF_COMMAND},
+      {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str7,    T_ENDMENU,      TF_COMMAND},
+      {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str8,    T_TYPE,         TF_COMMAND, S_TRISTATE},
+      {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str9,    T_ENDCHOICE,    TF_COMMAND},
+      {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str10,           T_RANGE,        TF_COMMAND},
+      {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str11,           T_TYPE,         TF_COMMAND, S_STRING},
+      {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str12,   T_DEFAULT,      TF_COMMAND, S_UNKNOWN},
+      {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str13,   T_DEFAULT,      TF_COMMAND, S_BOOLEAN},
+      {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str14,           T_MENU,         TF_COMMAND},
+      {-1},
+      {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str16,   T_DEFAULT,      TF_COMMAND, S_BOOLEAN},
+      {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str17,   T_DEFAULT,      TF_COMMAND, S_TRISTATE},
+      {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str18,   T_MAINMENU,     TF_COMMAND},
+      {-1},
+      {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str20,   T_MENUCONFIG,   TF_COMMAND},
+      {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str21,           T_CONFIG,       TF_COMMAND},
+      {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str22,           T_ON,           TF_PARAM},
+      {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str23,           T_TYPE,         TF_COMMAND, S_HEX},
+      {-1}, {-1},
+      {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str26,           T_SOURCE,       TF_COMMAND},
+      {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str27,   T_DEPENDS,      TF_COMMAND},
+      {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str28,   T_OPTIONAL,     TF_COMMAND},
+      {-1}, {-1},
+      {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str31,           T_SELECT,       TF_COMMAND},
+      {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str32,   T_COMMENT,      TF_COMMAND},
+      {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str33,   T_REQUIRES,     TF_COMMAND},
+      {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str34,           T_TYPE,         TF_COMMAND, S_BOOLEAN},
+      {-1}, {-1},
+      {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str37,   T_TYPE,         TF_COMMAND, S_BOOLEAN},
+      {-1}, {-1}, {-1},
+      {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str41,           T_CHOICE,       TF_COMMAND},
+      {-1}, {-1}, {-1}, {-1},
+      {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str46,           T_PROMPT,       TF_COMMAND}
+    };
+
+  if (len <= MAX_WORD_LENGTH && len >= MIN_WORD_LENGTH)
+    {
+      register int key = kconf_id_hash (str, len);
+
+      if (key <= MAX_HASH_VALUE && key >= 0)
+        {
+          register int o = wordlist[key].name;
+          if (o >= 0)
+            {
+              register const char *s = o + kconf_id_strings;
+
+              if (*str == *s && !strncmp (str + 1, s + 1, len - 1) && s[len] == '\0')
+                return &wordlist[key];
+            }
+        }
+    }
+  return 0;
+}
+
index 55517b2877cdb610c57acaae904647e57cfe5d8f..cfa46077c6b43a45dad6d89c60ea5dd274c566cf 100644 (file)
 
 #define START_STRSIZE  16
 
-char *text;
-static char *text_ptr;
+static struct {
+       struct file *file;
+       int lineno;
+} current_pos;
+
+static char *text;
 static int text_size, text_asize;
 
 struct buffer {
@@ -32,29 +36,28 @@ struct buffer *current_buf;
 static int last_ts, first_ts;
 
 static void zconf_endhelp(void);
-static struct buffer *zconf_endfile(void);
+static void zconf_endfile(void);
 
 void new_string(void)
 {
        text = malloc(START_STRSIZE);
        text_asize = START_STRSIZE;
-       text_ptr = text;
        text_size = 0;
-       *text_ptr = 0;
+       *text = 0;
 }
 
 void append_string(const char *str, int size)
 {
        int new_size = text_size + size + 1;
        if (new_size > text_asize) {
+               new_size += START_STRSIZE - 1;
+               new_size &= -START_STRSIZE;
                text = realloc(text, new_size);
                text_asize = new_size;
-               text_ptr = text + text_size;
        }
-       memcpy(text_ptr, str, size);
-       text_ptr += size;
+       memcpy(text + text_size, str, size);
        text_size += size;
-       *text_ptr = 0;
+       text[text_size] = 0;
 }
 
 void alloc_string(const char *str, int size)
@@ -72,10 +75,13 @@ n   [A-Za-z0-9_]
        int str = 0;
        int ts, i;
 
-[ \t]*#.*\n    current_file->lineno++;
+[ \t]*#.*\n    |
+[ \t]*\n       {
+       current_file->lineno++;
+       return T_EOL;
+}
 [ \t]*#.*
 
-[ \t]*\n       current_file->lineno++; return T_EOL;
 
 [ \t]+ {
        BEGIN(COMMAND);
@@ -88,42 +94,25 @@ n   [A-Za-z0-9_]
 
 
 <COMMAND>{
-       "mainmenu"              BEGIN(PARAM); return T_MAINMENU;
-       "menu"                  BEGIN(PARAM); return T_MENU;
-       "endmenu"               BEGIN(PARAM); return T_ENDMENU;
-       "source"                BEGIN(PARAM); return T_SOURCE;
-       "choice"                BEGIN(PARAM); return T_CHOICE;
-       "endchoice"             BEGIN(PARAM); return T_ENDCHOICE;
-       "comment"               BEGIN(PARAM); return T_COMMENT;
-       "config"                BEGIN(PARAM); return T_CONFIG;
-       "menuconfig"            BEGIN(PARAM); return T_MENUCONFIG;
-       "help"                  BEGIN(PARAM); return T_HELP;
-       "if"                    BEGIN(PARAM); return T_IF;
-       "endif"                 BEGIN(PARAM); return T_ENDIF;
-       "depends"               BEGIN(PARAM); return T_DEPENDS;
-       "requires"              BEGIN(PARAM); return T_REQUIRES;
-       "optional"              BEGIN(PARAM); return T_OPTIONAL;
-       "default"               BEGIN(PARAM); return T_DEFAULT;
-       "prompt"                BEGIN(PARAM); return T_PROMPT;
-       "tristate"              BEGIN(PARAM); return T_TRISTATE;
-       "def_tristate"          BEGIN(PARAM); return T_DEF_TRISTATE;
-       "bool"                  BEGIN(PARAM); return T_BOOLEAN;
-       "boolean"               BEGIN(PARAM); return T_BOOLEAN;
-       "def_bool"              BEGIN(PARAM); return T_DEF_BOOLEAN;
-       "def_boolean"           BEGIN(PARAM); return T_DEF_BOOLEAN;
-       "int"                   BEGIN(PARAM); return T_INT;
-       "hex"                   BEGIN(PARAM); return T_HEX;
-       "string"                BEGIN(PARAM); return T_STRING;
-       "select"                BEGIN(PARAM); return T_SELECT;
-       "enable"                BEGIN(PARAM); return T_SELECT;
-       "range"                 BEGIN(PARAM); return T_RANGE;
        {n}+    {
+               struct kconf_id *id = kconf_id_lookup(yytext, yyleng);
+               BEGIN(PARAM);
+               current_pos.file = current_file;
+               current_pos.lineno = current_file->lineno;
+               if (id && id->flags & TF_COMMAND) {
+                       zconflval.id = id;
+                       return id->token;
+               }
                alloc_string(yytext, yyleng);
                zconflval.string = text;
                return T_WORD;
        }
        .
-       \n      current_file->lineno++; BEGIN(INITIAL);
+       \n      {
+               BEGIN(INITIAL);
+               current_file->lineno++;
+               return T_EOL;
+       }
 }
 
 <PARAM>{
@@ -134,8 +123,6 @@ n   [A-Za-z0-9_]
        "!"     return T_NOT;
        "="     return T_EQUAL;
        "!="    return T_UNEQUAL;
-       "if"    return T_IF;
-       "on"    return T_ON;
        \"|\'   {
                str = yytext[0];
                new_string();
@@ -144,6 +131,11 @@ n  [A-Za-z0-9_]
        \n      BEGIN(INITIAL); current_file->lineno++; return T_EOL;
        ---     /* ignore */
        ({n}|[-/.])+    {
+               struct kconf_id *id = kconf_id_lookup(yytext, yyleng);
+               if (id && id->flags & TF_PARAM) {
+                       zconflval.id = id;
+                       return id->token;
+               }
                alloc_string(yytext, yyleng);
                zconflval.string = text;
                return T_WORD;
@@ -236,9 +228,9 @@ n   [A-Za-z0-9_]
 }
 
 <<EOF>>        {
-       if (current_buf) {
+       if (current_file) {
                zconf_endfile();
-               return T_EOF;
+               return T_EOL;
        }
        fclose(yyin);
        yyterminate();
@@ -329,7 +321,7 @@ void zconf_nextfile(const char *name)
        current_file = file;
 }
 
-static struct buffer *zconf_endfile(void)
+static void zconf_endfile(void)
 {
        struct buffer *parent;
 
@@ -345,22 +337,14 @@ static struct buffer *zconf_endfile(void)
        }
        free(current_buf);
        current_buf = parent;
-
-       return parent;
 }
 
 int zconf_lineno(void)
 {
-       if (current_buf)
-               return current_file->lineno - 1;
-       else
-               return 0;
+       return current_pos.lineno;
 }
 
 char *zconf_curname(void)
 {
-       if (current_buf)
-               return current_file->name;
-       else
-               return "<none>";
+       return current_pos.file ? current_pos.file->name : "<none>";
 }
index ff4fcc09720ecbd5303ab4c13a37efdde3eb0c98..ea7755da82f53959a53b8bc808dd85ef426701b1 100644 (file)
@@ -1,7 +1,7 @@
-/* A Bison parser, made by GNU Bison 1.875a.  */
+/* A Bison parser, made by GNU Bison 2.0.  */
 
 /* Skeleton parser for Yacc-like parsing with Bison,
-   Copyright (C) 1984, 1989, 1990, 2000, 2001, 2002, 2003 Free Software Foundation, Inc.
+   Copyright (C) 1984, 1989, 1990, 2000, 2001, 2002, 2003, 2004 Free Software Foundation, Inc.
 
    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
@@ -45,8 +45,7 @@
 /* Using locations.  */
 #define YYLSP_NEEDED 0
 
-/* If NAME_PREFIX is specified substitute the variables and functions
-   names.  */
+/* Substitute the variable and function names.  */
 #define yyparse zconfparse
 #define yylex   zconflex
 #define yyerror zconferror
      T_REQUIRES = 272,
      T_OPTIONAL = 273,
      T_PROMPT = 274,
-     T_DEFAULT = 275,
-     T_TRISTATE = 276,
-     T_DEF_TRISTATE = 277,
-     T_BOOLEAN = 278,
-     T_DEF_BOOLEAN = 279,
-     T_STRING = 280,
-     T_INT = 281,
-     T_HEX = 282,
-     T_WORD = 283,
-     T_WORD_QUOTE = 284,
-     T_UNEQUAL = 285,
-     T_EOF = 286,
-     T_EOL = 287,
-     T_CLOSE_PAREN = 288,
-     T_OPEN_PAREN = 289,
-     T_ON = 290,
-     T_SELECT = 291,
-     T_RANGE = 292,
-     T_OR = 293,
-     T_AND = 294,
-     T_EQUAL = 295,
-     T_NOT = 296
+     T_TYPE = 275,
+     T_DEFAULT = 276,
+     T_SELECT = 277,
+     T_RANGE = 278,
+     T_ON = 279,
+     T_WORD = 280,
+     T_WORD_QUOTE = 281,
+     T_UNEQUAL = 282,
+     T_CLOSE_PAREN = 283,
+     T_OPEN_PAREN = 284,
+     T_EOL = 285,
+     T_OR = 286,
+     T_AND = 287,
+     T_EQUAL = 288,
+     T_NOT = 289
    };
 #endif
 #define T_MAINMENU 258
 #define T_REQUIRES 272
 #define T_OPTIONAL 273
 #define T_PROMPT 274
-#define T_DEFAULT 275
-#define T_TRISTATE 276
-#define T_DEF_TRISTATE 277
-#define T_BOOLEAN 278
-#define T_DEF_BOOLEAN 279
-#define T_STRING 280
-#define T_INT 281
-#define T_HEX 282
-#define T_WORD 283
-#define T_WORD_QUOTE 284
-#define T_UNEQUAL 285
-#define T_EOF 286
-#define T_EOL 287
-#define T_CLOSE_PAREN 288
-#define T_OPEN_PAREN 289
-#define T_ON 290
-#define T_SELECT 291
-#define T_RANGE 292
-#define T_OR 293
-#define T_AND 294
-#define T_EQUAL 295
-#define T_NOT 296
+#define T_TYPE 275
+#define T_DEFAULT 276
+#define T_SELECT 277
+#define T_RANGE 278
+#define T_ON 279
+#define T_WORD 280
+#define T_WORD_QUOTE 281
+#define T_UNEQUAL 282
+#define T_CLOSE_PAREN 283
+#define T_OPEN_PAREN 284
+#define T_EOL 285
+#define T_OR 286
+#define T_AND 287
+#define T_EQUAL 288
+#define T_NOT 289
 
 
 
 #include <string.h>
 #include <stdbool.h>
 
+#define LKC_DIRECT_LINK
+#include "lkc.h"
+
+#include "zconf.hash.c"
+
 #define printd(mask, fmt...) if (cdebug & (mask)) printf(fmt)
 
 #define PRINTD         0x0001
@@ -170,14 +160,18 @@ int cdebug = PRINTD;
 
 extern int zconflex(void);
 static void zconfprint(const char *err, ...);
+static void zconf_error(const char *err, ...);
 static void zconferror(const char *err);
-static bool zconf_endtoken(int token, int starttoken, int endtoken);
+static bool zconf_endtoken(struct kconf_id *id, int starttoken, int endtoken);
 
 struct symbol *symbol_hash[257];
 
 static struct menu *current_menu, *current_entry;
 
+#define YYDEBUG 0
+#if YYDEBUG
 #define YYERROR_VERBOSE
+#endif
 
 
 /* Enabling traces.  */
@@ -196,13 +190,14 @@ static struct menu *current_menu, *current_entry;
 #if ! defined (YYSTYPE) && ! defined (YYSTYPE_IS_DECLARED)
 
 typedef union YYSTYPE {
-       int token;
        char *string;
+       struct file *file;
        struct symbol *symbol;
        struct expr *expr;
        struct menu *menu;
+       struct kconf_id *id;
 } YYSTYPE;
-/* Line 191 of yacc.c.  */
+/* Line 190 of yacc.c.  */
 
 # define yystype YYSTYPE /* obsolescent; will be withdrawn */
 # define YYSTYPE_IS_DECLARED 1
@@ -214,27 +209,26 @@ typedef union YYSTYPE {
 /* Copy the second part of user declarations.  */
 
 
-#define LKC_DIRECT_LINK
-#include "lkc.h"
-
-
-/* Line 214 of yacc.c.  */
+/* Line 213 of yacc.c.  */
 
 
 #if ! defined (yyoverflow) || YYERROR_VERBOSE
 
+# ifndef YYFREE
+#  define YYFREE free
+# endif
+# ifndef YYMALLOC
+#  define YYMALLOC malloc
+# endif
+
 /* The parser invokes alloca or malloc; define the necessary symbols.  */
 
-# if YYSTACK_USE_ALLOCA
-#  define YYSTACK_ALLOC alloca
-# else
-#  ifndef YYSTACK_USE_ALLOCA
-#   if defined (alloca) || defined (_ALLOCA_H)
-#    define YYSTACK_ALLOC alloca
+# ifdef YYSTACK_USE_ALLOCA
+#  if YYSTACK_USE_ALLOCA
+#   ifdef __GNUC__
+#    define YYSTACK_ALLOC __builtin_alloca
 #   else
-#    ifdef __GNUC__
-#     define YYSTACK_ALLOC __builtin_alloca
-#    endif
+#    define YYSTACK_ALLOC alloca
 #   endif
 #  endif
 # endif
@@ -247,20 +241,20 @@ typedef union YYSTYPE {
 #   include <stdlib.h> /* INFRINGES ON USER NAME SPACE */
 #   define YYSIZE_T size_t
 #  endif
-#  define YYSTACK_ALLOC malloc
-#  define YYSTACK_FREE free
+#  define YYSTACK_ALLOC YYMALLOC
+#  define YYSTACK_FREE YYFREE
 # endif
 #endif /* ! defined (yyoverflow) || YYERROR_VERBOSE */
 
 
 #if (! defined (yyoverflow) \
      && (! defined (__cplusplus) \
-        || (YYSTYPE_IS_TRIVIAL)))
+        || (defined (YYSTYPE_IS_TRIVIAL) && YYSTYPE_IS_TRIVIAL)))
 
 /* A type that is properly aligned for any stack member.  */
 union yyalloc
 {
-  short yyss;
+  short int yyss;
   YYSTYPE yyvs;
   };
 
@@ -270,13 +264,13 @@ union yyalloc
 /* The size of an array large to enough to hold all stacks, each with
    N elements.  */
 # define YYSTACK_BYTES(N) \
-     ((N) * (sizeof (short) + sizeof (YYSTYPE))                                \
+     ((N) * (sizeof (short int) + sizeof (YYSTYPE))                    \
       + YYSTACK_GAP_MAXIMUM)
 
 /* Copy COUNT objects from FROM to TO.  The source and destination do
    not overlap.  */
 # ifndef YYCOPY
-#  if 1 < __GNUC__
+#  if defined (__GNUC__) && 1 < __GNUC__
 #   define YYCOPY(To, From, Count) \
       __builtin_memcpy (To, From, (Count) * sizeof (*(From)))
 #  else
@@ -312,26 +306,26 @@ union yyalloc
 #if defined (__STDC__) || defined (__cplusplus)
    typedef signed char yysigned_char;
 #else
-   typedef short yysigned_char;
+   typedef short int yysigned_char;
 #endif
 
 /* YYFINAL -- State number of the termination state. */
-#define YYFINAL  2
+#define YYFINAL  3
 /* YYLAST -- Last index in YYTABLE.  */
-#define YYLAST   201
+#define YYLAST   264
 
 /* YYNTOKENS -- Number of terminals. */
-#define YYNTOKENS  42
+#define YYNTOKENS  35
 /* YYNNTS -- Number of nonterminals. */
-#define YYNNTS  41
+#define YYNNTS  42
 /* YYNRULES -- Number of rules. */
 #define YYNRULES  104
 /* YYNRULES -- Number of states. */
-#define YYNSTATES  182
+#define YYNSTATES  175
 
 /* YYTRANSLATE(YYLEX) -- Bison symbol number corresponding to YYLEX.  */
 #define YYUNDEFTOK  2
-#define YYMAXUTOK   296
+#define YYMAXUTOK   289
 
 #define YYTRANSLATE(YYX)                                               \
   ((unsigned int) (YYX) <= YYMAXUTOK ? yytranslate[YYX] : YYUNDEFTOK)
@@ -367,79 +361,78 @@ static const unsigned char yytranslate[] =
        2,     2,     2,     2,     2,     2,     1,     2,     3,     4,
        5,     6,     7,     8,     9,    10,    11,    12,    13,    14,
       15,    16,    17,    18,    19,    20,    21,    22,    23,    24,
-      25,    26,    27,    28,    29,    30,    31,    32,    33,    34,
-      35,    36,    37,    38,    39,    40,    41
+      25,    26,    27,    28,    29,    30,    31,    32,    33,    34
 };
 
 #if YYDEBUG
 /* YYPRHS[YYN] -- Index of the first RHS symbol of rule number YYN in
    YYRHS.  */
-static const unsigned short yyprhs[] =
+static const unsigned short int yyprhs[] =
 {
-       0,     0,     3,     4,     7,     9,    11,    13,    17,    19,
-      21,    23,    26,    28,    30,    32,    34,    36,    38,    42,
-      45,    49,    52,    53,    56,    59,    62,    65,    69,    74,
-      78,    83,    87,    91,    95,   100,   105,   110,   116,   119,
-     122,   124,   128,   131,   132,   135,   138,   141,   144,   149,
-     153,   157,   160,   165,   166,   169,   173,   175,   179,   182,
-     183,   186,   189,   192,   196,   199,   201,   205,   208,   209,
-     212,   215,   218,   222,   226,   228,   232,   235,   238,   241,
-     242,   245,   248,   253,   257,   261,   262,   265,   267,   269,
-     272,   275,   278,   280,   282,   283,   286,   288,   292,   296,
-     300,   303,   307,   311,   313
+       0,     0,     3,     5,     6,     9,    12,    15,    20,    23,
+      28,    33,    37,    39,    41,    43,    45,    47,    49,    51,
+      53,    55,    57,    59,    61,    63,    67,    70,    74,    77,
+      81,    84,    85,    88,    91,    94,    97,   100,   104,   109,
+     114,   119,   125,   128,   131,   133,   137,   138,   141,   144,
+     147,   150,   153,   158,   162,   165,   170,   171,   174,   178,
+     180,   184,   185,   188,   191,   194,   198,   201,   203,   207,
+     208,   211,   214,   217,   221,   225,   228,   231,   234,   235,
+     238,   241,   244,   249,   253,   257,   258,   261,   263,   265,
+     268,   271,   274,   276,   279,   280,   283,   285,   289,   293,
+     297,   300,   304,   308,   310
 };
 
 /* YYRHS -- A `-1'-separated list of the rules' RHS. */
 static const yysigned_char yyrhs[] =
 {
-      43,     0,    -1,    -1,    43,    44,    -1,    45,    -1,    55,
-      -1,    66,    -1,     3,    77,    79,    -1,     5,    -1,    15,
-      -1,     8,    -1,     1,    79,    -1,    61,    -1,    71,    -1,
-      47,    -1,    49,    -1,    69,    -1,    79,    -1,    10,    28,
-      32,    -1,    46,    50,    -1,    11,    28,    32,    -1,    48,
-      50,    -1,    -1,    50,    51,    -1,    50,    75,    -1,    50,
-      73,    -1,    50,    32,    -1,    21,    76,    32,    -1,    22,
-      81,    80,    32,    -1,    23,    76,    32,    -1,    24,    81,
-      80,    32,    -1,    26,    76,    32,    -1,    27,    76,    32,
-      -1,    25,    76,    32,    -1,    19,    77,    80,    32,    -1,
-      20,    81,    80,    32,    -1,    36,    28,    80,    32,    -1,
-      37,    82,    82,    80,    32,    -1,     7,    32,    -1,    52,
-      56,    -1,    78,    -1,    53,    58,    54,    -1,    53,    58,
-      -1,    -1,    56,    57,    -1,    56,    75,    -1,    56,    73,
-      -1,    56,    32,    -1,    19,    77,    80,    32,    -1,    21,
-      76,    32,    -1,    23,    76,    32,    -1,    18,    32,    -1,
-      20,    28,    80,    32,    -1,    -1,    58,    45,    -1,    14,
-      81,    32,    -1,    78,    -1,    59,    62,    60,    -1,    59,
-      62,    -1,    -1,    62,    45,    -1,    62,    66,    -1,    62,
-      55,    -1,     4,    77,    32,    -1,    63,    74,    -1,    78,
-      -1,    64,    67,    65,    -1,    64,    67,    -1,    -1,    67,
-      45,    -1,    67,    66,    -1,    67,    55,    -1,    67,     1,
-      32,    -1,     6,    77,    32,    -1,    68,    -1,     9,    77,
-      32,    -1,    70,    74,    -1,    12,    32,    -1,    72,    13,
-      -1,    -1,    74,    75,    -1,    74,    32,    -1,    16,    35,
-      81,    32,    -1,    16,    81,    32,    -1,    17,    81,    32,
-      -1,    -1,    77,    80,    -1,    28,    -1,    29,    -1,     5,
-      79,    -1,     8,    79,    -1,    15,    79,    -1,    32,    -1,
-      31,    -1,    -1,    14,    81,    -1,    82,    -1,    82,    40,
-      82,    -1,    82,    30,    82,    -1,    34,    81,    33,    -1,
-      41,    81,    -1,    81,    38,    81,    -1,    81,    39,    81,
-      -1,    28,    -1,    29,    -1
+      36,     0,    -1,    37,    -1,    -1,    37,    39,    -1,    37,
+      50,    -1,    37,    61,    -1,    37,     3,    71,    73,    -1,
+      37,    72,    -1,    37,    25,     1,    30,    -1,    37,    38,
+       1,    30,    -1,    37,     1,    30,    -1,    16,    -1,    19,
+      -1,    20,    -1,    22,    -1,    18,    -1,    23,    -1,    21,
+      -1,    30,    -1,    56,    -1,    65,    -1,    42,    -1,    44,
+      -1,    63,    -1,    25,     1,    30,    -1,     1,    30,    -1,
+      10,    25,    30,    -1,    41,    45,    -1,    11,    25,    30,
+      -1,    43,    45,    -1,    -1,    45,    46,    -1,    45,    69,
+      -1,    45,    67,    -1,    45,    40,    -1,    45,    30,    -1,
+      20,    70,    30,    -1,    19,    71,    74,    30,    -1,    21,
+      75,    74,    30,    -1,    22,    25,    74,    30,    -1,    23,
+      76,    76,    74,    30,    -1,     7,    30,    -1,    47,    51,
+      -1,    72,    -1,    48,    53,    49,    -1,    -1,    51,    52,
+      -1,    51,    69,    -1,    51,    67,    -1,    51,    30,    -1,
+      51,    40,    -1,    19,    71,    74,    30,    -1,    20,    70,
+      30,    -1,    18,    30,    -1,    21,    25,    74,    30,    -1,
+      -1,    53,    39,    -1,    14,    75,    73,    -1,    72,    -1,
+      54,    57,    55,    -1,    -1,    57,    39,    -1,    57,    61,
+      -1,    57,    50,    -1,     4,    71,    30,    -1,    58,    68,
+      -1,    72,    -1,    59,    62,    60,    -1,    -1,    62,    39,
+      -1,    62,    61,    -1,    62,    50,    -1,     6,    71,    30,
+      -1,     9,    71,    30,    -1,    64,    68,    -1,    12,    30,
+      -1,    66,    13,    -1,    -1,    68,    69,    -1,    68,    30,
+      -1,    68,    40,    -1,    16,    24,    75,    30,    -1,    16,
+      75,    30,    -1,    17,    75,    30,    -1,    -1,    71,    74,
+      -1,    25,    -1,    26,    -1,     5,    30,    -1,     8,    30,
+      -1,    15,    30,    -1,    30,    -1,    73,    30,    -1,    -1,
+      14,    75,    -1,    76,    -1,    76,    33,    76,    -1,    76,
+      27,    76,    -1,    29,    75,    28,    -1,    34,    75,    -1,
+      75,    31,    75,    -1,    75,    32,    75,    -1,    25,    -1,
+      26,    -1
 };
 
 /* YYRLINE[YYN] -- source line where rule number YYN was defined.  */
-static const unsigned short yyrline[] =
+static const unsigned short int yyrline[] =
 {
-       0,    94,    94,    95,    98,    99,   100,   101,   102,   103,
-     104,   105,   109,   110,   111,   112,   113,   114,   120,   128,
-     134,   142,   152,   154,   155,   156,   157,   160,   166,   173,
-     179,   186,   192,   198,   204,   210,   216,   222,   230,   239,
-     245,   254,   255,   261,   263,   264,   265,   266,   269,   275,
-     281,   287,   293,   299,   301,   306,   315,   324,   325,   331,
-     333,   334,   335,   340,   347,   353,   362,   363,   369,   371,
-     372,   373,   374,   377,   383,   390,   397,   404,   410,   417,
-     418,   419,   422,   427,   432,   440,   442,   447,   448,   451,
-     452,   453,   457,   457,   459,   460,   463,   464,   465,   466,
-     467,   468,   469,   472,   473
+       0,   103,   103,   105,   107,   108,   109,   110,   111,   112,
+     113,   117,   121,   121,   121,   121,   121,   121,   121,   125,
+     126,   127,   128,   129,   130,   134,   135,   141,   149,   155,
+     163,   173,   175,   176,   177,   178,   179,   182,   190,   196,
+     206,   212,   220,   229,   234,   242,   245,   247,   248,   249,
+     250,   251,   254,   260,   271,   277,   287,   289,   294,   302,
+     310,   313,   315,   316,   317,   322,   329,   334,   342,   345,
+     347,   348,   349,   352,   360,   367,   374,   380,   387,   389,
+     390,   391,   394,   399,   404,   412,   414,   419,   420,   423,
+     424,   425,   429,   430,   433,   434,   437,   438,   439,   440,
+     441,   442,   443,   446,   447
 };
 #endif
 
@@ -448,67 +441,65 @@ static const unsigned short yyrline[] =
    First, the terminals, then, starting at YYNTOKENS, nonterminals. */
 static const char *const yytname[] =
 {
-  "$end", "error", "$undefined", "T_MAINMENU", "T_MENU", "T_ENDMENU", 
-  "T_SOURCE", "T_CHOICE", "T_ENDCHOICE", "T_COMMENT", "T_CONFIG", 
-  "T_MENUCONFIG", "T_HELP", "T_HELPTEXT", "T_IF", "T_ENDIF", "T_DEPENDS", 
-  "T_REQUIRES", "T_OPTIONAL", "T_PROMPT", "T_DEFAULT", "T_TRISTATE", 
-  "T_DEF_TRISTATE", "T_BOOLEAN", "T_DEF_BOOLEAN", "T_STRING", "T_INT", 
-  "T_HEX", "T_WORD", "T_WORD_QUOTE", "T_UNEQUAL", "T_EOF", "T_EOL", 
-  "T_CLOSE_PAREN", "T_OPEN_PAREN", "T_ON", "T_SELECT", "T_RANGE", "T_OR", 
-  "T_AND", "T_EQUAL", "T_NOT", "$accept", "input", "block", 
-  "common_block", "config_entry_start", "config_stmt", 
-  "menuconfig_entry_start", "menuconfig_stmt", "config_option_list", 
-  "config_option", "choice", "choice_entry", "choice_end", "choice_stmt", 
-  "choice_option_list", "choice_option", "choice_block", "if", "if_end", 
-  "if_stmt", "if_block", "menu", "menu_entry", "menu_end", "menu_stmt", 
-  "menu_block", "source", "source_stmt", "comment", "comment_stmt", 
-  "help_start", "help", "depends_list", "depends", "prompt_stmt_opt", 
-  "prompt", "end", "nl_or_eof", "if_expr", "expr", "symbol", 0
+  "$end", "error", "$undefined", "T_MAINMENU", "T_MENU", "T_ENDMENU",
+  "T_SOURCE", "T_CHOICE", "T_ENDCHOICE", "T_COMMENT", "T_CONFIG",
+  "T_MENUCONFIG", "T_HELP", "T_HELPTEXT", "T_IF", "T_ENDIF", "T_DEPENDS",
+  "T_REQUIRES", "T_OPTIONAL", "T_PROMPT", "T_TYPE", "T_DEFAULT",
+  "T_SELECT", "T_RANGE", "T_ON", "T_WORD", "T_WORD_QUOTE", "T_UNEQUAL",
+  "T_CLOSE_PAREN", "T_OPEN_PAREN", "T_EOL", "T_OR", "T_AND", "T_EQUAL",
+  "T_NOT", "$accept", "input", "stmt_list", "option_name", "common_stmt",
+  "option_error", "config_entry_start", "config_stmt",
+  "menuconfig_entry_start", "menuconfig_stmt", "config_option_list",
+  "config_option", "choice", "choice_entry", "choice_end", "choice_stmt",
+  "choice_option_list", "choice_option", "choice_block", "if_entry",
+  "if_end", "if_stmt", "if_block", "menu", "menu_entry", "menu_end",
+  "menu_stmt", "menu_block", "source_stmt", "comment", "comment_stmt",
+  "help_start", "help", "depends_list", "depends", "prompt_stmt_opt",
+  "prompt", "end", "nl", "if_expr", "expr", "symbol", 0
 };
 #endif
 
 # ifdef YYPRINT
 /* YYTOKNUM[YYLEX-NUM] -- Internal token number corresponding to
    token YYLEX-NUM.  */
-static const unsigned short yytoknum[] =
+static const unsigned short int yytoknum[] =
 {
        0,   256,   257,   258,   259,   260,   261,   262,   263,   264,
      265,   266,   267,   268,   269,   270,   271,   272,   273,   274,
      275,   276,   277,   278,   279,   280,   281,   282,   283,   284,
-     285,   286,   287,   288,   289,   290,   291,   292,   293,   294,
-     295,   296
+     285,   286,   287,   288,   289
 };
 # endif
 
 /* YYR1[YYN] -- Symbol number of symbol that rule YYN derives.  */
 static const unsigned char yyr1[] =
 {
-       0,    42,    43,    43,    44,    44,    44,    44,    44,    44,
-      44,    44,    45,    45,    45,    45,    45,    45,    46,    47,
-      48,    49,    50,    50,    50,    50,    50,    51,    51,    51,
-      51,    51,    51,    51,    51,    51,    51,    51,    52,    53,
-      54,    55,    55,    56,    56,    56,    56,    56,    57,    57,
-      57,    57,    57,    58,    58,    59,    60,    61,    61,    62,
-      62,    62,    62,    63,    64,    65,    66,    66,    67,    67,
-      67,    67,    67,    68,    69,    70,    71,    72,    73,    74,
-      74,    74,    75,    75,    75,    76,    76,    77,    77,    78,
-      78,    78,    79,    79,    80,    80,    81,    81,    81,    81,
-      81,    81,    81,    82,    82
+       0,    35,    36,    37,    37,    37,    37,    37,    37,    37,
+      37,    37,    38,    38,    38,    38,    38,    38,    38,    39,
+      39,    39,    39,    39,    39,    40,    40,    41,    42,    43,
+      44,    45,    45,    45,    45,    45,    45,    46,    46,    46,
+      46,    46,    47,    48,    49,    50,    51,    51,    51,    51,
+      51,    51,    52,    52,    52,    52,    53,    53,    54,    55,
+      56,    57,    57,    57,    57,    58,    59,    60,    61,    62,
+      62,    62,    62,    63,    64,    65,    66,    67,    68,    68,
+      68,    68,    69,    69,    69,    70,    70,    71,    71,    72,
+      72,    72,    73,    73,    74,    74,    75,    75,    75,    75,
+      75,    75,    75,    76,    76
 };
 
 /* YYR2[YYN] -- Number of symbols composing right hand side of rule YYN.  */
 static const unsigned char yyr2[] =
 {
-       0,     2,     0,     2,     1,     1,     1,     3,     1,     1,
-       1,     2,     1,     1,     1,     1,     1,     1,     3,     2,
-       3,     2,     0,     2,     2,     2,     2,     3,     4,     3,
-       4,     3,     3,     3,     4,     4,     4,     5,     2,     2,
-       1,     3,     2,     0,     2,     2,     2,     2,     4,     3,
-       3,     2,     4,     0,     2,     3,     1,     3,     2,     0,
-       2,     2,     2,     3,     2,     1,     3,     2,     0,     2,
-       2,     2,     3,     3,     1,     3,     2,     2,     2,     0,
+       0,     2,     1,     0,     2,     2,     2,     4,     2,     4,
+       4,     3,     1,     1,     1,     1,     1,     1,     1,     1,
+       1,     1,     1,     1,     1,     3,     2,     3,     2,     3,
+       2,     0,     2,     2,     2,     2,     2,     3,     4,     4,
+       4,     5,     2,     2,     1,     3,     0,     2,     2,     2,
+       2,     2,     4,     3,     2,     4,     0,     2,     3,     1,
+       3,     0,     2,     2,     2,     3,     2,     1,     3,     0,
+       2,     2,     2,     3,     3,     2,     2,     2,     0,     2,
        2,     2,     4,     3,     3,     0,     2,     1,     1,     2,
-       2,     2,     1,     1,     0,     2,     1,     3,     3,     3,
+       2,     2,     1,     2,     0,     2,     1,     3,     3,     3,
        2,     3,     3,     1,     1
 };
 
@@ -517,151 +508,160 @@ static const unsigned char yyr2[] =
    means the default is an error.  */
 static const unsigned char yydefact[] =
 {
-       2,     0,     1,     0,     0,     0,     8,     0,     0,    10,
-       0,     0,     0,     0,     9,    93,    92,     3,     4,    22,
-      14,    22,    15,    43,    53,     5,    59,    12,    79,    68,
-       6,    74,    16,    79,    13,    17,    11,    87,    88,     0,
-       0,     0,    38,     0,     0,     0,   103,   104,     0,     0,
-       0,    96,    19,    21,    39,    42,    58,    64,     0,    76,
-       7,    63,    73,    75,    18,    20,     0,   100,    55,     0,
-       0,     0,     0,     0,     0,     0,     0,     0,    85,     0,
-      85,     0,    85,    85,    85,    26,     0,     0,    23,     0,
-      25,    24,     0,     0,     0,    85,    85,    47,    44,    46,
-      45,     0,     0,     0,    54,    41,    40,    60,    62,    57,
-      61,    56,    81,    80,     0,    69,    71,    66,    70,    65,
-      99,   101,   102,    98,    97,    77,     0,     0,     0,    94,
-      94,     0,    94,    94,     0,    94,     0,     0,     0,    94,
-       0,    78,    51,    94,    94,     0,     0,    89,    90,    91,
-      72,     0,    83,    84,     0,     0,     0,    27,    86,     0,
-      29,     0,    33,    31,    32,     0,    94,     0,     0,    49,
-      50,    82,    95,    34,    35,    28,    30,    36,     0,    48,
-      52,    37
+       3,     0,     0,     1,     0,     0,     0,     0,     0,     0,
+       0,     0,     0,     0,     0,     0,    12,    16,    13,    14,
+      18,    15,    17,     0,    19,     0,     4,    31,    22,    31,
+      23,    46,    56,     5,    61,    20,    78,    69,     6,    24,
+      78,    21,     8,    11,    87,    88,     0,     0,    89,     0,
+      42,    90,     0,     0,     0,   103,   104,     0,     0,     0,
+      96,    91,     0,     0,     0,     0,     0,     0,     0,     0,
+       0,     0,    92,     7,    65,    73,    74,    27,    29,     0,
+     100,     0,     0,    58,     0,     0,     9,    10,     0,     0,
+       0,     0,     0,    85,     0,     0,     0,     0,    36,    35,
+      32,     0,    34,    33,     0,     0,    85,     0,    50,    51,
+      47,    49,    48,    57,    45,    44,    62,    64,    60,    63,
+      59,    80,    81,    79,    70,    72,    68,    71,    67,    93,
+      99,   101,   102,    98,    97,    26,    76,     0,     0,     0,
+      94,     0,    94,    94,    94,     0,     0,    77,    54,    94,
+       0,    94,     0,    83,    84,     0,     0,    37,    86,     0,
+       0,    94,    25,     0,    53,     0,    82,    95,    38,    39,
+      40,     0,    52,    55,    41
 };
 
 /* YYDEFGOTO[NTERM-NUM]. */
-static const short yydefgoto[] =
+static const short int yydefgoto[] =
 {
-      -1,     1,    17,    18,    19,    20,    21,    22,    52,    88,
-      23,    24,   105,    25,    54,    98,    55,    26,   109,    27,
-      56,    28,    29,   117,    30,    58,    31,    32,    33,    34,
-      89,    90,    57,    91,   131,   132,   106,    35,   155,    50,
-      51
+      -1,     1,     2,    25,    26,    99,    27,    28,    29,    30,
+      64,   100,    31,    32,   114,    33,    66,   110,    67,    34,
+     118,    35,    68,    36,    37,   126,    38,    70,    39,    40,
+      41,   101,   102,    69,   103,   141,   142,    42,    73,   156,
+      59,    60
 };
 
 /* YYPACT[STATE-NUM] -- Index in YYTABLE of the portion describing
    STATE-NUM.  */
-#define YYPACT_NINF -99
-static const short yypact[] =
+#define YYPACT_NINF -78
+static const short int yypact[] =
 {
-     -99,    48,   -99,    38,    46,    46,   -99,    46,   -29,   -99,
-      46,   -17,    -3,   -11,   -99,   -99,   -99,   -99,   -99,   -99,
-     -99,   -99,   -99,   -99,   -99,   -99,   -99,   -99,   -99,   -99,
-     -99,   -99,   -99,   -99,   -99,   -99,   -99,   -99,   -99,    38,
-      12,    15,   -99,    18,    51,    62,   -99,   -99,   -11,   -11,
-       4,   -24,   138,   138,   160,   121,   110,    -4,    81,    -4,
-     -99,   -99,   -99,   -99,   -99,   -99,   -19,   -99,   -99,   -11,
-     -11,    70,    70,    73,    32,   -11,    46,   -11,    46,   -11,
-      46,   -11,    46,    46,    46,   -99,    36,    70,   -99,    95,
-     -99,   -99,    96,    46,   106,    46,    46,   -99,   -99,   -99,
-     -99,    38,    38,    38,   -99,   -99,   -99,   -99,   -99,   -99,
-     -99,   -99,   -99,   -99,   112,   -99,   -99,   -99,   -99,   -99,
-     -99,   117,   -99,   -99,   -99,   -99,   -11,    33,    65,   131,
-       1,   119,   131,     1,   136,     1,   153,   154,   155,   131,
-      70,   -99,   -99,   131,   131,   156,   157,   -99,   -99,   -99,
-     -99,   101,   -99,   -99,   -11,   158,   159,   -99,   -99,   161,
-     -99,   162,   -99,   -99,   -99,   163,   131,   164,   165,   -99,
-     -99,   -99,    99,   -99,   -99,   -99,   -99,   -99,   166,   -99,
-     -99,   -99
+     -78,     2,   159,   -78,   -21,     0,     0,   -12,     0,     1,
+       4,     0,    27,    38,    60,    58,   -78,   -78,   -78,   -78,
+     -78,   -78,   -78,   100,   -78,   104,   -78,   -78,   -78,   -78,
+     -78,   -78,   -78,   -78,   -78,   -78,   -78,   -78,   -78,   -78,
+     -78,   -78,   -78,   -78,   -78,   -78,    86,   113,   -78,   114,
+     -78,   -78,   125,   127,   128,   -78,   -78,    60,    60,   210,
+      65,   -78,   141,   142,    39,   103,   182,   200,     6,    66,
+       6,   131,   -78,   146,   -78,   -78,   -78,   -78,   -78,   196,
+     -78,    60,    60,   146,    40,    40,   -78,   -78,   155,   156,
+      -2,    60,     0,     0,    60,   105,    40,   194,   -78,   -78,
+     -78,   206,   -78,   -78,   183,     0,     0,   195,   -78,   -78,
+     -78,   -78,   -78,   -78,   -78,   -78,   -78,   -78,   -78,   -78,
+     -78,   -78,   -78,   -78,   -78,   -78,   -78,   -78,   -78,   -78,
+     -78,   197,   -78,   -78,   -78,   -78,   -78,    60,   213,   216,
+     212,   203,   212,   190,   212,    40,   208,   -78,   -78,   212,
+     222,   212,   219,   -78,   -78,    60,   223,   -78,   -78,   224,
+     225,   212,   -78,   226,   -78,   227,   -78,    47,   -78,   -78,
+     -78,   228,   -78,   -78,   -78
 };
 
 /* YYPGOTO[NTERM-NUM].  */
-static const short yypgoto[] =
+static const short int yypgoto[] =
 {
-     -99,   -99,   -99,   111,   -99,   -99,   -99,   -99,   178,   -99,
-     -99,   -99,   -99,    91,   -99,   -99,   -99,   -99,   -99,   -99,
-     -99,   -99,   -99,   -99,   115,   -99,   -99,   -99,   -99,   -99,
-     -99,   146,   168,    89,    27,     0,   126,    -1,   -98,   -48,
-     -63
+     -78,   -78,   -78,   -78,   164,   -36,   -78,   -78,   -78,   -78,
+     230,   -78,   -78,   -78,   -78,    29,   -78,   -78,   -78,   -78,
+     -78,   -78,   -78,   -78,   -78,   -78,    59,   -78,   -78,   -78,
+     -78,   -78,   198,   220,    24,   157,    -5,   169,   202,    74,
+     -53,   -77
 };
 
 /* YYTABLE[YYPACT[STATE-NUM]].  What to do in state STATE-NUM.  If
    positive, shift that token.  If negative, reduce the rule which
    number is the opposite.  If zero, do what YYDEFACT says.
    If YYTABLE_NINF, syntax error.  */
-#define YYTABLE_NINF -68
-static const short yytable[] =
+#define YYTABLE_NINF -76
+static const short int yytable[] =
 {
-      66,    67,    36,    42,    39,    40,    71,    41,   123,   124,
-      43,    44,    74,    75,   120,   154,    72,    46,    47,    69,
-      70,   121,   122,    48,   140,    45,   127,   128,   112,   130,
-      49,   133,   156,   135,   158,   159,    68,   161,    60,    69,
-      70,   165,    69,    70,    61,   167,   168,    62,     2,     3,
-      63,     4,     5,     6,     7,     8,     9,    10,    11,    12,
-      46,    47,    13,    14,   139,   152,    48,   126,   178,    15,
-      16,    69,    70,    49,    37,    38,   129,   166,   151,    15,
-      16,   -67,   114,    64,   -67,     5,   101,     7,     8,   102,
-      10,    11,    12,   143,    65,    13,   103,   153,    46,    47,
-     147,   148,   149,    69,    70,   125,   172,   134,   141,   136,
-     137,   138,    15,    16,     5,   101,     7,     8,   102,    10,
-      11,    12,   145,   146,    13,   103,   101,     7,   142,   102,
-      10,    11,    12,   171,   144,    13,   103,    69,    70,    69,
-      70,    15,    16,   100,   150,   154,   113,   108,   113,   116,
-      73,   157,    15,    16,    74,    75,    70,    76,    77,    78,
-      79,    80,    81,    82,    83,    84,   104,   107,   160,   115,
-      85,   110,    73,   118,    86,    87,    74,    75,    92,    93,
-      94,    95,   111,    96,   119,   162,   163,   164,   169,   170,
-     173,   174,    97,   175,   176,   177,   179,   180,   181,    53,
-      99,    59
+      46,    47,     3,    49,    79,    80,    52,   133,   134,    43,
+       6,     7,     8,     9,    10,    11,    12,    13,    48,   145,
+      14,    15,   137,    55,    56,    44,    45,    57,   131,   132,
+     109,    50,    58,   122,    51,   122,    24,   138,   139,   -28,
+      88,   143,   -28,   -28,   -28,   -28,   -28,   -28,   -28,   -28,
+     -28,    89,    53,   -28,   -28,    90,    91,   -28,    92,    93,
+      94,    95,    96,    54,    97,    55,    56,    88,   161,    98,
+     -66,   -66,   -66,   -66,   -66,   -66,   -66,   -66,    81,    82,
+     -66,   -66,    90,    91,   152,    55,    56,   140,    61,    57,
+     112,    97,    84,   123,    58,   123,   121,   117,    85,   125,
+     149,    62,   167,   -30,    88,    63,   -30,   -30,   -30,   -30,
+     -30,   -30,   -30,   -30,   -30,    89,    72,   -30,   -30,    90,
+      91,   -30,    92,    93,    94,    95,    96,   119,    97,   127,
+     144,   -75,    88,    98,   -75,   -75,   -75,   -75,   -75,   -75,
+     -75,   -75,   -75,    74,    75,   -75,   -75,    90,    91,   -75,
+     -75,   -75,   -75,   -75,   -75,    76,    97,    77,    78,    -2,
+       4,   121,     5,     6,     7,     8,     9,    10,    11,    12,
+      13,    86,    87,    14,    15,    16,   129,    17,    18,    19,
+      20,    21,    22,    88,    23,   135,   136,   -43,   -43,    24,
+     -43,   -43,   -43,   -43,    89,   146,   -43,   -43,    90,    91,
+     104,   105,   106,   107,   155,     7,     8,    97,    10,    11,
+      12,    13,   108,   148,    14,    15,   158,   159,   160,   147,
+     151,    81,    82,   163,   130,   165,   155,    81,    82,    82,
+      24,   113,   116,   157,   124,   171,   115,   120,   162,   128,
+      72,    81,    82,   153,    81,    82,   154,    81,    82,   166,
+      81,    82,   164,   168,   169,   170,   172,   173,   174,    65,
+      71,    83,     0,   150,   111
 };
 
-static const unsigned char yycheck[] =
+static const short int yycheck[] =
 {
-      48,    49,     3,    32,     4,     5,    30,     7,    71,    72,
-      10,    28,    16,    17,    33,    14,    40,    28,    29,    38,
-      39,    69,    70,    34,    87,    28,    74,    75,    32,    77,
-      41,    79,   130,    81,   132,   133,    32,   135,    39,    38,
-      39,   139,    38,    39,    32,   143,   144,    32,     0,     1,
-      32,     3,     4,     5,     6,     7,     8,     9,    10,    11,
-      28,    29,    14,    15,    28,    32,    34,    35,   166,    31,
-      32,    38,    39,    41,    28,    29,    76,   140,   126,    31,
-      32,     0,     1,    32,     3,     4,     5,     6,     7,     8,
-       9,    10,    11,    93,    32,    14,    15,    32,    28,    29,
-     101,   102,   103,    38,    39,    32,   154,    80,    13,    82,
-      83,    84,    31,    32,     4,     5,     6,     7,     8,     9,
-      10,    11,    95,    96,    14,    15,     5,     6,    32,     8,
-       9,    10,    11,    32,    28,    14,    15,    38,    39,    38,
-      39,    31,    32,    54,    32,    14,    57,    56,    59,    58,
-      12,    32,    31,    32,    16,    17,    39,    19,    20,    21,
-      22,    23,    24,    25,    26,    27,    55,    56,    32,    58,
-      32,    56,    12,    58,    36,    37,    16,    17,    18,    19,
-      20,    21,    56,    23,    58,    32,    32,    32,    32,    32,
-      32,    32,    32,    32,    32,    32,    32,    32,    32,    21,
-      54,    33
+       5,     6,     0,     8,    57,    58,    11,    84,    85,    30,
+       4,     5,     6,     7,     8,     9,    10,    11,    30,    96,
+      14,    15,    24,    25,    26,    25,    26,    29,    81,    82,
+      66,    30,    34,    69,    30,    71,    30,    90,    91,     0,
+       1,    94,     3,     4,     5,     6,     7,     8,     9,    10,
+      11,    12,    25,    14,    15,    16,    17,    18,    19,    20,
+      21,    22,    23,    25,    25,    25,    26,     1,   145,    30,
+       4,     5,     6,     7,     8,     9,    10,    11,    31,    32,
+      14,    15,    16,    17,   137,    25,    26,    92,    30,    29,
+      66,    25,    27,    69,    34,    71,    30,    68,    33,    70,
+     105,     1,   155,     0,     1,     1,     3,     4,     5,     6,
+       7,     8,     9,    10,    11,    12,    30,    14,    15,    16,
+      17,    18,    19,    20,    21,    22,    23,    68,    25,    70,
+      25,     0,     1,    30,     3,     4,     5,     6,     7,     8,
+       9,    10,    11,    30,    30,    14,    15,    16,    17,    18,
+      19,    20,    21,    22,    23,    30,    25,    30,    30,     0,
+       1,    30,     3,     4,     5,     6,     7,     8,     9,    10,
+      11,    30,    30,    14,    15,    16,    30,    18,    19,    20,
+      21,    22,    23,     1,    25,    30,    30,     5,     6,    30,
+       8,     9,    10,    11,    12,     1,    14,    15,    16,    17,
+      18,    19,    20,    21,    14,     5,     6,    25,     8,     9,
+      10,    11,    30,    30,    14,    15,   142,   143,   144,    13,
+      25,    31,    32,   149,    28,   151,    14,    31,    32,    32,
+      30,    67,    68,    30,    70,   161,    67,    68,    30,    70,
+      30,    31,    32,    30,    31,    32,    30,    31,    32,    30,
+      31,    32,    30,    30,    30,    30,    30,    30,    30,    29,
+      40,    59,    -1,   106,    66
 };
 
 /* YYSTOS[STATE-NUM] -- The (internal number of the) accessing
    symbol of state STATE-NUM.  */
 static const unsigned char yystos[] =
 {
-       0,    43,     0,     1,     3,     4,     5,     6,     7,     8,
-       9,    10,    11,    14,    15,    31,    32,    44,    45,    46,
-      47,    48,    49,    52,    53,    55,    59,    61,    63,    64,
-      66,    68,    69,    70,    71,    79,    79,    28,    29,    77,
-      77,    77,    32,    77,    28,    28,    28,    29,    34,    41,
-      81,    82,    50,    50,    56,    58,    62,    74,    67,    74,
-      79,    32,    32,    32,    32,    32,    81,    81,    32,    38,
-      39,    30,    40,    12,    16,    17,    19,    20,    21,    22,
-      23,    24,    25,    26,    27,    32,    36,    37,    51,    72,
-      73,    75,    18,    19,    20,    21,    23,    32,    57,    73,
-      75,     5,     8,    15,    45,    54,    78,    45,    55,    60,
-      66,    78,    32,    75,     1,    45,    55,    65,    66,    78,
-      33,    81,    81,    82,    82,    32,    35,    81,    81,    77,
-      81,    76,    77,    81,    76,    81,    76,    76,    76,    28,
-      82,    13,    32,    77,    28,    76,    76,    79,    79,    79,
-      32,    81,    32,    32,    14,    80,    80,    32,    80,    80,
-      32,    80,    32,    32,    32,    80,    82,    80,    80,    32,
-      32,    32,    81,    32,    32,    32,    32,    32,    80,    32,
-      32,    32
+       0,    36,    37,     0,     1,     3,     4,     5,     6,     7,
+       8,     9,    10,    11,    14,    15,    16,    18,    19,    20,
+      21,    22,    23,    25,    30,    38,    39,    41,    42,    43,
+      44,    47,    48,    50,    54,    56,    58,    59,    61,    63,
+      64,    65,    72,    30,    25,    26,    71,    71,    30,    71,
+      30,    30,    71,    25,    25,    25,    26,    29,    34,    75,
+      76,    30,     1,     1,    45,    45,    51,    53,    57,    68,
+      62,    68,    30,    73,    30,    30,    30,    30,    30,    75,
+      75,    31,    32,    73,    27,    33,    30,    30,     1,    12,
+      16,    17,    19,    20,    21,    22,    23,    25,    30,    40,
+      46,    66,    67,    69,    18,    19,    20,    21,    30,    40,
+      52,    67,    69,    39,    49,    72,    39,    50,    55,    61,
+      72,    30,    40,    69,    39,    50,    60,    61,    72,    30,
+      28,    75,    75,    76,    76,    30,    30,    24,    75,    75,
+      71,    70,    71,    75,    25,    76,     1,    13,    30,    71,
+      70,    25,    75,    30,    30,    14,    74,    30,    74,    74,
+      74,    76,    30,    74,    30,    74,    30,    75,    30,    30,
+      30,    74,    30,    30,    30
 };
 
 #if ! defined (YYSIZE_T) && defined (__SIZE_TYPE__)
@@ -687,7 +687,7 @@ static const unsigned char yystos[] =
 
 #define YYACCEPT       goto yyacceptlab
 #define YYABORT                goto yyabortlab
-#define YYERROR                goto yyerrlab1
+#define YYERROR                goto yyerrorlab
 
 
 /* Like YYERROR except do call yyerror.  This remains here temporarily
@@ -715,20 +715,53 @@ do                                                                \
     }                                                          \
 while (0)
 
+
 #define YYTERROR       1
 #define YYERRCODE      256
 
-/* YYLLOC_DEFAULT -- Compute the default location (before the actions
-   are run).  */
 
+/* YYLLOC_DEFAULT -- Set CURRENT to span from RHS[1] to RHS[N].
+   If N is 0, then set CURRENT to the empty location which ends
+   the previous symbol: RHS[0] (always defined).  */
+
+#define YYRHSLOC(Rhs, K) ((Rhs)[K])
 #ifndef YYLLOC_DEFAULT
-# define YYLLOC_DEFAULT(Current, Rhs, N)         \
-  Current.first_line   = Rhs[1].first_line;      \
-  Current.first_column = Rhs[1].first_column;    \
-  Current.last_line    = Rhs[N].last_line;       \
-  Current.last_column  = Rhs[N].last_column;
+# define YYLLOC_DEFAULT(Current, Rhs, N)                               \
+    do                                                                 \
+      if (N)                                                           \
+       {                                                               \
+         (Current).first_line   = YYRHSLOC (Rhs, 1).first_line;        \
+         (Current).first_column = YYRHSLOC (Rhs, 1).first_column;      \
+         (Current).last_line    = YYRHSLOC (Rhs, N).last_line;         \
+         (Current).last_column  = YYRHSLOC (Rhs, N).last_column;       \
+       }                                                               \
+      else                                                             \
+       {                                                               \
+         (Current).first_line   = (Current).last_line   =              \
+           YYRHSLOC (Rhs, 0).last_line;                                \
+         (Current).first_column = (Current).last_column =              \
+           YYRHSLOC (Rhs, 0).last_column;                              \
+       }                                                               \
+    while (0)
+#endif
+
+
+/* YY_LOCATION_PRINT -- Print the location on the stream.
+   This macro was not mandated originally: define only if we know
+   we won't break user code: when these are the locations we know.  */
+
+#ifndef YY_LOCATION_PRINT
+# if YYLTYPE_IS_TRIVIAL
+#  define YY_LOCATION_PRINT(File, Loc)                 \
+     fprintf (File, "%d.%d-%d.%d",                     \
+              (Loc).first_line, (Loc).first_column,    \
+              (Loc).last_line,  (Loc).last_column)
+# else
+#  define YY_LOCATION_PRINT(File, Loc) ((void) 0)
+# endif
 #endif
 
+
 /* YYLEX -- calling `yylex' with the right arguments.  */
 
 #ifdef YYLEX_PARAM
@@ -751,36 +784,30 @@ do {                                              \
     YYFPRINTF Args;                            \
 } while (0)
 
-# define YYDSYMPRINT(Args)                     \
-do {                                           \
-  if (yydebug)                                 \
-    yysymprint Args;                           \
-} while (0)
-
-# define YYDSYMPRINTF(Title, Token, Value, Location)           \
+# define YY_SYMBOL_PRINT(Title, Type, Value, Location)         \
 do {                                                           \
   if (yydebug)                                                 \
     {                                                          \
       YYFPRINTF (stderr, "%s ", Title);                                \
       yysymprint (stderr,                                      \
-                  Token, Value);       \
+                  Type, Value);        \
       YYFPRINTF (stderr, "\n");                                        \
     }                                                          \
 } while (0)
 
 /*------------------------------------------------------------------.
 | yy_stack_print -- Print the state stack from its BOTTOM up to its |
-| TOP (cinluded).                                                   |
+| TOP (included).                                                   |
 `------------------------------------------------------------------*/
 
 #if defined (__STDC__) || defined (__cplusplus)
 static void
-yy_stack_print (short *bottom, short *top)
+yy_stack_print (short int *bottom, short int *top)
 #else
 static void
 yy_stack_print (bottom, top)
-    short *bottom;
-    short *top;
+    short int *bottom;
+    short int *top;
 #endif
 {
   YYFPRINTF (stderr, "Stack now");
@@ -810,9 +837,9 @@ yy_reduce_print (yyrule)
 #endif
 {
   int yyi;
-  unsigned int yylineno = yyrline[yyrule];
+  unsigned int yylno = yyrline[yyrule];
   YYFPRINTF (stderr, "Reducing stack by rule %d (line %u), ",
-             yyrule - 1, yylineno);
+             yyrule - 1, yylno);
   /* Print the symbols being reduced, and their result.  */
   for (yyi = yyprhs[yyrule]; 0 <= yyrhs[yyi]; yyi++)
     YYFPRINTF (stderr, "%s ", yytname [yyrhs[yyi]]);
@@ -830,8 +857,7 @@ do {                                        \
 int yydebug;
 #else /* !YYDEBUG */
 # define YYDPRINTF(Args)
-# define YYDSYMPRINT(Args)
-# define YYDSYMPRINTF(Title, Token, Value, Location)
+# define YY_SYMBOL_PRINT(Title, Type, Value, Location)
 # define YY_STACK_PRINT(Bottom, Top)
 # define YY_REDUCE_PRINT(Rule)
 #endif /* !YYDEBUG */
@@ -849,10 +875,6 @@ int yydebug;
    SIZE_MAX < YYSTACK_BYTES (YYMAXDEPTH)
    evaluated with infinite-precision integer arithmetic.  */
 
-#if YYMAXDEPTH == 0
-# undef YYMAXDEPTH
-#endif
-
 #ifndef YYMAXDEPTH
 # define YYMAXDEPTH 10000
 #endif
@@ -934,15 +956,15 @@ yysymprint (yyoutput, yytype, yyvaluep)
   (void) yyvaluep;
 
   if (yytype < YYNTOKENS)
-    {
-      YYFPRINTF (yyoutput, "token %s (", yytname[yytype]);
-# ifdef YYPRINT
-      YYPRINT (yyoutput, yytoknum[yytype], *yyvaluep);
-# endif
-    }
+    YYFPRINTF (yyoutput, "token %s (", yytname[yytype]);
   else
     YYFPRINTF (yyoutput, "nterm %s (", yytname[yytype]);
 
+
+# ifdef YYPRINT
+  if (yytype < YYNTOKENS)
+    YYPRINT (yyoutput, yytoknum[yytype], *yyvaluep);
+# endif
   switch (yytype)
     {
       default:
@@ -958,10 +980,11 @@ yysymprint (yyoutput, yytype, yyvaluep)
 
 #if defined (__STDC__) || defined (__cplusplus)
 static void
-yydestruct (int yytype, YYSTYPE *yyvaluep)
+yydestruct (const char *yymsg, int yytype, YYSTYPE *yyvaluep)
 #else
 static void
-yydestruct (yytype, yyvaluep)
+yydestruct (yymsg, yytype, yyvaluep)
+    const char *yymsg;
     int yytype;
     YYSTYPE *yyvaluep;
 #endif
@@ -969,8 +992,42 @@ yydestruct (yytype, yyvaluep)
   /* Pacify ``unused variable'' warnings.  */
   (void) yyvaluep;
 
+  if (!yymsg)
+    yymsg = "Deleting";
+  YY_SYMBOL_PRINT (yymsg, yytype, yyvaluep, yylocationp);
+
   switch (yytype)
     {
+      case 48: /* choice_entry */
+
+        {
+       fprintf(stderr, "%s:%d: missing end statement for this entry\n",
+               (yyvaluep->menu)->file->name, (yyvaluep->menu)->lineno);
+       if (current_menu == (yyvaluep->menu))
+               menu_end_menu();
+};
+
+        break;
+      case 54: /* if_entry */
+
+        {
+       fprintf(stderr, "%s:%d: missing end statement for this entry\n",
+               (yyvaluep->menu)->file->name, (yyvaluep->menu)->lineno);
+       if (current_menu == (yyvaluep->menu))
+               menu_end_menu();
+};
+
+        break;
+      case 59: /* menu_entry */
+
+        {
+       fprintf(stderr, "%s:%d: missing end statement for this entry\n",
+               (yyvaluep->menu)->file->name, (yyvaluep->menu)->lineno);
+       if (current_menu == (yyvaluep->menu))
+               menu_end_menu();
+};
+
+        break;
 
       default:
         break;
@@ -996,10 +1053,10 @@ int yyparse ();
 
 
 
-/* The lookahead symbol.  */
+/* The look-ahead symbol.  */
 int yychar;
 
-/* The semantic value of the lookahead symbol.  */
+/* The semantic value of the look-ahead symbol.  */
 YYSTYPE yylval;
 
 /* Number of syntax errors so far.  */
@@ -1035,7 +1092,7 @@ yyparse ()
   int yyresult;
   /* Number of tokens to shift before error messages enabled.  */
   int yyerrstatus;
-  /* Lookahead token as an internal (translated) token number.  */
+  /* Look-ahead token as an internal (translated) token number.  */
   int yytoken = 0;
 
   /* Three stacks and their tools:
@@ -1047,9 +1104,9 @@ yyparse ()
      to reallocate them elsewhere.  */
 
   /* The state stack.  */
-  short        yyssa[YYINITDEPTH];
-  short *yyss = yyssa;
-  register short *yyssp;
+  short int yyssa[YYINITDEPTH];
+  short int *yyss = yyssa;
+  register short int *yyssp;
 
   /* The semantic value stack.  */
   YYSTYPE yyvsa[YYINITDEPTH];
@@ -1086,6 +1143,9 @@ yyparse ()
   yyssp = yyss;
   yyvsp = yyvs;
 
+
+  yyvsp[0] = yylval;
+
   goto yysetstate;
 
 /*------------------------------------------------------------.
@@ -1111,7 +1171,7 @@ yyparse ()
           these so that the &'s don't force the real ones into
           memory.  */
        YYSTYPE *yyvs1 = yyvs;
-       short *yyss1 = yyss;
+       short int *yyss1 = yyss;
 
 
        /* Each stack pointer address is followed by the size of the
@@ -1139,7 +1199,7 @@ yyparse ()
        yystacksize = YYMAXDEPTH;
 
       {
-       short *yyss1 = yyss;
+       short int *yyss1 = yyss;
        union yyalloc *yyptr =
          (union yyalloc *) YYSTACK_ALLOC (YYSTACK_BYTES (yystacksize));
        if (! yyptr)
@@ -1175,18 +1235,18 @@ yyparse ()
 yybackup:
 
 /* Do appropriate processing given the current state.  */
-/* Read a lookahead token if we need one and don't already have one.  */
+/* Read a look-ahead token if we need one and don't already have one.  */
 /* yyresume: */
 
-  /* First try to decide what to do without reference to lookahead token.  */
+  /* First try to decide what to do without reference to look-ahead token.  */
 
   yyn = yypact[yystate];
   if (yyn == YYPACT_NINF)
     goto yydefault;
 
-  /* Not known => get a lookahead token if don't already have one.  */
+  /* Not known => get a look-ahead token if don't already have one.  */
 
-  /* YYCHAR is either YYEMPTY or YYEOF or a valid lookahead symbol.  */
+  /* YYCHAR is either YYEMPTY or YYEOF or a valid look-ahead symbol.  */
   if (yychar == YYEMPTY)
     {
       YYDPRINTF ((stderr, "Reading a token: "));
@@ -1201,7 +1261,7 @@ yybackup:
   else
     {
       yytoken = YYTRANSLATE (yychar);
-      YYDSYMPRINTF ("Next token is", yytoken, &yylval, &yylloc);
+      YY_SYMBOL_PRINT ("Next token is", yytoken, &yylval, &yylloc);
     }
 
   /* If the proper action on seeing token YYTOKEN is to reduce or to
@@ -1221,8 +1281,8 @@ yybackup:
   if (yyn == YYFINAL)
     YYACCEPT;
 
-  /* Shift the lookahead token.  */
-  YYDPRINTF ((stderr, "Shifting token %s, ", yytname[yytoken]));
+  /* Shift the look-ahead token.  */
+  YY_SYMBOL_PRINT ("Shifting", yytoken, &yylval, &yylloc);
 
   /* Discard the token being shifted unless it is eof.  */
   if (yychar != YYEOF)
@@ -1273,155 +1333,123 @@ yyreduce:
     {
         case 8:
 
-    { zconfprint("unexpected 'endmenu' statement"); ;}
+    { zconf_error("unexpected end statement"); ;}
     break;
 
   case 9:
 
-    { zconfprint("unexpected 'endif' statement"); ;}
+    { zconf_error("unknown statement \"%s\"", (yyvsp[-2].string)); ;}
     break;
 
   case 10:
 
-    { zconfprint("unexpected 'endchoice' statement"); ;}
+    {
+       zconf_error("unexpected option \"%s\"", kconf_id_strings + (yyvsp[-2].id)->name);
+;}
     break;
 
   case 11:
 
-    { zconfprint("syntax error"); yyerrok; ;}
+    { zconf_error("invalid statement"); ;}
     break;
 
-  case 18:
+  case 25:
 
-    {
-       struct symbol *sym = sym_lookup(yyvsp[-1].string, 0);
-       sym->flags |= SYMBOL_OPTIONAL;
-       menu_add_entry(sym);
-       printd(DEBUG_PARSE, "%s:%d:config %s\n", zconf_curname(), zconf_lineno(), yyvsp[-1].string);
-;}
+    { zconf_error("unknown option \"%s\"", (yyvsp[-2].string)); ;}
     break;
 
-  case 19:
+  case 26:
 
-    {
-       menu_end_entry();
-       printd(DEBUG_PARSE, "%s:%d:endconfig\n", zconf_curname(), zconf_lineno());
-;}
+    { zconf_error("invalid option"); ;}
     break;
 
-  case 20:
+  case 27:
 
     {
-       struct symbol *sym = sym_lookup(yyvsp[-1].string, 0);
+       struct symbol *sym = sym_lookup((yyvsp[-1].string), 0);
        sym->flags |= SYMBOL_OPTIONAL;
        menu_add_entry(sym);
-       printd(DEBUG_PARSE, "%s:%d:menuconfig %s\n", zconf_curname(), zconf_lineno(), yyvsp[-1].string);
+       printd(DEBUG_PARSE, "%s:%d:config %s\n", zconf_curname(), zconf_lineno(), (yyvsp[-1].string));
 ;}
     break;
 
-  case 21:
+  case 28:
 
     {
-       if (current_entry->prompt)
-               current_entry->prompt->type = P_MENU;
-       else
-               zconfprint("warning: menuconfig statement without prompt");
        menu_end_entry();
        printd(DEBUG_PARSE, "%s:%d:endconfig\n", zconf_curname(), zconf_lineno());
 ;}
     break;
 
-  case 27:
-
-    {
-       menu_set_type(S_TRISTATE);
-       printd(DEBUG_PARSE, "%s:%d:tristate\n", zconf_curname(), zconf_lineno());
-;}
-    break;
-
-  case 28:
-
-    {
-       menu_add_expr(P_DEFAULT, yyvsp[-2].expr, yyvsp[-1].expr);
-       menu_set_type(S_TRISTATE);
-       printd(DEBUG_PARSE, "%s:%d:def_boolean\n", zconf_curname(), zconf_lineno());
-;}
-    break;
-
   case 29:
 
     {
-       menu_set_type(S_BOOLEAN);
-       printd(DEBUG_PARSE, "%s:%d:boolean\n", zconf_curname(), zconf_lineno());
+       struct symbol *sym = sym_lookup((yyvsp[-1].string), 0);
+       sym->flags |= SYMBOL_OPTIONAL;
+       menu_add_entry(sym);
+       printd(DEBUG_PARSE, "%s:%d:menuconfig %s\n", zconf_curname(), zconf_lineno(), (yyvsp[-1].string));
 ;}
     break;
 
   case 30:
 
     {
-       menu_add_expr(P_DEFAULT, yyvsp[-2].expr, yyvsp[-1].expr);
-       menu_set_type(S_BOOLEAN);
-       printd(DEBUG_PARSE, "%s:%d:def_boolean\n", zconf_curname(), zconf_lineno());
-;}
-    break;
-
-  case 31:
-
-    {
-       menu_set_type(S_INT);
-       printd(DEBUG_PARSE, "%s:%d:int\n", zconf_curname(), zconf_lineno());
-;}
-    break;
-
-  case 32:
-
-    {
-       menu_set_type(S_HEX);
-       printd(DEBUG_PARSE, "%s:%d:hex\n", zconf_curname(), zconf_lineno());
+       if (current_entry->prompt)
+               current_entry->prompt->type = P_MENU;
+       else
+               zconfprint("warning: menuconfig statement without prompt");
+       menu_end_entry();
+       printd(DEBUG_PARSE, "%s:%d:endconfig\n", zconf_curname(), zconf_lineno());
 ;}
     break;
 
-  case 33:
+  case 37:
 
     {
-       menu_set_type(S_STRING);
-       printd(DEBUG_PARSE, "%s:%d:string\n", zconf_curname(), zconf_lineno());
+       menu_set_type((yyvsp[-2].id)->stype);
+       printd(DEBUG_PARSE, "%s:%d:type(%u)\n",
+               zconf_curname(), zconf_lineno(),
+               (yyvsp[-2].id)->stype);
 ;}
     break;
 
-  case 34:
+  case 38:
 
     {
-       menu_add_prompt(P_PROMPT, yyvsp[-2].string, yyvsp[-1].expr);
+       menu_add_prompt(P_PROMPT, (yyvsp[-2].string), (yyvsp[-1].expr));
        printd(DEBUG_PARSE, "%s:%d:prompt\n", zconf_curname(), zconf_lineno());
 ;}
     break;
 
-  case 35:
+  case 39:
 
     {
-       menu_add_expr(P_DEFAULT, yyvsp[-2].expr, yyvsp[-1].expr);
-       printd(DEBUG_PARSE, "%s:%d:default\n", zconf_curname(), zconf_lineno());
+       menu_add_expr(P_DEFAULT, (yyvsp[-2].expr), (yyvsp[-1].expr));
+       if ((yyvsp[-3].id)->stype != S_UNKNOWN)
+               menu_set_type((yyvsp[-3].id)->stype);
+       printd(DEBUG_PARSE, "%s:%d:default(%u)\n",
+               zconf_curname(), zconf_lineno(),
+               (yyvsp[-3].id)->stype);
 ;}
     break;
 
-  case 36:
+  case 40:
 
     {
-       menu_add_symbol(P_SELECT, sym_lookup(yyvsp[-2].string, 0), yyvsp[-1].expr);
+       menu_add_symbol(P_SELECT, sym_lookup((yyvsp[-2].string), 0), (yyvsp[-1].expr));
        printd(DEBUG_PARSE, "%s:%d:select\n", zconf_curname(), zconf_lineno());
 ;}
     break;
 
-  case 37:
+  case 41:
 
     {
-       menu_add_expr(P_RANGE, expr_alloc_comp(E_RANGE,yyvsp[-3].symbol, yyvsp[-2].symbol), yyvsp[-1].expr);
+       menu_add_expr(P_RANGE, expr_alloc_comp(E_RANGE,(yyvsp[-3].symbol), (yyvsp[-2].symbol)), (yyvsp[-1].expr));
        printd(DEBUG_PARSE, "%s:%d:range\n", zconf_curname(), zconf_lineno());
 ;}
     break;
 
-  case 38:
+  case 42:
 
     {
        struct symbol *sym = sym_lookup(NULL, 0);
@@ -1432,57 +1460,45 @@ yyreduce:
 ;}
     break;
 
-  case 39:
+  case 43:
 
     {
-       menu_end_entry();
-       menu_add_menu();
+       (yyval.menu) = menu_add_menu();
 ;}
     break;
 
-  case 40:
+  case 44:
 
     {
-       if (zconf_endtoken(yyvsp[0].token, T_CHOICE, T_ENDCHOICE)) {
+       if (zconf_endtoken((yyvsp[0].id), T_CHOICE, T_ENDCHOICE)) {
                menu_end_menu();
                printd(DEBUG_PARSE, "%s:%d:endchoice\n", zconf_curname(), zconf_lineno());
        }
 ;}
     break;
 
-  case 42:
-
-    {
-       printf("%s:%d: missing 'endchoice' for this 'choice' statement\n", current_menu->file->name, current_menu->lineno);
-       zconfnerrs++;
-;}
-    break;
-
-  case 48:
+  case 52:
 
     {
-       menu_add_prompt(P_PROMPT, yyvsp[-2].string, yyvsp[-1].expr);
+       menu_add_prompt(P_PROMPT, (yyvsp[-2].string), (yyvsp[-1].expr));
        printd(DEBUG_PARSE, "%s:%d:prompt\n", zconf_curname(), zconf_lineno());
 ;}
     break;
 
-  case 49:
+  case 53:
 
     {
-       menu_set_type(S_TRISTATE);
-       printd(DEBUG_PARSE, "%s:%d:tristate\n", zconf_curname(), zconf_lineno());
+       if ((yyvsp[-2].id)->stype == S_BOOLEAN || (yyvsp[-2].id)->stype == S_TRISTATE) {
+               menu_set_type((yyvsp[-2].id)->stype);
+               printd(DEBUG_PARSE, "%s:%d:type(%u)\n",
+                       zconf_curname(), zconf_lineno(),
+                       (yyvsp[-2].id)->stype);
+       } else
+               YYERROR;
 ;}
     break;
 
-  case 50:
-
-    {
-       menu_set_type(S_BOOLEAN);
-       printd(DEBUG_PARSE, "%s:%d:boolean\n", zconf_curname(), zconf_lineno());
-;}
-    break;
-
-  case 51:
+  case 54:
 
     {
        current_entry->sym->flags |= SYMBOL_OPTIONAL;
@@ -1490,115 +1506,89 @@ yyreduce:
 ;}
     break;
 
-  case 52:
+  case 55:
 
     {
-       menu_add_symbol(P_DEFAULT, sym_lookup(yyvsp[-2].string, 0), yyvsp[-1].expr);
-       printd(DEBUG_PARSE, "%s:%d:default\n", zconf_curname(), zconf_lineno());
+       if ((yyvsp[-3].id)->stype == S_UNKNOWN) {
+               menu_add_symbol(P_DEFAULT, sym_lookup((yyvsp[-2].string), 0), (yyvsp[-1].expr));
+               printd(DEBUG_PARSE, "%s:%d:default\n",
+                       zconf_curname(), zconf_lineno());
+       } else
+               YYERROR;
 ;}
     break;
 
-  case 55:
+  case 58:
 
     {
        printd(DEBUG_PARSE, "%s:%d:if\n", zconf_curname(), zconf_lineno());
        menu_add_entry(NULL);
-       menu_add_dep(yyvsp[-1].expr);
-       menu_end_entry();
-       menu_add_menu();
+       menu_add_dep((yyvsp[-1].expr));
+       (yyval.menu) = menu_add_menu();
 ;}
     break;
 
-  case 56:
+  case 59:
 
     {
-       if (zconf_endtoken(yyvsp[0].token, T_IF, T_ENDIF)) {
+       if (zconf_endtoken((yyvsp[0].id), T_IF, T_ENDIF)) {
                menu_end_menu();
                printd(DEBUG_PARSE, "%s:%d:endif\n", zconf_curname(), zconf_lineno());
        }
 ;}
     break;
 
-  case 58:
-
-    {
-       printf("%s:%d: missing 'endif' for this 'if' statement\n", current_menu->file->name, current_menu->lineno);
-       zconfnerrs++;
-;}
-    break;
-
-  case 63:
+  case 65:
 
     {
        menu_add_entry(NULL);
-       menu_add_prompt(P_MENU, yyvsp[-1].string, NULL);
+       menu_add_prompt(P_MENU, (yyvsp[-1].string), NULL);
        printd(DEBUG_PARSE, "%s:%d:menu\n", zconf_curname(), zconf_lineno());
 ;}
     break;
 
-  case 64:
+  case 66:
 
     {
-       menu_end_entry();
-       menu_add_menu();
+       (yyval.menu) = menu_add_menu();
 ;}
     break;
 
-  case 65:
+  case 67:
 
     {
-       if (zconf_endtoken(yyvsp[0].token, T_MENU, T_ENDMENU)) {
+       if (zconf_endtoken((yyvsp[0].id), T_MENU, T_ENDMENU)) {
                menu_end_menu();
                printd(DEBUG_PARSE, "%s:%d:endmenu\n", zconf_curname(), zconf_lineno());
        }
 ;}
     break;
 
-  case 67:
-
-    {
-       printf("%s:%d: missing 'endmenu' for this 'menu' statement\n", current_menu->file->name, current_menu->lineno);
-       zconfnerrs++;
-;}
-    break;
-
-  case 72:
-
-    { zconfprint("invalid menu option"); yyerrok; ;}
-    break;
-
   case 73:
 
     {
-       yyval.string = yyvsp[-1].string;
-       printd(DEBUG_PARSE, "%s:%d:source %s\n", zconf_curname(), zconf_lineno(), yyvsp[-1].string);
+       printd(DEBUG_PARSE, "%s:%d:source %s\n", zconf_curname(), zconf_lineno(), (yyvsp[-1].string));
+       zconf_nextfile((yyvsp[-1].string));
 ;}
     break;
 
   case 74:
 
-    {
-       zconf_nextfile(yyvsp[0].string);
-;}
-    break;
-
-  case 75:
-
     {
        menu_add_entry(NULL);
-       menu_add_prompt(P_COMMENT, yyvsp[-1].string, NULL);
+       menu_add_prompt(P_COMMENT, (yyvsp[-1].string), NULL);
        printd(DEBUG_PARSE, "%s:%d:comment\n", zconf_curname(), zconf_lineno());
 ;}
     break;
 
-  case 76:
+  case 75:
 
     {
        menu_end_entry();
 ;}
     break;
 
-  case 77:
+  case 76:
 
     {
        printd(DEBUG_PARSE, "%s:%d:help\n", zconf_curname(), zconf_lineno());
@@ -1606,17 +1596,17 @@ yyreduce:
 ;}
     break;
 
-  case 78:
+  case 77:
 
     {
-       current_entry->sym->help = yyvsp[0].string;
+       current_entry->sym->help = (yyvsp[0].string);
 ;}
     break;
 
   case 82:
 
     {
-       menu_add_dep(yyvsp[-1].expr);
+       menu_add_dep((yyvsp[-1].expr));
        printd(DEBUG_PARSE, "%s:%d:depends on\n", zconf_curname(), zconf_lineno());
 ;}
     break;
@@ -1624,7 +1614,7 @@ yyreduce:
   case 83:
 
     {
-       menu_add_dep(yyvsp[-1].expr);
+       menu_add_dep((yyvsp[-1].expr));
        printd(DEBUG_PARSE, "%s:%d:depends\n", zconf_curname(), zconf_lineno());
 ;}
     break;
@@ -1632,7 +1622,7 @@ yyreduce:
   case 84:
 
     {
-       menu_add_dep(yyvsp[-1].expr);
+       menu_add_dep((yyvsp[-1].expr));
        printd(DEBUG_PARSE, "%s:%d:requires\n", zconf_curname(), zconf_lineno());
 ;}
     break;
@@ -1640,84 +1630,84 @@ yyreduce:
   case 86:
 
     {
-       menu_add_prompt(P_PROMPT, yyvsp[-1].string, yyvsp[0].expr);
+       menu_add_prompt(P_PROMPT, (yyvsp[-1].string), (yyvsp[0].expr));
 ;}
     break;
 
   case 89:
 
-    { yyval.token = T_ENDMENU; ;}
+    { (yyval.id) = (yyvsp[-1].id); ;}
     break;
 
   case 90:
 
-    { yyval.token = T_ENDCHOICE; ;}
+    { (yyval.id) = (yyvsp[-1].id); ;}
     break;
 
   case 91:
 
-    { yyval.token = T_ENDIF; ;}
+    { (yyval.id) = (yyvsp[-1].id); ;}
     break;
 
   case 94:
 
-    { yyval.expr = NULL; ;}
+    { (yyval.expr) = NULL; ;}
     break;
 
   case 95:
 
-    { yyval.expr = yyvsp[0].expr; ;}
+    { (yyval.expr) = (yyvsp[0].expr); ;}
     break;
 
   case 96:
 
-    { yyval.expr = expr_alloc_symbol(yyvsp[0].symbol); ;}
+    { (yyval.expr) = expr_alloc_symbol((yyvsp[0].symbol)); ;}
     break;
 
   case 97:
 
-    { yyval.expr = expr_alloc_comp(E_EQUAL, yyvsp[-2].symbol, yyvsp[0].symbol); ;}
+    { (yyval.expr) = expr_alloc_comp(E_EQUAL, (yyvsp[-2].symbol), (yyvsp[0].symbol)); ;}
     break;
 
   case 98:
 
-    { yyval.expr = expr_alloc_comp(E_UNEQUAL, yyvsp[-2].symbol, yyvsp[0].symbol); ;}
+    { (yyval.expr) = expr_alloc_comp(E_UNEQUAL, (yyvsp[-2].symbol), (yyvsp[0].symbol)); ;}
     break;
 
   case 99:
 
-    { yyval.expr = yyvsp[-1].expr; ;}
+    { (yyval.expr) = (yyvsp[-1].expr); ;}
     break;
 
   case 100:
 
-    { yyval.expr = expr_alloc_one(E_NOT, yyvsp[0].expr); ;}
+    { (yyval.expr) = expr_alloc_one(E_NOT, (yyvsp[0].expr)); ;}
     break;
 
   case 101:
 
-    { yyval.expr = expr_alloc_two(E_OR, yyvsp[-2].expr, yyvsp[0].expr); ;}
+    { (yyval.expr) = expr_alloc_two(E_OR, (yyvsp[-2].expr), (yyvsp[0].expr)); ;}
     break;
 
   case 102:
 
-    { yyval.expr = expr_alloc_two(E_AND, yyvsp[-2].expr, yyvsp[0].expr); ;}
+    { (yyval.expr) = expr_alloc_two(E_AND, (yyvsp[-2].expr), (yyvsp[0].expr)); ;}
     break;
 
   case 103:
 
-    { yyval.symbol = sym_lookup(yyvsp[0].string, 0); free(yyvsp[0].string); ;}
+    { (yyval.symbol) = sym_lookup((yyvsp[0].string), 0); free((yyvsp[0].string)); ;}
     break;
 
   case 104:
 
-    { yyval.symbol = sym_lookup(yyvsp[0].string, 1); free(yyvsp[0].string); ;}
+    { (yyval.symbol) = sym_lookup((yyvsp[0].string), 1); free((yyvsp[0].string)); ;}
     break;
 
 
     }
 
-/* Line 999 of yacc.c.  */
+/* Line 1037 of yacc.c.  */
 
 \f
   yyvsp -= yylen;
@@ -1759,18 +1749,33 @@ yyerrlab:
        {
          YYSIZE_T yysize = 0;
          int yytype = YYTRANSLATE (yychar);
+         const char* yyprefix;
          char *yymsg;
-         int yyx, yycount;
+         int yyx;
 
-         yycount = 0;
          /* Start YYX at -YYN if negative to avoid negative indexes in
             YYCHECK.  */
-         for (yyx = yyn < 0 ? -yyn : 0;
-              yyx < (int) (sizeof (yytname) / sizeof (char *)); yyx++)
+         int yyxbegin = yyn < 0 ? -yyn : 0;
+
+         /* Stay within bounds of both yycheck and yytname.  */
+         int yychecklim = YYLAST - yyn;
+         int yyxend = yychecklim < YYNTOKENS ? yychecklim : YYNTOKENS;
+         int yycount = 0;
+
+         yyprefix = ", expecting ";
+         for (yyx = yyxbegin; yyx < yyxend; ++yyx)
            if (yycheck[yyx + yyn] == yyx && yyx != YYTERROR)
-             yysize += yystrlen (yytname[yyx]) + 15, yycount++;
-         yysize += yystrlen ("syntax error, unexpected ") + 1;
-         yysize += yystrlen (yytname[yytype]);
+             {
+               yysize += yystrlen (yyprefix) + yystrlen (yytname [yyx]);
+               yycount += 1;
+               if (yycount == 5)
+                 {
+                   yysize = 0;
+                   break;
+                 }
+             }
+         yysize += (sizeof ("syntax error, unexpected ")
+                    + yystrlen (yytname[yytype]));
          yymsg = (char *) YYSTACK_ALLOC (yysize);
          if (yymsg != 0)
            {
@@ -1779,16 +1784,13 @@ yyerrlab:
 
              if (yycount < 5)
                {
-                 yycount = 0;
-                 for (yyx = yyn < 0 ? -yyn : 0;
-                      yyx < (int) (sizeof (yytname) / sizeof (char *));
-                      yyx++)
+                 yyprefix = ", expecting ";
+                 for (yyx = yyxbegin; yyx < yyxend; ++yyx)
                    if (yycheck[yyx + yyn] == yyx && yyx != YYTERROR)
                      {
-                       const char *yyq = ! yycount ? ", expecting " : " or ";
-                       yyp = yystpcpy (yyp, yyq);
+                       yyp = yystpcpy (yyp, yyprefix);
                        yyp = yystpcpy (yyp, yytname[yyx]);
-                       yycount++;
+                       yyprefix = " or ";
                      }
                }
              yyerror (yymsg);
@@ -1806,38 +1808,57 @@ yyerrlab:
 
   if (yyerrstatus == 3)
     {
-      /* If just tried and failed to reuse lookahead token after an
+      /* If just tried and failed to reuse look-ahead token after an
         error, discard it.  */
 
-      /* Return failure if at end of input.  */
-      if (yychar == YYEOF)
+      if (yychar <= YYEOF)
         {
-         /* Pop the error token.  */
-          YYPOPSTACK;
-         /* Pop the rest of the stack.  */
-         while (yyss < yyssp)
-           {
-             YYDSYMPRINTF ("Error: popping", yystos[*yyssp], yyvsp, yylsp);
-             yydestruct (yystos[*yyssp], yyvsp);
-             YYPOPSTACK;
-           }
-         YYABORT;
+          /* If at end of input, pop the error token,
+            then the rest of the stack, then return failure.  */
+         if (yychar == YYEOF)
+            for (;;)
+              {
+
+                YYPOPSTACK;
+                if (yyssp == yyss)
+                  YYABORT;
+                yydestruct ("Error: popping",
+                             yystos[*yyssp], yyvsp);
+              }
         }
-
-      YYDSYMPRINTF ("Error: discarding", yytoken, &yylval, &yylloc);
-      yydestruct (yytoken, &yylval);
-      yychar = YYEMPTY;
-
+      else
+       {
+         yydestruct ("Error: discarding", yytoken, &yylval);
+         yychar = YYEMPTY;
+       }
     }
 
-  /* Else will try to reuse lookahead token after shifting the error
+  /* Else will try to reuse look-ahead token after shifting the error
      token.  */
   goto yyerrlab1;
 
 
-/*----------------------------------------------------.
-| yyerrlab1 -- error raised explicitly by an action.  |
-`----------------------------------------------------*/
+/*---------------------------------------------------.
+| yyerrorlab -- error raised explicitly by YYERROR.  |
+`---------------------------------------------------*/
+yyerrorlab:
+
+#ifdef __GNUC__
+  /* Pacify GCC when the user code never invokes YYERROR and the label
+     yyerrorlab therefore never appears in user code.  */
+  if (0)
+     goto yyerrorlab;
+#endif
+
+yyvsp -= yylen;
+  yyssp -= yylen;
+  yystate = *yyssp;
+  goto yyerrlab1;
+
+
+/*-------------------------------------------------------------.
+| yyerrlab1 -- common code for both syntax error and YYERROR.  |
+`-------------------------------------------------------------*/
 yyerrlab1:
   yyerrstatus = 3;     /* Each real token shifted decrements this.  */
 
@@ -1859,22 +1880,22 @@ yyerrlab1:
       if (yyssp == yyss)
        YYABORT;
 
-      YYDSYMPRINTF ("Error: popping", yystos[*yyssp], yyvsp, yylsp);
-      yydestruct (yystos[yystate], yyvsp);
-      yyvsp--;
-      yystate = *--yyssp;
 
+      yydestruct ("Error: popping", yystos[yystate], yyvsp);
+      YYPOPSTACK;
+      yystate = *yyssp;
       YY_STACK_PRINT (yyss, yyssp);
     }
 
   if (yyn == YYFINAL)
     YYACCEPT;
 
-  YYDPRINTF ((stderr, "Shifting error token, "));
-
   *++yyvsp = yylval;
 
 
+  /* Shift the error token. */
+  YY_SYMBOL_PRINT ("Shifting", yystos[yyn], yyvsp, yylsp);
+
   yystate = yyn;
   goto yynewstate;
 
@@ -1890,6 +1911,9 @@ yyacceptlab:
 | yyabortlab -- YYABORT comes here.  |
 `-----------------------------------*/
 yyabortlab:
+  yydestruct ("Error: discarding lookahead",
+              yytoken, &yylval);
+  yychar = YYEMPTY;
   yyresult = 1;
   goto yyreturn;
 
@@ -1927,16 +1951,16 @@ void conf_parse(const char *name)
        modules_sym = sym_lookup("MODULES", 0);
        rootmenu.prompt = menu_add_prompt(P_MENU, "Linux Kernel Configuration", NULL);
 
-       //zconfdebug = 1;
+#if YYDEBUG
+       if (getenv("ZCONF_DEBUG"))
+               zconfdebug = 1;
+#endif
        zconfparse();
        if (zconfnerrs)
                exit(1);
        menu_finalize(&rootmenu);
        for_all_symbols(i, sym) {
-                if (!(sym->flags & SYMBOL_CHECKED) && sym_check_deps(sym))
-                        printf("\n");
-               else
-                       sym->flags |= SYMBOL_CHECK_DONE;
+               sym_check_deps(sym);
         }
 
        sym_change_count = 1;
@@ -1951,20 +1975,25 @@ const char *zconf_tokenname(int token)
        case T_ENDCHOICE:       return "endchoice";
        case T_IF:              return "if";
        case T_ENDIF:           return "endif";
+       case T_DEPENDS:         return "depends";
        }
        return "<token>";
 }
 
-static bool zconf_endtoken(int token, int starttoken, int endtoken)
+static bool zconf_endtoken(struct kconf_id *id, int starttoken, int endtoken)
 {
-       if (token != endtoken) {
-               zconfprint("unexpected '%s' within %s block", zconf_tokenname(token), zconf_tokenname(starttoken));
+       if (id->token != endtoken) {
+               zconf_error("unexpected '%s' within %s block",
+                       kconf_id_strings + id->name, zconf_tokenname(starttoken));
                zconfnerrs++;
                return false;
        }
        if (current_menu->file != current_file) {
-               zconfprint("'%s' in different file than '%s'", zconf_tokenname(token), zconf_tokenname(starttoken));
-               zconfprint("location of the '%s'", zconf_tokenname(starttoken));
+               zconf_error("'%s' in different file than '%s'",
+                       kconf_id_strings + id->name, zconf_tokenname(starttoken));
+               fprintf(stderr, "%s:%d: location of the '%s'\n",
+                       current_menu->file->name, current_menu->lineno,
+                       zconf_tokenname(starttoken));
                zconfnerrs++;
                return false;
        }
@@ -1975,7 +2004,19 @@ static void zconfprint(const char *err, ...)
 {
        va_list ap;
 
-       fprintf(stderr, "%s:%d: ", zconf_curname(), zconf_lineno() + 1);
+       fprintf(stderr, "%s:%d: ", zconf_curname(), zconf_lineno());
+       va_start(ap, err);
+       vfprintf(stderr, err, ap);
+       va_end(ap);
+       fprintf(stderr, "\n");
+}
+
+static void zconf_error(const char *err, ...)
+{
+       va_list ap;
+
+       zconfnerrs++;
+       fprintf(stderr, "%s:%d: ", zconf_curname(), zconf_lineno());
        va_start(ap, err);
        vfprintf(stderr, err, ap);
        va_end(ap);
@@ -1984,7 +2025,9 @@ static void zconfprint(const char *err, ...)
 
 static void zconferror(const char *err)
 {
+#if YYDEBUG
        fprintf(stderr, "%s:%d: %s\n", zconf_curname(), zconf_lineno() + 1, err);
+#endif
 }
 
 void print_quoted_string(FILE *out, const char *str)
diff --git a/scripts/kconfig/zconf.tab.h_shipped b/scripts/kconfig/zconf.tab.h_shipped
deleted file mode 100644 (file)
index 3b191ef..0000000
+++ /dev/null
@@ -1,125 +0,0 @@
-/* A Bison parser, made from zconf.y, by GNU bison 1.75.  */
-
-/* Skeleton parser for Yacc-like parsing with Bison,
-   Copyright (C) 1984, 1989, 1990, 2000, 2001, 2002 Free Software Foundation, Inc.
-
-   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, or (at your option)
-   any later version.
-
-   This program is distributed in the hope that it will be useful,
-   but WITHOUT ANY WARRANTY; without even the implied warranty of
-   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-   GNU General Public License for more details.
-
-   You should have received a copy of the GNU General Public License
-   along with this program; if not, write to the Free Software
-   Foundation, Inc., 59 Temple Place - Suite 330,
-   Boston, MA 02111-1307, USA.  */
-
-/* As a special exception, when this file is copied by Bison into a
-   Bison output file, you may use that output file without restriction.
-   This special exception was added by the Free Software Foundation
-   in version 1.24 of Bison.  */
-
-#ifndef BISON_ZCONF_TAB_H
-# define BISON_ZCONF_TAB_H
-
-/* Tokens.  */
-#ifndef YYTOKENTYPE
-# define YYTOKENTYPE
-   /* Put the tokens into the symbol table, so that GDB and other debuggers
-      know about them.  */
-   enum yytokentype {
-     T_MAINMENU = 258,
-     T_MENU = 259,
-     T_ENDMENU = 260,
-     T_SOURCE = 261,
-     T_CHOICE = 262,
-     T_ENDCHOICE = 263,
-     T_COMMENT = 264,
-     T_CONFIG = 265,
-     T_HELP = 266,
-     T_HELPTEXT = 267,
-     T_IF = 268,
-     T_ENDIF = 269,
-     T_DEPENDS = 270,
-     T_REQUIRES = 271,
-     T_OPTIONAL = 272,
-     T_PROMPT = 273,
-     T_DEFAULT = 274,
-     T_TRISTATE = 275,
-     T_BOOLEAN = 276,
-     T_INT = 277,
-     T_HEX = 278,
-     T_WORD = 279,
-     T_STRING = 280,
-     T_UNEQUAL = 281,
-     T_EOF = 282,
-     T_EOL = 283,
-     T_CLOSE_PAREN = 284,
-     T_OPEN_PAREN = 285,
-     T_ON = 286,
-     T_OR = 287,
-     T_AND = 288,
-     T_EQUAL = 289,
-     T_NOT = 290
-   };
-#endif
-#define T_MAINMENU 258
-#define T_MENU 259
-#define T_ENDMENU 260
-#define T_SOURCE 261
-#define T_CHOICE 262
-#define T_ENDCHOICE 263
-#define T_COMMENT 264
-#define T_CONFIG 265
-#define T_HELP 266
-#define T_HELPTEXT 267
-#define T_IF 268
-#define T_ENDIF 269
-#define T_DEPENDS 270
-#define T_REQUIRES 271
-#define T_OPTIONAL 272
-#define T_PROMPT 273
-#define T_DEFAULT 274
-#define T_TRISTATE 275
-#define T_BOOLEAN 276
-#define T_INT 277
-#define T_HEX 278
-#define T_WORD 279
-#define T_STRING 280
-#define T_UNEQUAL 281
-#define T_EOF 282
-#define T_EOL 283
-#define T_CLOSE_PAREN 284
-#define T_OPEN_PAREN 285
-#define T_ON 286
-#define T_OR 287
-#define T_AND 288
-#define T_EQUAL 289
-#define T_NOT 290
-
-
-
-
-#ifndef YYSTYPE
-#line 33 "zconf.y"
-typedef union {
-       int token;
-       char *string;
-       struct symbol *symbol;
-       struct expr *expr;
-       struct menu *menu;
-} yystype;
-/* Line 1281 of /usr/share/bison/yacc.c.  */
-#line 118 "zconf.tab.h"
-# define YYSTYPE yystype
-#endif
-
-extern YYSTYPE zconflval;
-
-
-#endif /* not BISON_ZCONF_TAB_H */
-
index e1a0f455d4a8decb163ff3196a0725b738279bb1..1f61fba6aa287a7699fa474a5ff999c70b6cf793 100644 (file)
 #include <string.h>
 #include <stdbool.h>
 
+#define LKC_DIRECT_LINK
+#include "lkc.h"
+
+#include "zconf.hash.c"
+
 #define printd(mask, fmt...) if (cdebug & (mask)) printf(fmt)
 
 #define PRINTD         0x0001
@@ -20,61 +25,59 @@ int cdebug = PRINTD;
 
 extern int zconflex(void);
 static void zconfprint(const char *err, ...);
+static void zconf_error(const char *err, ...);
 static void zconferror(const char *err);
-static bool zconf_endtoken(int token, int starttoken, int endtoken);
+static bool zconf_endtoken(struct kconf_id *id, int starttoken, int endtoken);
 
 struct symbol *symbol_hash[257];
 
 static struct menu *current_menu, *current_entry;
 
+#define YYDEBUG 0
+#if YYDEBUG
 #define YYERROR_VERBOSE
+#endif
 %}
-%expect 40
+%expect 26
 
 %union
 {
-       int token;
        char *string;
+       struct file *file;
        struct symbol *symbol;
        struct expr *expr;
        struct menu *menu;
+       struct kconf_id *id;
 }
 
-%token T_MAINMENU
-%token T_MENU
-%token T_ENDMENU
-%token T_SOURCE
-%token T_CHOICE
-%token T_ENDCHOICE
-%token T_COMMENT
-%token T_CONFIG
-%token T_MENUCONFIG
-%token T_HELP
+%token <id>T_MAINMENU
+%token <id>T_MENU
+%token <id>T_ENDMENU
+%token <id>T_SOURCE
+%token <id>T_CHOICE
+%token <id>T_ENDCHOICE
+%token <id>T_COMMENT
+%token <id>T_CONFIG
+%token <id>T_MENUCONFIG
+%token <id>T_HELP
 %token <string> T_HELPTEXT
-%token T_IF
-%token T_ENDIF
-%token T_DEPENDS
-%token T_REQUIRES
-%token T_OPTIONAL
-%token T_PROMPT
-%token T_DEFAULT
-%token T_TRISTATE
-%token T_DEF_TRISTATE
-%token T_BOOLEAN
-%token T_DEF_BOOLEAN
-%token T_STRING
-%token T_INT
-%token T_HEX
+%token <id>T_IF
+%token <id>T_ENDIF
+%token <id>T_DEPENDS
+%token <id>T_REQUIRES
+%token <id>T_OPTIONAL
+%token <id>T_PROMPT
+%token <id>T_TYPE
+%token <id>T_DEFAULT
+%token <id>T_SELECT
+%token <id>T_RANGE
+%token <id>T_ON
 %token <string> T_WORD
 %token <string> T_WORD_QUOTE
 %token T_UNEQUAL
-%token T_EOF
-%token T_EOL
 %token T_CLOSE_PAREN
 %token T_OPEN_PAREN
-%token T_ON
-%token T_SELECT
-%token T_RANGE
+%token T_EOL
 
 %left T_OR
 %left T_AND
@@ -82,38 +85,54 @@ static struct menu *current_menu, *current_entry;
 %nonassoc T_NOT
 
 %type <string> prompt
-%type <string> source
 %type <symbol> symbol
 %type <expr> expr
 %type <expr> if_expr
-%type <token> end
+%type <id> end
+%type <id> option_name
+%type <menu> if_entry menu_entry choice_entry
+
+%destructor {
+       fprintf(stderr, "%s:%d: missing end statement for this entry\n",
+               $$->file->name, $$->lineno);
+       if (current_menu == $$)
+               menu_end_menu();
+} if_entry menu_entry choice_entry
 
-%{
-#define LKC_DIRECT_LINK
-#include "lkc.h"
-%}
 %%
-input:   /* empty */
-       | input block
+input: stmt_list;
+
+stmt_list:
+         /* empty */
+       | stmt_list common_stmt
+       | stmt_list choice_stmt
+       | stmt_list menu_stmt
+       | stmt_list T_MAINMENU prompt nl
+       | stmt_list end                 { zconf_error("unexpected end statement"); }
+       | stmt_list T_WORD error T_EOL  { zconf_error("unknown statement \"%s\"", $2); }
+       | stmt_list option_name error T_EOL
+{
+       zconf_error("unexpected option \"%s\"", kconf_id_strings + $2->name);
+}
+       | stmt_list error T_EOL         { zconf_error("invalid statement"); }
 ;
 
-block:   common_block
-       | choice_stmt
-       | menu_stmt
-       | T_MAINMENU prompt nl_or_eof
-       | T_ENDMENU             { zconfprint("unexpected 'endmenu' statement"); }
-       | T_ENDIF               { zconfprint("unexpected 'endif' statement"); }
-       | T_ENDCHOICE           { zconfprint("unexpected 'endchoice' statement"); }
-       | error nl_or_eof       { zconfprint("syntax error"); yyerrok; }
+option_name:
+       T_DEPENDS | T_PROMPT | T_TYPE | T_SELECT | T_OPTIONAL | T_RANGE | T_DEFAULT
 ;
 
-common_block:
-         if_stmt
+common_stmt:
+         T_EOL
+       | if_stmt
        | comment_stmt
        | config_stmt
        | menuconfig_stmt
        | source_stmt
-       | nl_or_eof
+;
+
+option_error:
+         T_WORD error T_EOL            { zconf_error("unknown option \"%s\"", $1); }
+       | error T_EOL                   { zconf_error("invalid option"); }
 ;
 
 
@@ -156,51 +175,16 @@ config_option_list:
        | config_option_list config_option
        | config_option_list depends
        | config_option_list help
+       | config_option_list option_error
        | config_option_list T_EOL
 ;
 
-config_option: T_TRISTATE prompt_stmt_opt T_EOL
+config_option: T_TYPE prompt_stmt_opt T_EOL
 {
-       menu_set_type(S_TRISTATE);
-       printd(DEBUG_PARSE, "%s:%d:tristate\n", zconf_curname(), zconf_lineno());
-};
-
-config_option: T_DEF_TRISTATE expr if_expr T_EOL
-{
-       menu_add_expr(P_DEFAULT, $2, $3);
-       menu_set_type(S_TRISTATE);
-       printd(DEBUG_PARSE, "%s:%d:def_boolean\n", zconf_curname(), zconf_lineno());
-};
-
-config_option: T_BOOLEAN prompt_stmt_opt T_EOL
-{
-       menu_set_type(S_BOOLEAN);
-       printd(DEBUG_PARSE, "%s:%d:boolean\n", zconf_curname(), zconf_lineno());
-};
-
-config_option: T_DEF_BOOLEAN expr if_expr T_EOL
-{
-       menu_add_expr(P_DEFAULT, $2, $3);
-       menu_set_type(S_BOOLEAN);
-       printd(DEBUG_PARSE, "%s:%d:def_boolean\n", zconf_curname(), zconf_lineno());
-};
-
-config_option: T_INT prompt_stmt_opt T_EOL
-{
-       menu_set_type(S_INT);
-       printd(DEBUG_PARSE, "%s:%d:int\n", zconf_curname(), zconf_lineno());
-};
-
-config_option: T_HEX prompt_stmt_opt T_EOL
-{
-       menu_set_type(S_HEX);
-       printd(DEBUG_PARSE, "%s:%d:hex\n", zconf_curname(), zconf_lineno());
-};
-
-config_option: T_STRING prompt_stmt_opt T_EOL
-{
-       menu_set_type(S_STRING);
-       printd(DEBUG_PARSE, "%s:%d:string\n", zconf_curname(), zconf_lineno());
+       menu_set_type($1->stype);
+       printd(DEBUG_PARSE, "%s:%d:type(%u)\n",
+               zconf_curname(), zconf_lineno(),
+               $1->stype);
 };
 
 config_option: T_PROMPT prompt if_expr T_EOL
@@ -212,7 +196,11 @@ config_option: T_PROMPT prompt if_expr T_EOL
 config_option: T_DEFAULT expr if_expr T_EOL
 {
        menu_add_expr(P_DEFAULT, $2, $3);
-       printd(DEBUG_PARSE, "%s:%d:default\n", zconf_curname(), zconf_lineno());
+       if ($1->stype != S_UNKNOWN)
+               menu_set_type($1->stype);
+       printd(DEBUG_PARSE, "%s:%d:default(%u)\n",
+               zconf_curname(), zconf_lineno(),
+               $1->stype);
 };
 
 config_option: T_SELECT T_WORD if_expr T_EOL
@@ -240,8 +228,7 @@ choice: T_CHOICE T_EOL
 
 choice_entry: choice choice_option_list
 {
-       menu_end_entry();
-       menu_add_menu();
+       $$ = menu_add_menu();
 };
 
 choice_end: end
@@ -252,13 +239,8 @@ choice_end: end
        }
 };
 
-choice_stmt:
-         choice_entry choice_block choice_end
-       | choice_entry choice_block
-{
-       printf("%s:%d: missing 'endchoice' for this 'choice' statement\n", current_menu->file->name, current_menu->lineno);
-       zconfnerrs++;
-};
+choice_stmt: choice_entry choice_block choice_end
+;
 
 choice_option_list:
          /* empty */
@@ -266,6 +248,7 @@ choice_option_list:
        | choice_option_list depends
        | choice_option_list help
        | choice_option_list T_EOL
+       | choice_option_list option_error
 ;
 
 choice_option: T_PROMPT prompt if_expr T_EOL
@@ -274,16 +257,15 @@ choice_option: T_PROMPT prompt if_expr T_EOL
        printd(DEBUG_PARSE, "%s:%d:prompt\n", zconf_curname(), zconf_lineno());
 };
 
-choice_option: T_TRISTATE prompt_stmt_opt T_EOL
-{
-       menu_set_type(S_TRISTATE);
-       printd(DEBUG_PARSE, "%s:%d:tristate\n", zconf_curname(), zconf_lineno());
-};
-
-choice_option: T_BOOLEAN prompt_stmt_opt T_EOL
+choice_option: T_TYPE prompt_stmt_opt T_EOL
 {
-       menu_set_type(S_BOOLEAN);
-       printd(DEBUG_PARSE, "%s:%d:boolean\n", zconf_curname(), zconf_lineno());
+       if ($1->stype == S_BOOLEAN || $1->stype == S_TRISTATE) {
+               menu_set_type($1->stype);
+               printd(DEBUG_PARSE, "%s:%d:type(%u)\n",
+                       zconf_curname(), zconf_lineno(),
+                       $1->stype);
+       } else
+               YYERROR;
 };
 
 choice_option: T_OPTIONAL T_EOL
@@ -294,24 +276,27 @@ choice_option: T_OPTIONAL T_EOL
 
 choice_option: T_DEFAULT T_WORD if_expr T_EOL
 {
-       menu_add_symbol(P_DEFAULT, sym_lookup($2, 0), $3);
-       printd(DEBUG_PARSE, "%s:%d:default\n", zconf_curname(), zconf_lineno());
+       if ($1->stype == S_UNKNOWN) {
+               menu_add_symbol(P_DEFAULT, sym_lookup($2, 0), $3);
+               printd(DEBUG_PARSE, "%s:%d:default\n",
+                       zconf_curname(), zconf_lineno());
+       } else
+               YYERROR;
 };
 
 choice_block:
          /* empty */
-       | choice_block common_block
+       | choice_block common_stmt
 ;
 
 /* if entry */
 
-if: T_IF expr T_EOL
+if_entry: T_IF expr nl
 {
        printd(DEBUG_PARSE, "%s:%d:if\n", zconf_curname(), zconf_lineno());
        menu_add_entry(NULL);
        menu_add_dep($2);
-       menu_end_entry();
-       menu_add_menu();
+       $$ = menu_add_menu();
 };
 
 if_end: end
@@ -322,17 +307,12 @@ if_end: end
        }
 };
 
-if_stmt:
-         if if_block if_end
-       | if if_block
-{
-       printf("%s:%d: missing 'endif' for this 'if' statement\n", current_menu->file->name, current_menu->lineno);
-       zconfnerrs++;
-};
+if_stmt: if_entry if_block if_end
+;
 
 if_block:
          /* empty */
-       | if_block common_block
+       | if_block common_stmt
        | if_block menu_stmt
        | if_block choice_stmt
 ;
@@ -348,8 +328,7 @@ menu: T_MENU prompt T_EOL
 
 menu_entry: menu depends_list
 {
-       menu_end_entry();
-       menu_add_menu();
+       $$ = menu_add_menu();
 };
 
 menu_end: end
@@ -360,31 +339,20 @@ menu_end: end
        }
 };
 
-menu_stmt:
-         menu_entry menu_block menu_end
-       | menu_entry menu_block
-{
-       printf("%s:%d: missing 'endmenu' for this 'menu' statement\n", current_menu->file->name, current_menu->lineno);
-       zconfnerrs++;
-};
+menu_stmt: menu_entry menu_block menu_end
+;
 
 menu_block:
          /* empty */
-       | menu_block common_block
+       | menu_block common_stmt
        | menu_block menu_stmt
        | menu_block choice_stmt
-       | menu_block error T_EOL                { zconfprint("invalid menu option"); yyerrok; }
 ;
 
-source: T_SOURCE prompt T_EOL
+source_stmt: T_SOURCE prompt T_EOL
 {
-       $$ = $2;
        printd(DEBUG_PARSE, "%s:%d:source %s\n", zconf_curname(), zconf_lineno(), $2);
-};
-
-source_stmt: source
-{
-       zconf_nextfile($1);
+       zconf_nextfile($2);
 };
 
 /* comment entry */
@@ -416,9 +384,11 @@ help: help_start T_HELPTEXT
 
 /* depends option */
 
-depends_list:    /* empty */
-               | depends_list depends
-               | depends_list T_EOL
+depends_list:
+         /* empty */
+       | depends_list depends
+       | depends_list T_EOL
+       | depends_list option_error
 ;
 
 depends: T_DEPENDS T_ON expr T_EOL
@@ -450,13 +420,15 @@ prompt:     T_WORD
        | T_WORD_QUOTE
 ;
 
-end:     T_ENDMENU nl_or_eof   { $$ = T_ENDMENU; }
-       | T_ENDCHOICE nl_or_eof { $$ = T_ENDCHOICE; }
-       | T_ENDIF nl_or_eof     { $$ = T_ENDIF; }
+end:     T_ENDMENU T_EOL       { $$ = $1; }
+       | T_ENDCHOICE T_EOL     { $$ = $1; }
+       | T_ENDIF T_EOL         { $$ = $1; }
 ;
 
-nl_or_eof:
-       T_EOL | T_EOF;
+nl:
+         T_EOL
+       | nl T_EOL
+;
 
 if_expr:  /* empty */                  { $$ = NULL; }
        | T_IF expr                     { $$ = $2; }
@@ -489,16 +461,16 @@ void conf_parse(const char *name)
        modules_sym = sym_lookup("MODULES", 0);
        rootmenu.prompt = menu_add_prompt(P_MENU, "Linux Kernel Configuration", NULL);
 
-       //zconfdebug = 1;
+#if YYDEBUG
+       if (getenv("ZCONF_DEBUG"))
+               zconfdebug = 1;
+#endif
        zconfparse();
        if (zconfnerrs)
                exit(1);
        menu_finalize(&rootmenu);
        for_all_symbols(i, sym) {
-                if (!(sym->flags & SYMBOL_CHECKED) && sym_check_deps(sym))
-                        printf("\n");
-               else
-                       sym->flags |= SYMBOL_CHECK_DONE;
+               sym_check_deps(sym);
         }
 
        sym_change_count = 1;
@@ -513,20 +485,25 @@ const char *zconf_tokenname(int token)
        case T_ENDCHOICE:       return "endchoice";
        case T_IF:              return "if";
        case T_ENDIF:           return "endif";
+       case T_DEPENDS:         return "depends";
        }
        return "<token>";
 }
 
-static bool zconf_endtoken(int token, int starttoken, int endtoken)
+static bool zconf_endtoken(struct kconf_id *id, int starttoken, int endtoken)
 {
-       if (token != endtoken) {
-               zconfprint("unexpected '%s' within %s block", zconf_tokenname(token), zconf_tokenname(starttoken));
+       if (id->token != endtoken) {
+               zconf_error("unexpected '%s' within %s block",
+                       kconf_id_strings + id->name, zconf_tokenname(starttoken));
                zconfnerrs++;
                return false;
        }
        if (current_menu->file != current_file) {
-               zconfprint("'%s' in different file than '%s'", zconf_tokenname(token), zconf_tokenname(starttoken));
-               zconfprint("location of the '%s'", zconf_tokenname(starttoken));
+               zconf_error("'%s' in different file than '%s'",
+                       kconf_id_strings + id->name, zconf_tokenname(starttoken));
+               fprintf(stderr, "%s:%d: location of the '%s'\n",
+                       current_menu->file->name, current_menu->lineno,
+                       zconf_tokenname(starttoken));
                zconfnerrs++;
                return false;
        }
@@ -537,7 +514,19 @@ static void zconfprint(const char *err, ...)
 {
        va_list ap;
 
-       fprintf(stderr, "%s:%d: ", zconf_curname(), zconf_lineno() + 1);
+       fprintf(stderr, "%s:%d: ", zconf_curname(), zconf_lineno());
+       va_start(ap, err);
+       vfprintf(stderr, err, ap);
+       va_end(ap);
+       fprintf(stderr, "\n");
+}
+
+static void zconf_error(const char *err, ...)
+{
+       va_list ap;
+
+       zconfnerrs++;
+       fprintf(stderr, "%s:%d: ", zconf_curname(), zconf_lineno());
        va_start(ap, err);
        vfprintf(stderr, err, ap);
        va_end(ap);
@@ -546,7 +535,9 @@ static void zconfprint(const char *err, ...)
 
 static void zconferror(const char *err)
 {
+#if YYDEBUG
        fprintf(stderr, "%s:%d: %s\n", zconf_curname(), zconf_lineno() + 1, err);
+#endif
 }
 
 void print_quoted_string(FILE *out, const char *str)
index 45c41490d521e22b07219345fe195f02e171ac27..fc774436a264d0f21c1b07f142d96331372014f2 100644 (file)
@@ -1986,6 +1986,9 @@ static int selinux_inode_init_security(struct inode *inode, struct inode *dir,
 
        inode_security_set_sid(inode, newsid);
 
+       if (sbsec->behavior == SECURITY_FS_USE_MNTPOINT)
+               return -EOPNOTSUPP;
+
        if (name) {
                namep = kstrdup(XATTR_SELINUX_SUFFIX, GFP_KERNEL);
                if (!namep)
index fdc3823897207284fafe407546b40cdc7edd7899..0e1352a555c867baa67d136a49d946f8e9f5fc73 100644 (file)
@@ -271,46 +271,38 @@ static struct file_operations sel_load_ops = {
        .write          = sel_write_load,
 };
 
-
-static ssize_t sel_write_context(struct file * file, const char __user * buf,
-                                size_t count, loff_t *ppos)
-
+static ssize_t sel_write_context(struct file * file, char *buf, size_t size)
 {
-       char *page;
-       u32 sid;
+       char *canon;
+       u32 sid, len;
        ssize_t length;
 
        length = task_has_security(current, SECURITY__CHECK_CONTEXT);
        if (length)
                return length;
 
-       if (count >= PAGE_SIZE)
-               return -ENOMEM;
-       if (*ppos != 0) {
-               /* No partial writes. */
-               return -EINVAL;
-       }
-       page = (char*)get_zeroed_page(GFP_KERNEL);
-       if (!page)
-               return -ENOMEM;
-       length = -EFAULT;
-       if (copy_from_user(page, buf, count))
-               goto out;
+       length = security_context_to_sid(buf, size, &sid);
+       if (length < 0)
+               return length;
 
-       length = security_context_to_sid(page, count, &sid);
+       length = security_sid_to_context(sid, &canon, &len);
        if (length < 0)
+               return length;
+
+       if (len > SIMPLE_TRANSACTION_LIMIT) {
+               printk(KERN_ERR "%s:  context size (%u) exceeds payload "
+                      "max\n", __FUNCTION__, len);
+               length = -ERANGE;
                goto out;
+       }
 
-       length = count;
+       memcpy(buf, canon, len);
+       length = len;
 out:
-       free_page((unsigned long) page);
+       kfree(canon);
        return length;
 }
 
-static struct file_operations sel_context_ops = {
-       .write          = sel_write_context,
-};
-
 static ssize_t sel_read_checkreqprot(struct file *filp, char __user *buf,
                                     size_t count, loff_t *ppos)
 {
@@ -375,6 +367,7 @@ static ssize_t (*write_op[])(struct file *, char *, size_t) = {
        [SEL_RELABEL] = sel_write_relabel,
        [SEL_USER] = sel_write_user,
        [SEL_MEMBER] = sel_write_member,
+       [SEL_CONTEXT] = sel_write_context,
 };
 
 static ssize_t selinux_transaction_write(struct file *file, const char __user *buf, size_t size, loff_t *pos)
@@ -1220,7 +1213,7 @@ static int sel_fill_super(struct super_block * sb, void * data, int silent)
        static struct tree_descr selinux_files[] = {
                [SEL_LOAD] = {"load", &sel_load_ops, S_IRUSR|S_IWUSR},
                [SEL_ENFORCE] = {"enforce", &sel_enforce_ops, S_IRUGO|S_IWUSR},
-               [SEL_CONTEXT] = {"context", &sel_context_ops, S_IRUGO|S_IWUGO},
+               [SEL_CONTEXT] = {"context", &transaction_ops, S_IRUGO|S_IWUGO},
                [SEL_ACCESS] = {"access", &transaction_ops, S_IRUGO|S_IWUGO},
                [SEL_CREATE] = {"create", &transaction_ops, S_IRUGO|S_IWUGO},
                [SEL_RELABEL] = {"relabel", &transaction_ops, S_IRUGO|S_IWUGO},
index aaefac2921f1d94cedbd33f29afa631796e28503..640d0bfdbc6819e4ffa7845f1e10e92b5640e14a 100644 (file)
@@ -262,8 +262,11 @@ int mls_context_to_sid(char oldc,
        struct cat_datum *catdatum, *rngdatum;
        int l, rc = -EINVAL;
 
-       if (!selinux_mls_enabled)
+       if (!selinux_mls_enabled) {
+               if (def_sid != SECSID_NULL && oldc)
+                       *scontext += strlen(*scontext);
                return 0;
+       }
 
        /*
         * No MLS component to the security context, try and map to
index 9a3dc3c3b3de301ec2d5739662c08058e209bfe8..c4993b004c420be609e7d95530a48634f17f2ae0 100644 (file)
@@ -23,6 +23,7 @@
 #include <sound/driver.h>
 #include <linux/device.h>
 #include <linux/firmware.h>
+#include <linux/vmalloc.h>
 #include <sound/core.h>
 #include <sound/hwdep.h>
 #include <sound/vx_core.h>
index 953e5f3ea03d6bb990584f58bed059b6f8420c25..88e52dc84c096b94514fd2e4ed76761edaceb42a 100644 (file)
@@ -4,9 +4,24 @@
 # More hacking for modularisation.
 #
 # Prompt user for primary drivers.
+
+config OBSOLETE_OSS_DRIVER
+       bool "Obsolete OSS drivers"
+       depends on SOUND_PRIME
+       help
+         This option enables support for obsolete OSS drivers that
+         are scheduled for removal in the near future since there
+         are ALSA drivers for the same hardware.
+
+         Please contact Adrian Bunk <bunk@stusta.de> if you had to
+         say Y here because your soundcard is not properly supported
+         by ALSA.
+
+         If unsure, say N.
+
 config SOUND_BT878
        tristate "BT878 audio dma"
-       depends on SOUND_PRIME && PCI
+       depends on SOUND_PRIME && PCI && OBSOLETE_OSS_DRIVER
        ---help---
          Audio DMA support for bt878 based grabber boards.  As you might have
          already noticed, bt878 is listed with two functions in /proc/pci.
@@ -22,7 +37,7 @@ config SOUND_BT878
 
 config SOUND_CMPCI
        tristate "C-Media PCI (CMI8338/8738)"
-       depends on SOUND_PRIME && PCI
+       depends on SOUND_PRIME && PCI && OBSOLETE_OSS_DRIVER
        help
          Say Y or M if you have a PCI sound card using the CMI8338
          or the CMI8738 chipset.  Data on these chips are available at
@@ -61,7 +76,7 @@ config SOUND_CMPCI_JOYSTICK
 
 config SOUND_EMU10K1
        tristate "Creative SBLive! (EMU10K1)"
-       depends on SOUND_PRIME && PCI
+       depends on SOUND_PRIME && PCI && OBSOLETE_OSS_DRIVER
        ---help---
          Say Y or M if you have a PCI sound card using the EMU10K1 chipset,
          such as the Creative SBLive!, SB PCI512 or Emu-APS.
@@ -95,7 +110,7 @@ config SOUND_FUSION
 
 config SOUND_CS4281
        tristate "Crystal Sound CS4281"
-       depends on SOUND_PRIME && PCI
+       depends on SOUND_PRIME && PCI && OBSOLETE_OSS_DRIVER
        help
          Picture and feature list at
          <http://www.pcbroker.com/crystal4281.html>.
@@ -112,7 +127,7 @@ config SOUND_BCM_CS4297A
 
 config SOUND_ES1370
        tristate "Ensoniq AudioPCI (ES1370)"
-       depends on SOUND_PRIME && PCI
+       depends on SOUND_PRIME && PCI && OBSOLETE_OSS_DRIVER
        help
          Say Y or M if you have a PCI sound card utilizing the Ensoniq
          ES1370 chipset, such as Ensoniq's AudioPCI (non-97). To find
@@ -125,7 +140,7 @@ config SOUND_ES1370
 
 config SOUND_ES1371
        tristate "Creative Ensoniq AudioPCI 97 (ES1371)"
-       depends on SOUND_PRIME && PCI
+       depends on SOUND_PRIME && PCI && OBSOLETE_OSS_DRIVER
        help
          Say Y or M if you have a PCI sound card utilizing the Ensoniq
          ES1371 chipset, such as Ensoniq's AudioPCI97. To find out if
@@ -138,7 +153,7 @@ config SOUND_ES1371
 
 config SOUND_ESSSOLO1
        tristate "ESS Technology Solo1" 
-       depends on SOUND_PRIME && PCI
+       depends on SOUND_PRIME && PCI && OBSOLETE_OSS_DRIVER
        help
          Say Y or M if you have a PCI sound card utilizing the ESS Technology
          Solo1 chip. To find out if your sound card uses a
@@ -149,7 +164,7 @@ config SOUND_ESSSOLO1
 
 config SOUND_MAESTRO
        tristate "ESS Maestro, Maestro2, Maestro2E driver"
-       depends on SOUND_PRIME && PCI
+       depends on SOUND_PRIME && PCI && OBSOLETE_OSS_DRIVER
        help
          Say Y or M if you have a sound system driven by ESS's Maestro line
          of PCI sound chips.  These include the Maestro 1, Maestro 2, and
@@ -158,7 +173,7 @@ config SOUND_MAESTRO
 
 config SOUND_MAESTRO3
        tristate "ESS Maestro3/Allegro driver (EXPERIMENTAL)"
-       depends on SOUND_PRIME && PCI && EXPERIMENTAL
+       depends on SOUND_PRIME && PCI && EXPERIMENTAL && OBSOLETE_OSS_DRIVER
        help
          Say Y or M if you have a sound system driven by ESS's Maestro 3
          PCI sound chip.
@@ -172,14 +187,14 @@ config SOUND_ICH
 
 config SOUND_HARMONY
        tristate "PA Harmony audio driver"
-       depends on GSC_LASI && SOUND_PRIME
+       depends on GSC_LASI && SOUND_PRIME && OBSOLETE_OSS_DRIVER
        help
          Say 'Y' or 'M' to include support for Harmony soundchip
          on HP 712, 715/new and many other GSC based machines.
 
 config SOUND_SONICVIBES
        tristate "S3 SonicVibes"
-       depends on SOUND_PRIME && PCI
+       depends on SOUND_PRIME && PCI && OBSOLETE_OSS_DRIVER
        help
          Say Y or M if you have a PCI sound card utilizing the S3
          SonicVibes chipset. To find out if your sound card uses a
@@ -218,7 +233,7 @@ config SOUND_VRC5477
 
 config SOUND_AU1000
        tristate "Au1000 Sound"
-       depends on SOUND_PRIME && (SOC_AU1000 || SOC_AU1100 || SOC_AU1500)
+       depends on SOUND_PRIME && (SOC_AU1000 || SOC_AU1100 || SOC_AU1500) && OBSOLETE_OSS_DRIVER
 
 config SOUND_AU1550_AC97
        tristate "Au1550 AC97 Sound"
@@ -492,7 +507,7 @@ config MSND_FIFOSIZE
 
 config SOUND_VIA82CXXX
        tristate "VIA 82C686 Audio Codec"
-       depends on SOUND_PRIME && PCI
+       depends on SOUND_PRIME && PCI && OBSOLETE_OSS_DRIVER
        help
          Say Y here to include support for the audio codec found on VIA
          82Cxxx-based chips. Typically these are built into a motherboard.
@@ -563,7 +578,7 @@ config SOUND_AD1889
 
 config SOUND_SGALAXY
        tristate "Aztech Sound Galaxy (non-PnP) cards"
-       depends on SOUND_OSS
+       depends on SOUND_OSS && OBSOLETE_OSS_DRIVER
        help
          This module initializes the older non Plug and Play sound galaxy
          cards from Aztech. It supports the Waverider Pro 32 - 3D and the
@@ -599,7 +614,7 @@ config SOUND_ACI_MIXER
 
 config SOUND_CS4232
        tristate "Crystal CS4232 based (PnP) cards"
-       depends on SOUND_OSS
+       depends on SOUND_OSS && OBSOLETE_OSS_DRIVER
        help
          Say Y here if you have a card based on the Crystal CS4232 chip set,
          which uses its own Plug and Play protocol.
@@ -613,7 +628,7 @@ config SOUND_CS4232
 
 config SOUND_SSCAPE
        tristate "Ensoniq SoundScape support"
-       depends on SOUND_OSS
+       depends on SOUND_OSS && OBSOLETE_OSS_DRIVER
        help
          Answer Y if you have a sound card based on the Ensoniq SoundScape
          chipset. Such cards are being manufactured at least by Ensoniq, Spea
@@ -625,7 +640,7 @@ config SOUND_SSCAPE
 
 config SOUND_GUS
        tristate "Gravis Ultrasound support"
-       depends on SOUND_OSS
+       depends on SOUND_OSS && OBSOLETE_OSS_DRIVER
        help
          Say Y here for any type of Gravis Ultrasound card, including the GUS
          or GUS MAX.  See also <file:Documentation/sound/oss/ultrasound> for more
@@ -727,7 +742,7 @@ config SOUND_MPU401
 
 config SOUND_NM256
        tristate "NM256AV/NM256ZX audio support"
-       depends on SOUND_OSS
+       depends on SOUND_OSS && OBSOLETE_OSS_DRIVER
        help
          Say M here to include audio support for the NeoMagic 256AV/256ZX
          chipsets. These are the audio chipsets found in the Sony
@@ -739,7 +754,7 @@ config SOUND_NM256
 
 config SOUND_MAD16
        tristate "OPTi MAD16 and/or Mozart based cards"
-       depends on SOUND_OSS
+       depends on SOUND_OSS && OBSOLETE_OSS_DRIVER
        ---help---
          Answer Y if your card has a Mozart (OAK OTI-601) or MAD16 (OPTi
          82C928 or 82C929 or 82C931) audio interface chip. These chips are
@@ -860,7 +875,7 @@ config SOUND_SB
 
 config SOUND_AWE32_SYNTH
        tristate "AWE32 synth"
-       depends on SOUND_OSS
+       depends on SOUND_OSS && OBSOLETE_OSS_DRIVER
        help
          Say Y here if you have a Sound Blaster SB32, AWE32-PnP, SB AWE64 or
          similar sound card. See <file:Documentation/sound/oss/README.awe>,
@@ -870,7 +885,7 @@ config SOUND_AWE32_SYNTH
 
 config SOUND_WAVEFRONT
        tristate "Full support for Turtle Beach WaveFront (Tropez Plus, Tropez, Maui) synth/soundcards"
-       depends on SOUND_OSS && m
+       depends on SOUND_OSS && m && OBSOLETE_OSS_DRIVER
        help
          Answer Y or M if you have a Tropez Plus, Tropez or Maui sound card
          and read the files <file:Documentation/sound/oss/Wavefront> and
@@ -878,7 +893,7 @@ config SOUND_WAVEFRONT
 
 config SOUND_MAUI
        tristate "Limited support for Turtle Beach Wave Front (Maui, Tropez) synthesizers"
-       depends on SOUND_OSS
+       depends on SOUND_OSS && OBSOLETE_OSS_DRIVER
        help
          Say Y here if you have a Turtle Beach Wave Front, Maui, or Tropez
          sound card.
@@ -904,7 +919,7 @@ config MAUI_BOOT_FILE
 
 config SOUND_YM3812
        tristate "Yamaha FM synthesizer (YM3812/OPL-3) support"
-       depends on SOUND_OSS
+       depends on SOUND_OSS && OBSOLETE_OSS_DRIVER
        ---help---
          Answer Y if your card has a FM chip made by Yamaha (OPL2/OPL3/OPL4).
          Answering Y is usually a safe and recommended choice, however some
@@ -920,7 +935,7 @@ config SOUND_YM3812
 
 config SOUND_OPL3SA1
        tristate "Yamaha OPL3-SA1 audio controller"
-       depends on SOUND_OSS
+       depends on SOUND_OSS && OBSOLETE_OSS_DRIVER
        help
          Say Y or M if you have a Yamaha OPL3-SA1 sound chip, which is
          usually built into motherboards. Read
@@ -946,7 +961,7 @@ config SOUND_OPL3SA2
 
 config SOUND_YMFPCI
        tristate "Yamaha YMF7xx PCI audio (native mode)"
-       depends on SOUND_OSS && PCI
+       depends on SOUND_OSS && PCI && OBSOLETE_OSS_DRIVER
        help
          Support for Yamaha cards including the YMF711, YMF715, YMF718,
          YMF719, YMF724, Waveforce 192XG, and Waveforce 192 Digital.
@@ -1088,11 +1103,11 @@ config SOUND_KAHLUA
 
 config SOUND_ALI5455
        tristate "ALi5455 audio support"
-       depends on SOUND_PRIME && PCI
+       depends on SOUND_PRIME && PCI && OBSOLETE_OSS_DRIVER
 
 config SOUND_FORTE
        tristate "ForteMedia FM801 driver"
-       depends on SOUND_PRIME && PCI
+       depends on SOUND_PRIME && PCI && OBSOLETE_OSS_DRIVER
        help
          Say Y or M if you want driver support for the ForteMedia FM801 PCI
          audio controller (Abit AU10, Genius Sound Maker, HP Workstation
@@ -1100,7 +1115,7 @@ config SOUND_FORTE
 
 config SOUND_RME96XX
        tristate "RME Hammerfall (RME96XX) support"
-       depends on SOUND_PRIME && PCI
+       depends on SOUND_PRIME && PCI && OBSOLETE_OSS_DRIVER
        help
          Say Y or M if you have a Hammerfall or Hammerfall light
          multichannel card from RME. If you want to access advanced
@@ -1108,7 +1123,7 @@ config SOUND_RME96XX
 
 config SOUND_AD1980
        tristate "AD1980 front/back switch plugin"
-       depends on SOUND_PRIME
+       depends on SOUND_PRIME && OBSOLETE_OSS_DRIVER
 
 config SOUND_SH_DAC_AUDIO
        tristate "SuperH DAC audio support"
index 4f1ff1bccdcee0a6106ffbd16b206071564c22d6..a7ad2b0a2ac095b768bb6f9ddd7fdf65615b6654 100644 (file)
@@ -24,7 +24,6 @@
  *
  ********************************************************************/
 
-#include <linux/version.h>
 #include <linux/module.h>
 #include <linux/kernel.h>
 #include <linux/slab.h>
index 80dce329cc3a65d8d0a9fcef8793370c415a2687..0490562c7f7f03d8bed5f945ee4f30943721f64b 100644 (file)
@@ -5,10 +5,8 @@
 #undef  DO_TIMINGS
 
 #include <linux/module.h>
-#include <linux/version.h>
 
 #ifdef __KERNEL__
-#include <linux/utsname.h>
 #include <linux/string.h>
 #include <linux/fs.h>
 #include <asm/dma.h>
index 7609c68a89f44ca4fab2b2a4c9f915a29bcb72fe..318dc51009fe282e101cfcb862ca04637e622019 100644 (file)
@@ -44,7 +44,6 @@ TODO:
 #define RMEVERSION "0.8"
 #endif
 
-#include <linux/version.h>
 #include <linux/module.h>
 #include <linux/string.h>
 #include <linux/sched.h>
index c09cdeedc1914f33ee7e443715761a456997f24b..8a9917c919c2e60cc00b06908f61d855bb184f3c 100644 (file)
@@ -2,7 +2,6 @@
 #include <linux/module.h>
 #include <linux/init.h>
 #include <linux/sched.h>
-#include <linux/version.h>
 #include <linux/linkage.h>
 #include <linux/slab.h>
 #include <linux/fs.h>
index ae3bb6c6edfffb0827c4e47e0a2cb4997e1cabb9..bfff788e9847d960a58a9a6be3dd7735ec77e611 100644 (file)
@@ -22,7 +22,6 @@
 #ifndef __PMAC_H
 #define __PMAC_H
 
-#include <linux/version.h>
 #include <sound/control.h>
 #include <sound/pcm.h>
 #include "awacs.h"