Merge branch 'for-linus' of git://git.kernel.dk/linux-2.6-block
authorLinus Torvalds <torvalds@linux-foundation.org>
Wed, 16 Sep 2009 14:46:34 +0000 (07:46 -0700)
committerLinus Torvalds <torvalds@linux-foundation.org>
Wed, 16 Sep 2009 14:46:34 +0000 (07:46 -0700)
* 'for-linus' of git://git.kernel.dk/linux-2.6-block:
  block: fix linkage problem with blk_iopoll and !CONFIG_BLOCK

619 files changed:
CREDITS
Documentation/arm/SA1100/ADSBitsy
Documentation/arm/SA1100/Assabet
Documentation/arm/SA1100/Brutus
Documentation/arm/SA1100/GraphicsClient
Documentation/arm/SA1100/GraphicsMaster
Documentation/arm/SA1100/Victor
Documentation/intel_txt.txt [new file with mode: 0644]
Documentation/kernel-parameters.txt
Documentation/video4linux/CARDLIST.cx23885
Documentation/video4linux/CARDLIST.cx88
Documentation/video4linux/CARDLIST.em28xx
Documentation/video4linux/CARDLIST.saa7134
Documentation/video4linux/CARDLIST.tuner
Documentation/video4linux/CQcam.txt
Documentation/video4linux/gspca.txt
Documentation/video4linux/si4713.txt [new file with mode: 0644]
Documentation/x86/zero-page.txt
MAINTAINERS
Makefile
arch/alpha/include/asm/agp.h
arch/alpha/include/asm/percpu.h
arch/alpha/include/asm/tlbflush.h
arch/alpha/kernel/vmlinux.lds.S
arch/arm/boot/compressed/head-sa1100.S
arch/arm/kernel/vmlinux.lds.S
arch/arm/lib/lib1funcs.S
arch/arm/lib/sha1.S
arch/arm/mach-sa1100/include/mach/assabet.h
arch/arm/mach-sa1100/include/mach/hardware.h
arch/arm/mach-sa1100/include/mach/memory.h
arch/arm/mach-sa1100/include/mach/neponset.h
arch/arm/mach-sa1100/include/mach/system.h
arch/arm/mach-sa1100/include/mach/uncompress.h
arch/arm/mach-sa1100/pm.c
arch/arm/mach-sa1100/time.c
arch/arm/mm/proc-xscale.S
arch/arm/plat-iop/setup.c
arch/arm/plat-omap/include/mach/system.h
arch/avr32/kernel/vmlinux.lds.S
arch/blackfin/kernel/vmlinux.lds.S
arch/blackfin/mm/sram-alloc.c
arch/cris/include/asm/mmu_context.h
arch/cris/kernel/vmlinux.lds.S
arch/cris/mm/fault.c
arch/frv/kernel/vmlinux.lds.S
arch/h8300/kernel/vmlinux.lds.S
arch/ia64/Kconfig
arch/ia64/include/asm/agp.h
arch/ia64/kernel/setup.c
arch/ia64/kernel/smp.c
arch/ia64/kernel/vmlinux.lds.S
arch/ia64/sn/kernel/setup.c
arch/m32r/kernel/vmlinux.lds.S
arch/m68k/kernel/vmlinux-std.lds
arch/m68k/kernel/vmlinux-sun3.lds
arch/m68knommu/kernel/vmlinux.lds.S
arch/microblaze/kernel/vmlinux.lds.S
arch/mips/kernel/vmlinux.lds.S
arch/mn10300/kernel/vmlinux.lds.S
arch/parisc/include/asm/agp.h
arch/parisc/kernel/vmlinux.lds.S
arch/powerpc/Kconfig
arch/powerpc/Makefile
arch/powerpc/boot/4xx.c
arch/powerpc/boot/4xx.h
arch/powerpc/boot/Makefile
arch/powerpc/boot/cuboot-hotfoot.c [new file with mode: 0644]
arch/powerpc/boot/cuboot-kilauea.c [new file with mode: 0644]
arch/powerpc/boot/dcr.h
arch/powerpc/boot/dts/arches.dts
arch/powerpc/boot/dts/canyonlands.dts
arch/powerpc/boot/dts/eiger.dts [new file with mode: 0644]
arch/powerpc/boot/dts/gef_sbc310.dts
arch/powerpc/boot/dts/hotfoot.dts [new file with mode: 0644]
arch/powerpc/boot/dts/kilauea.dts
arch/powerpc/boot/dts/mgcoge.dts
arch/powerpc/boot/dts/mpc8272ads.dts
arch/powerpc/boot/dts/mpc8377_rdb.dts
arch/powerpc/boot/dts/mpc8377_wlan.dts [new file with mode: 0644]
arch/powerpc/boot/dts/mpc8378_rdb.dts
arch/powerpc/boot/dts/mpc8379_rdb.dts
arch/powerpc/boot/dts/mpc8536ds.dts
arch/powerpc/boot/dts/mpc8536ds_36b.dts [new file with mode: 0644]
arch/powerpc/boot/dts/mpc8548cds.dts
arch/powerpc/boot/dts/mpc8569mds.dts
arch/powerpc/boot/dts/p2020rdb.dts [new file with mode: 0644]
arch/powerpc/boot/dts/sbc8349.dts
arch/powerpc/boot/dts/sbc8560.dts
arch/powerpc/boot/mktree.c
arch/powerpc/boot/ppcboot-hotfoot.h [new file with mode: 0644]
arch/powerpc/boot/wrapper
arch/powerpc/configs/40x/kilauea_defconfig
arch/powerpc/configs/44x/arches_defconfig
arch/powerpc/configs/44x/canyonlands_defconfig
arch/powerpc/configs/44x/eiger_defconfig [new file with mode: 0644]
arch/powerpc/configs/83xx/sbc834x_defconfig
arch/powerpc/configs/mgcoge_defconfig
arch/powerpc/configs/mpc85xx_defconfig
arch/powerpc/include/asm/agp.h
arch/powerpc/include/asm/bitops.h
arch/powerpc/include/asm/cell-regs.h
arch/powerpc/include/asm/cputhreads.h
arch/powerpc/include/asm/device.h
arch/powerpc/include/asm/dma-mapping.h
arch/powerpc/include/asm/exception-64e.h [new file with mode: 0644]
arch/powerpc/include/asm/exception-64s.h [new file with mode: 0644]
arch/powerpc/include/asm/exception.h [deleted file]
arch/powerpc/include/asm/hardirq.h
arch/powerpc/include/asm/hw_irq.h
arch/powerpc/include/asm/iommu.h
arch/powerpc/include/asm/irq.h
arch/powerpc/include/asm/machdep.h
arch/powerpc/include/asm/mmu-40x.h
arch/powerpc/include/asm/mmu-44x.h
arch/powerpc/include/asm/mmu-8xx.h
arch/powerpc/include/asm/mmu-book3e.h
arch/powerpc/include/asm/mmu-hash32.h
arch/powerpc/include/asm/mmu-hash64.h
arch/powerpc/include/asm/mmu.h
arch/powerpc/include/asm/mmu_context.h
arch/powerpc/include/asm/nvram.h
arch/powerpc/include/asm/paca.h
arch/powerpc/include/asm/page.h
arch/powerpc/include/asm/page_64.h
arch/powerpc/include/asm/pci-bridge.h
arch/powerpc/include/asm/pci.h
arch/powerpc/include/asm/pgalloc.h
arch/powerpc/include/asm/pgtable-ppc32.h
arch/powerpc/include/asm/pgtable-ppc64-64k.h
arch/powerpc/include/asm/pgtable-ppc64.h
arch/powerpc/include/asm/pmc.h
arch/powerpc/include/asm/ppc-opcode.h
arch/powerpc/include/asm/ppc-pci.h
arch/powerpc/include/asm/ppc_asm.h
arch/powerpc/include/asm/pte-40x.h
arch/powerpc/include/asm/pte-44x.h
arch/powerpc/include/asm/pte-8xx.h
arch/powerpc/include/asm/pte-book3e.h [new file with mode: 0644]
arch/powerpc/include/asm/pte-common.h
arch/powerpc/include/asm/pte-fsl-booke.h
arch/powerpc/include/asm/pte-hash32.h
arch/powerpc/include/asm/reg.h
arch/powerpc/include/asm/reg_booke.h
arch/powerpc/include/asm/setup.h
arch/powerpc/include/asm/smp.h
arch/powerpc/include/asm/swiotlb.h
arch/powerpc/include/asm/systbl.h
arch/powerpc/include/asm/tlb.h
arch/powerpc/include/asm/tlbflush.h
arch/powerpc/include/asm/vdso.h
arch/powerpc/kernel/Makefile
arch/powerpc/kernel/asm-offsets.c
arch/powerpc/kernel/cpu_setup_6xx.S
arch/powerpc/kernel/cputable.c
arch/powerpc/kernel/dma-iommu.c
arch/powerpc/kernel/dma-swiotlb.c
arch/powerpc/kernel/dma.c
arch/powerpc/kernel/entry_32.S
arch/powerpc/kernel/entry_64.S
arch/powerpc/kernel/exceptions-64e.S [new file with mode: 0644]
arch/powerpc/kernel/exceptions-64s.S
arch/powerpc/kernel/fpu.S
arch/powerpc/kernel/head_32.S
arch/powerpc/kernel/head_40x.S
arch/powerpc/kernel/head_44x.S
arch/powerpc/kernel/head_64.S
arch/powerpc/kernel/head_8xx.S
arch/powerpc/kernel/head_booke.h
arch/powerpc/kernel/head_fsl_booke.S
arch/powerpc/kernel/ibmebus.c
arch/powerpc/kernel/lparcfg.c
arch/powerpc/kernel/misc_32.S
arch/powerpc/kernel/of_platform.c
arch/powerpc/kernel/paca.c
arch/powerpc/kernel/pci-common.c
arch/powerpc/kernel/pci_32.c
arch/powerpc/kernel/pci_64.c
arch/powerpc/kernel/pci_of_scan.c [new file with mode: 0644]
arch/powerpc/kernel/perf_counter.c
arch/powerpc/kernel/process.c
arch/powerpc/kernel/prom_init.c
arch/powerpc/kernel/rtas.c
arch/powerpc/kernel/setup_32.c
arch/powerpc/kernel/setup_64.c
arch/powerpc/kernel/smp.c
arch/powerpc/kernel/sys_ppc32.c
arch/powerpc/kernel/sysfs.c
arch/powerpc/kernel/time.c
arch/powerpc/kernel/vdso.c
arch/powerpc/kernel/vdso32/Makefile
arch/powerpc/kernel/vdso64/Makefile
arch/powerpc/kernel/vector.S
arch/powerpc/kernel/vio.c
arch/powerpc/kernel/vmlinux.lds.S
arch/powerpc/kvm/booke_interrupts.S
arch/powerpc/mm/40x_mmu.c
arch/powerpc/mm/Makefile
arch/powerpc/mm/fsl_booke_mmu.c
arch/powerpc/mm/hash_low_32.S
arch/powerpc/mm/hugetlbpage.c
arch/powerpc/mm/init_32.c
arch/powerpc/mm/init_64.c
arch/powerpc/mm/mmu_context_nohash.c
arch/powerpc/mm/mmu_decl.h
arch/powerpc/mm/pgtable.c
arch/powerpc/mm/pgtable_32.c
arch/powerpc/mm/pgtable_64.c
arch/powerpc/mm/slb.c
arch/powerpc/mm/stab.c
arch/powerpc/mm/tlb_hash32.c
arch/powerpc/mm/tlb_hash64.c
arch/powerpc/mm/tlb_low_64e.S [new file with mode: 0644]
arch/powerpc/mm/tlb_nohash.c
arch/powerpc/mm/tlb_nohash_low.S
arch/powerpc/platforms/40x/Kconfig
arch/powerpc/platforms/40x/ppc40x_simple.c
arch/powerpc/platforms/44x/Kconfig
arch/powerpc/platforms/44x/ppc44x_simple.c
arch/powerpc/platforms/82xx/mgcoge.c
arch/powerpc/platforms/82xx/mpc8272_ads.c
arch/powerpc/platforms/83xx/Kconfig
arch/powerpc/platforms/83xx/mpc837x_rdb.c
arch/powerpc/platforms/83xx/mpc83xx.h
arch/powerpc/platforms/85xx/Kconfig
arch/powerpc/platforms/85xx/Makefile
arch/powerpc/platforms/85xx/mpc8536_ds.c
arch/powerpc/platforms/85xx/mpc85xx_ds.c
arch/powerpc/platforms/85xx/mpc85xx_mds.c
arch/powerpc/platforms/85xx/mpc85xx_rdb.c [new file with mode: 0644]
arch/powerpc/platforms/85xx/sbc8560.c
arch/powerpc/platforms/85xx/smp.c
arch/powerpc/platforms/86xx/gef_ppc9a.c
arch/powerpc/platforms/86xx/mpc86xx_hpcn.c
arch/powerpc/platforms/86xx/mpc86xx_smp.c
arch/powerpc/platforms/Kconfig.cputype
arch/powerpc/platforms/amigaone/setup.c
arch/powerpc/platforms/cell/Kconfig
arch/powerpc/platforms/cell/celleb_setup.c
arch/powerpc/platforms/cell/iommu.c
arch/powerpc/platforms/cell/smp.c
arch/powerpc/platforms/cell/spufs/Makefile
arch/powerpc/platforms/cell/spufs/context.c
arch/powerpc/platforms/cell/spufs/file.c
arch/powerpc/platforms/cell/spufs/sched.c
arch/powerpc/platforms/cell/spufs/spufs.h
arch/powerpc/platforms/cell/spufs/sputrace.c [deleted file]
arch/powerpc/platforms/cell/spufs/sputrace.h [new file with mode: 0644]
arch/powerpc/platforms/iseries/exception.S
arch/powerpc/platforms/iseries/exception.h
arch/powerpc/platforms/iseries/mf.c
arch/powerpc/platforms/pasemi/idle.c
arch/powerpc/platforms/powermac/cpufreq_32.c
arch/powerpc/platforms/powermac/feature.c
arch/powerpc/platforms/powermac/pci.c
arch/powerpc/platforms/powermac/smp.c
arch/powerpc/platforms/ps3/mm.c
arch/powerpc/platforms/ps3/smp.c
arch/powerpc/platforms/ps3/system-bus.c
arch/powerpc/platforms/pseries/pci_dlpar.c
arch/powerpc/platforms/pseries/reconfig.c
arch/powerpc/platforms/pseries/setup.c
arch/powerpc/platforms/pseries/smp.c
arch/powerpc/sysdev/fsl_rio.c
arch/powerpc/sysdev/fsl_soc.c
arch/powerpc/sysdev/ipic.c
arch/powerpc/sysdev/mmio_nvram.c
arch/powerpc/sysdev/mpic.c
arch/powerpc/sysdev/qe_lib/gpio.c
arch/powerpc/sysdev/qe_lib/qe_ic.c
arch/powerpc/xmon/Makefile
arch/powerpc/xmon/xmon.c
arch/s390/include/asm/percpu.h
arch/s390/kernel/vmlinux.lds.S
arch/sh/kernel/vmlinux.lds.S
arch/sparc/Kconfig
arch/sparc/include/asm/agp.h
arch/sparc/kernel/smp_64.c
arch/sparc/kernel/vmlinux.lds.S
arch/um/include/asm/common.lds.S
arch/um/kernel/dyn.lds.S
arch/um/kernel/uml.lds.S
arch/x86/Kconfig
arch/x86/include/asm/agp.h
arch/x86/include/asm/bootparam.h
arch/x86/include/asm/cacheflush.h
arch/x86/include/asm/fixmap.h
arch/x86/include/asm/iomap.h
arch/x86/include/asm/mtrr.h
arch/x86/include/asm/pat.h
arch/x86/include/asm/percpu.h
arch/x86/kernel/Makefile
arch/x86/kernel/cpu/cpu_debug.c
arch/x86/kernel/cpu/mcheck/mce.c
arch/x86/kernel/cpu/mcheck/mce_amd.c
arch/x86/kernel/cpu/mtrr/main.c
arch/x86/kernel/cpu/perf_counter.c
arch/x86/kernel/reboot.c
arch/x86/kernel/setup.c
arch/x86/kernel/setup_percpu.c
arch/x86/kernel/smpboot.c
arch/x86/kernel/tboot.c [new file with mode: 0644]
arch/x86/kernel/vmlinux.lds.S
arch/x86/mm/iomap_32.c
arch/x86/mm/ioremap.c
arch/x86/mm/pageattr.c
arch/x86/mm/pat.c
arch/x86/power/cpu.c
arch/xtensa/kernel/vmlinux.lds.S
block/as-iosched.c
block/cfq-iosched.c
drivers/acpi/acpica/hwsleep.c
drivers/block/ps3vram.c
drivers/char/agp/agp.h
drivers/char/agp/ali-agp.c
drivers/char/agp/amd-k7-agp.c
drivers/char/agp/amd64-agp.c
drivers/char/agp/ati-agp.c
drivers/char/agp/backend.c
drivers/char/agp/efficeon-agp.c
drivers/char/agp/generic.c
drivers/char/agp/hp-agp.c
drivers/char/agp/i460-agp.c
drivers/char/agp/intel-agp.c
drivers/char/agp/nvidia-agp.c
drivers/char/agp/parisc-agp.c
drivers/char/agp/sgi-agp.c
drivers/char/agp/sworks-agp.c
drivers/char/agp/uninorth-agp.c
drivers/char/generic_nvram.c
drivers/char/hvc_console.c
drivers/char/hvc_vio.c
drivers/char/hvsi.c
drivers/cpufreq/cpufreq_conservative.c
drivers/cpufreq/cpufreq_ondemand.c
drivers/ide/at91_ide.c
drivers/ide/ide-cd.c
drivers/ide/ide-disk_proc.c
drivers/ide/ide-floppy_proc.c
drivers/ide/ide-ioctls.c
drivers/ide/ide-iops.c
drivers/ide/ide-probe.c
drivers/ide/ide-proc.c
drivers/ide/ide-tape.c
drivers/ide/ide-taskfile.c
drivers/ide/palm_bk3710.c
drivers/input/keyboard/pxa27x_keypad.c
drivers/macintosh/macio_asic.c
drivers/macintosh/therm_windtunnel.c
drivers/media/common/ir-functions.c
drivers/media/common/ir-keymaps.c
drivers/media/common/tuners/tda18271-fe.c
drivers/media/common/tuners/tda18271-priv.h
drivers/media/common/tuners/tda18271.h
drivers/media/common/tuners/tuner-simple.c
drivers/media/common/tuners/tuner-types.c
drivers/media/dvb/Kconfig
drivers/media/dvb/b2c2/flexcop-fe-tuner.c
drivers/media/dvb/bt8xx/dst.c
drivers/media/dvb/dm1105/dm1105.c
drivers/media/dvb/dvb-core/dmxdev.c
drivers/media/dvb/dvb-core/dmxdev.h
drivers/media/dvb/dvb-core/dvb_demux.c
drivers/media/dvb/dvb-core/dvb_frontend.c
drivers/media/dvb/dvb-core/dvbdev.h
drivers/media/dvb/dvb-usb/Kconfig
drivers/media/dvb/dvb-usb/a800.c
drivers/media/dvb/dvb-usb/af9005-remote.c
drivers/media/dvb/dvb-usb/af9015.c
drivers/media/dvb/dvb-usb/af9015.h
drivers/media/dvb/dvb-usb/anysee.c
drivers/media/dvb/dvb-usb/cinergyT2-core.c
drivers/media/dvb/dvb-usb/cinergyT2-fe.c
drivers/media/dvb/dvb-usb/cxusb.c
drivers/media/dvb/dvb-usb/dib0700_devices.c
drivers/media/dvb/dvb-usb/dibusb-common.c
drivers/media/dvb/dvb-usb/dibusb-mc.c
drivers/media/dvb/dvb-usb/digitv.c
drivers/media/dvb/dvb-usb/dtt200u.c
drivers/media/dvb/dvb-usb/dvb-usb-i2c.c
drivers/media/dvb/dvb-usb/dvb-usb-ids.h
drivers/media/dvb/dvb-usb/dvb-usb-remote.c
drivers/media/dvb/dvb-usb/dvb-usb.h
drivers/media/dvb/dvb-usb/dw2102.c
drivers/media/dvb/dvb-usb/m920x.c
drivers/media/dvb/dvb-usb/nova-t-usb2.c
drivers/media/dvb/dvb-usb/opera1.c
drivers/media/dvb/dvb-usb/vp702x.c
drivers/media/dvb/dvb-usb/vp7045.c
drivers/media/dvb/firewire/firedtv-avc.c
drivers/media/dvb/frontends/Kconfig
drivers/media/dvb/frontends/Makefile
drivers/media/dvb/frontends/cx22700.c
drivers/media/dvb/frontends/cx24113.c
drivers/media/dvb/frontends/cx24123.c
drivers/media/dvb/frontends/dib0070.c
drivers/media/dvb/frontends/dib7000p.c
drivers/media/dvb/frontends/dvb-pll.c
drivers/media/dvb/frontends/dvb-pll.h
drivers/media/dvb/frontends/lgs8gxx.c
drivers/media/dvb/frontends/lgs8gxx.h
drivers/media/dvb/frontends/lgs8gxx_priv.h
drivers/media/dvb/frontends/mt312.c
drivers/media/dvb/frontends/stb6100.c
drivers/media/dvb/frontends/stv0900_core.c
drivers/media/dvb/frontends/stv0900_sw.c
drivers/media/dvb/frontends/stv6110.c
drivers/media/dvb/frontends/stv6110.h
drivers/media/dvb/frontends/tda10021.c
drivers/media/dvb/frontends/tda8261.c
drivers/media/dvb/frontends/ves1820.c
drivers/media/dvb/frontends/zl10036.c
drivers/media/dvb/frontends/zl10039.c [new file with mode: 0644]
drivers/media/dvb/frontends/zl10039.h [new file with mode: 0644]
drivers/media/dvb/frontends/zl10353.c
drivers/media/dvb/pluto2/pluto2.c
drivers/media/dvb/ttpci/av7110_v4l.c
drivers/media/dvb/ttpci/budget-ci.c
drivers/media/radio/Kconfig
drivers/media/radio/Makefile
drivers/media/radio/radio-cadet.c
drivers/media/radio/radio-si470x.c [deleted file]
drivers/media/radio/radio-si4713.c [new file with mode: 0644]
drivers/media/radio/si470x/Kconfig [new file with mode: 0644]
drivers/media/radio/si470x/Makefile [new file with mode: 0644]
drivers/media/radio/si470x/radio-si470x-common.c [new file with mode: 0644]
drivers/media/radio/si470x/radio-si470x-i2c.c [new file with mode: 0644]
drivers/media/radio/si470x/radio-si470x-usb.c [new file with mode: 0644]
drivers/media/radio/si470x/radio-si470x.h [new file with mode: 0644]
drivers/media/radio/si4713-i2c.c [new file with mode: 0644]
drivers/media/radio/si4713-i2c.h [new file with mode: 0644]
drivers/media/video/Kconfig
drivers/media/video/au0828/au0828-dvb.c
drivers/media/video/au0828/au0828-i2c.c
drivers/media/video/bt8xx/bttv-cards.c
drivers/media/video/bt8xx/bttv-driver.c
drivers/media/video/bt8xx/bttv-i2c.c
drivers/media/video/bt8xx/bttv-input.c
drivers/media/video/cafe_ccic.c
drivers/media/video/cx18/cx18-cards.c
drivers/media/video/cx18/cx18-cards.h
drivers/media/video/cx18/cx18-driver.c
drivers/media/video/cx18/cx18-fileops.c
drivers/media/video/cx18/cx18-i2c.c
drivers/media/video/cx18/cx18-ioctl.c
drivers/media/video/cx231xx/cx231xx-conf-reg.h
drivers/media/video/cx231xx/cx231xx-i2c.c
drivers/media/video/cx231xx/cx231xx-video.c
drivers/media/video/cx231xx/cx231xx.h
drivers/media/video/cx23885/cimax2.c
drivers/media/video/cx23885/cx23885-417.c
drivers/media/video/cx23885/cx23885-cards.c
drivers/media/video/cx23885/cx23885-core.c
drivers/media/video/cx23885/cx23885-dvb.c
drivers/media/video/cx23885/cx23885-i2c.c
drivers/media/video/cx23885/cx23885.h
drivers/media/video/cx25840/cx25840-core.c
drivers/media/video/cx25840/cx25840-firmware.c
drivers/media/video/cx88/cx88-cards.c
drivers/media/video/cx88/cx88-dvb.c
drivers/media/video/cx88/cx88-input.c
drivers/media/video/cx88/cx88.h
drivers/media/video/em28xx/em28xx-cards.c
drivers/media/video/em28xx/em28xx-i2c.c
drivers/media/video/em28xx/em28xx-video.c
drivers/media/video/em28xx/em28xx.h
drivers/media/video/gspca/Kconfig
drivers/media/video/gspca/Makefile
drivers/media/video/gspca/conex.c
drivers/media/video/gspca/etoms.c
drivers/media/video/gspca/gspca.c
drivers/media/video/gspca/gspca.h
drivers/media/video/gspca/jeilinj.c [new file with mode: 0644]
drivers/media/video/gspca/m5602/m5602_s5k83a.c
drivers/media/video/gspca/mr97310a.c
drivers/media/video/gspca/pac207.c
drivers/media/video/gspca/pac7311.c
drivers/media/video/gspca/sn9c20x.c
drivers/media/video/gspca/sonixj.c
drivers/media/video/gspca/spca501.c
drivers/media/video/gspca/spca506.c
drivers/media/video/gspca/spca508.c
drivers/media/video/gspca/stv06xx/stv06xx.c
drivers/media/video/gspca/sunplus.c
drivers/media/video/gspca/t613.c
drivers/media/video/gspca/tv8532.c
drivers/media/video/gspca/vc032x.c
drivers/media/video/gspca/zc3xx.c
drivers/media/video/hdpvr/hdpvr-control.c
drivers/media/video/hdpvr/hdpvr-core.c
drivers/media/video/hdpvr/hdpvr-i2c.c
drivers/media/video/hdpvr/hdpvr-video.c
drivers/media/video/ir-kbd-i2c.c
drivers/media/video/ivtv/ivtv-cards.c
drivers/media/video/ivtv/ivtv-cards.h
drivers/media/video/ivtv/ivtv-driver.c
drivers/media/video/ivtv/ivtv-gpio.c
drivers/media/video/ivtv/ivtv-i2c.c
drivers/media/video/meye.c
drivers/media/video/pvrusb2/pvrusb2-audio.c
drivers/media/video/pvrusb2/pvrusb2-i2c-core.c
drivers/media/video/pwc/pwc-if.c
drivers/media/video/pwc/pwc-v4l.c
drivers/media/video/pwc/pwc.h
drivers/media/video/saa6588.c
drivers/media/video/saa7134/Kconfig
drivers/media/video/saa7134/saa6752hs.c
drivers/media/video/saa7134/saa7134-alsa.c
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-input.c
drivers/media/video/saa7134/saa7134-video.c
drivers/media/video/saa7134/saa7134.h
drivers/media/video/sn9c102/sn9c102_devtable.h
drivers/media/video/stk-webcam.c
drivers/media/video/stv680.c
drivers/media/video/tuner-core.c
drivers/media/video/tveeprom.c
drivers/media/video/uvc/uvc_ctrl.c
drivers/media/video/uvc/uvc_driver.c
drivers/media/video/uvc/uvc_isight.c
drivers/media/video/uvc/uvc_v4l2.c
drivers/media/video/uvc/uvc_video.c
drivers/media/video/uvc/uvcvideo.h
drivers/media/video/v4l1-compat.c
drivers/media/video/v4l2-common.c
drivers/media/video/v4l2-compat-ioctl32.c
drivers/media/video/v4l2-ioctl.c
drivers/media/video/vino.c
drivers/media/video/w9968cf.c
drivers/media/video/zoran/zoran_card.c
drivers/media/video/zr364xx.c
drivers/mtd/chips/cfi_cmdset_0001.c
drivers/mtd/chips/cfi_cmdset_0020.c
drivers/mtd/maps/bfin-async-flash.c
drivers/mtd/maps/ceiva.c
drivers/mtd/maps/dc21285.c
drivers/mtd/maps/ipaq-flash.c
drivers/mtd/maps/pxa2xx-flash.c
drivers/mtd/maps/sa1100-flash.c
drivers/mtd/mtdblock.c
drivers/mtd/mtdpart.c
drivers/net/smc91x.c
drivers/net/smc91x.h
drivers/pci/dmar.c
drivers/pci/intel-iommu.c
drivers/ps3/ps3stor_lib.c
drivers/rtc/rtc-sa1100.c
drivers/video/ps3fb.c
drivers/video/sa1100fb.c
drivers/xen/events.c
fs/afs/write.c
fs/block_dev.c
fs/btrfs/disk-io.c
fs/btrfs/ordered-data.c
fs/fs-writeback.c
fs/fuse/inode.c
fs/inode.c
fs/jbd2/commit.c
fs/nfs/super.c
fs/nfs/write.c
fs/nilfs2/the_nilfs.c
fs/super.c
fs/sync.c
fs/ubifs/budget.c
fs/ubifs/super.c
include/asm-generic/vmlinux.lds.h
include/linux/agp_backend.h
include/linux/backing-dev.h
include/linux/dma-mapping.h
include/linux/dvb/dmx.h
include/linux/fs.h
include/linux/ide.h
include/linux/io-mapping.h
include/linux/mtd/partitions.h
include/linux/page-flags.h
include/linux/pci_ids.h
include/linux/percpu-defs.h
include/linux/percpu.h
include/linux/tboot.h [new file with mode: 0644]
include/linux/usb/video.h [new file with mode: 0644]
include/linux/videodev2.h
include/linux/vmalloc.h
include/linux/writeback.h
include/media/ir-common.h
include/media/ir-kbd-i2c.h
include/media/radio-si4713.h [new file with mode: 0644]
include/media/si4713.h [new file with mode: 0644]
include/media/tuner.h
include/media/v4l2-subdev.h
include/trace/events/ext4.h
init/main.c
kernel/cpu.c
kernel/gcov/Kconfig
kernel/module.c
kernel/perf_counter.c
kernel/sched.c
kernel/smp.c
kernel/trace/trace_events.c
lib/Kconfig.debug
lib/inflate.c
mm/Kconfig
mm/Makefile
mm/allocpercpu.c
mm/backing-dev.c
mm/kmemleak-test.c
mm/page-writeback.c
mm/percpu.c
mm/quicklist.c
mm/slub.c
mm/vmalloc.c
net/ipv4/syncookies.c
net/ipv6/syncookies.c
net/rds/ib_stats.c
net/rds/iw_stats.c
net/rds/page.c
scripts/module-common.lds [new file with mode: 0644]
security/Kconfig

diff --git a/CREDITS b/CREDITS
index 1a41bf4addd0689c9bd7243c80712ee409da9310..72b487869788c14cd40e9535b700f4be166aa12b 100644 (file)
--- a/CREDITS
+++ b/CREDITS
@@ -2800,7 +2800,7 @@ D: Starter of Linux1394 effort
 S: ask per mail for current address
 
 N: Nicolas Pitre
-E: nico@cam.org
+E: nico@fluxnic.net
 D: StrongARM SA1100 support integrator & hacker
 D: Xscale PXA architecture
 D: unified SMC 91C9x/91C11x ethernet driver (smc91x)
index ab47c3833908c67ff71d8c65569707859099fcf1..7197a9e958ee259a77428ca27a3cd5f143ec4dfd 100644 (file)
@@ -40,4 +40,4 @@ Notes:
   mode, the timing is off so the image is corrupted.  This will be
   fixed soon.
 
-Any contribution can be sent to nico@cam.org and will be greatly welcome!
+Any contribution can be sent to nico@fluxnic.net and will be greatly welcome!
index 78bc1c1b04e58596d118d0f601914ad0cba9a3ce..91f7ce7ba426b39dc319b54cbc83fda7ec97554e 100644 (file)
@@ -240,7 +240,7 @@ Then, rebooting the Assabet is just a matter of waiting for the login prompt.
 
 
 Nicolas Pitre
-nico@cam.org
+nico@fluxnic.net
 June 12, 2001
 
 
index 2254c8f0b326958e713d4e47397b322699fafeb8..b1cfd405dccc599378139c1b7093919f696f258c 100644 (file)
@@ -60,7 +60,7 @@ little modifications.
 
 Any contribution is welcome.
 
-Please send patches to nico@cam.org
+Please send patches to nico@fluxnic.net
 
 Have Fun !
 
index 8fa7e8027ff13ec2230ab6117ea8821b1a08f4ab..6c9c4f5a36e17fe6c5e3700483aa71811f261952 100644 (file)
@@ -4,7 +4,7 @@ For more details, contact Applied Data Systems or see
 http://www.applieddata.net/products.html
 
 The original Linux support for this product has been provided by 
-Nicolas Pitre <nico@cam.org>. Continued development work by
+Nicolas Pitre <nico@fluxnic.net>. Continued development work by
 Woojung Huh <whuh@applieddata.net>
 
 It's currently possible to mount a root filesystem via NFS providing a
@@ -94,5 +94,5 @@ Notes:
   mode, the timing is off so the image is corrupted.  This will be
   fixed soon.
 
-Any contribution can be sent to nico@cam.org and will be greatly welcome!
+Any contribution can be sent to nico@fluxnic.net and will be greatly welcome!
 
index dd28745ac52169a176e1a2f9d91f9629000f53f1..ee7c6595f23fbbc48bd6526701bcdbacbd646249 100644 (file)
@@ -4,7 +4,7 @@ For more details, contact Applied Data Systems or see
 http://www.applieddata.net/products.html
 
 The original Linux support for this product has been provided by
-Nicolas Pitre <nico@cam.org>. Continued development work by
+Nicolas Pitre <nico@fluxnic.net>. Continued development work by
 Woojung Huh <whuh@applieddata.net>
 
 Use 'make graphicsmaster_config' before any 'make config'.
@@ -50,4 +50,4 @@ Notes:
   mode, the timing is off so the image is corrupted.  This will be
   fixed soon.
 
-Any contribution can be sent to nico@cam.org and will be greatly welcome!
+Any contribution can be sent to nico@fluxnic.net and will be greatly welcome!
index 01e81fc49461dab8ba1979973b40371e46cdfb67..f938a29fdc20f8c7a9ddbcbfc6036f69923b2e75 100644 (file)
@@ -9,7 +9,7 @@ Of course Victor is using Linux as its main operating system.
 The Victor implementation for Linux is maintained by Nicolas Pitre:
 
        nico@visuaide.com
-       nico@cam.org
+       nico@fluxnic.net
 
 For any comments, please feel free to contact me through the above
 addresses.
diff --git a/Documentation/intel_txt.txt b/Documentation/intel_txt.txt
new file mode 100644 (file)
index 0000000..f40a1f0
--- /dev/null
@@ -0,0 +1,210 @@
+Intel(R) TXT Overview:
+=====================
+
+Intel's technology for safer computing, Intel(R) Trusted Execution
+Technology (Intel(R) TXT), defines platform-level enhancements that
+provide the building blocks for creating trusted platforms.
+
+Intel TXT was formerly known by the code name LaGrande Technology (LT).
+
+Intel TXT in Brief:
+o  Provides dynamic root of trust for measurement (DRTM)
+o  Data protection in case of improper shutdown
+o  Measurement and verification of launched environment
+
+Intel TXT is part of the vPro(TM) brand and is also available some
+non-vPro systems.  It is currently available on desktop systems
+based on the Q35, X38, Q45, and Q43 Express chipsets (e.g. Dell
+Optiplex 755, HP dc7800, etc.) and mobile systems based on the GM45,
+PM45, and GS45 Express chipsets.
+
+For more information, see http://www.intel.com/technology/security/.
+This site also has a link to the Intel TXT MLE Developers Manual,
+which has been updated for the new released platforms.
+
+Intel TXT has been presented at various events over the past few
+years, some of which are:
+      LinuxTAG 2008:
+          http://www.linuxtag.org/2008/en/conf/events/vp-donnerstag/
+          details.html?talkid=110
+      TRUST2008:
+          http://www.trust2008.eu/downloads/Keynote-Speakers/
+          3_David-Grawrock_The-Front-Door-of-Trusted-Computing.pdf
+      IDF 2008, Shanghai:
+          http://inteldeveloperforum.com.edgesuite.net/shanghai_2008/
+          aep/PROS003/index.html
+      IDFs 2006, 2007 (I'm not sure if/where they are online)
+
+Trusted Boot Project Overview:
+=============================
+
+Trusted Boot (tboot) is an open source, pre- kernel/VMM module that
+uses Intel TXT to perform a measured and verified launch of an OS
+kernel/VMM.
+
+It is hosted on SourceForge at http://sourceforge.net/projects/tboot.
+The mercurial source repo is available at http://www.bughost.org/
+repos.hg/tboot.hg.
+
+Tboot currently supports launching Xen (open source VMM/hypervisor
+w/ TXT support since v3.2), and now Linux kernels.
+
+
+Value Proposition for Linux or "Why should you care?"
+=====================================================
+
+While there are many products and technologies that attempt to
+measure or protect the integrity of a running kernel, they all
+assume the kernel is "good" to begin with.  The Integrity
+Measurement Architecture (IMA) and Linux Integrity Module interface
+are examples of such solutions.
+
+To get trust in the initial kernel without using Intel TXT, a
+static root of trust must be used.  This bases trust in BIOS
+starting at system reset and requires measurement of all code
+executed between system reset through the completion of the kernel
+boot as well as data objects used by that code.  In the case of a
+Linux kernel, this means all of BIOS, any option ROMs, the
+bootloader and the boot config.  In practice, this is a lot of
+code/data, much of which is subject to change from boot to boot
+(e.g. changing NICs may change option ROMs).  Without reference
+hashes, these measurement changes are difficult to assess or
+confirm as benign.  This process also does not provide DMA
+protection, memory configuration/alias checks and locks, crash
+protection, or policy support.
+
+By using the hardware-based root of trust that Intel TXT provides,
+many of these issues can be mitigated.  Specifically: many
+pre-launch components can be removed from the trust chain, DMA
+protection is provided to all launched components, a large number
+of platform configuration checks are performed and values locked,
+protection is provided for any data in the event of an improper
+shutdown, and there is support for policy-based execution/verification.
+This provides a more stable measurement and a higher assurance of
+system configuration and initial state than would be otherwise
+possible.  Since the tboot project is open source, source code for
+almost all parts of the trust chain is available (excepting SMM and
+Intel-provided firmware).
+
+How Does it Work?
+=================
+
+o  Tboot is an executable that is launched by the bootloader as
+   the "kernel" (the binary the bootloader executes).
+o  It performs all of the work necessary to determine if the
+   platform supports Intel TXT and, if so, executes the GETSEC[SENTER]
+   processor instruction that initiates the dynamic root of trust.
+   -  If tboot determines that the system does not support Intel TXT
+      or is not configured correctly (e.g. the SINIT AC Module was
+      incorrect), it will directly launch the kernel with no changes
+      to any state.
+   -  Tboot will output various information about its progress to the
+      terminal, serial port, and/or an in-memory log; the output
+      locations can be configured with a command line switch.
+o  The GETSEC[SENTER] instruction will return control to tboot and
+   tboot then verifies certain aspects of the environment (e.g. TPM NV
+   lock, e820 table does not have invalid entries, etc.).
+o  It will wake the APs from the special sleep state the GETSEC[SENTER]
+   instruction had put them in and place them into a wait-for-SIPI
+   state.
+   -  Because the processors will not respond to an INIT or SIPI when
+      in the TXT environment, it is necessary to create a small VT-x
+      guest for the APs.  When they run in this guest, they will
+      simply wait for the INIT-SIPI-SIPI sequence, which will cause
+      VMEXITs, and then disable VT and jump to the SIPI vector.  This
+      approach seemed like a better choice than having to insert
+      special code into the kernel's MP wakeup sequence.
+o  Tboot then applies an (optional) user-defined launch policy to
+   verify the kernel and initrd.
+   -  This policy is rooted in TPM NV and is described in the tboot
+      project.  The tboot project also contains code for tools to
+      create and provision the policy.
+   -  Policies are completely under user control and if not present
+      then any kernel will be launched.
+   -  Policy action is flexible and can include halting on failures
+      or simply logging them and continuing.
+o  Tboot adjusts the e820 table provided by the bootloader to reserve
+   its own location in memory as well as to reserve certain other
+   TXT-related regions.
+o  As part of it's launch, tboot DMA protects all of RAM (using the
+   VT-d PMRs).  Thus, the kernel must be booted with 'intel_iommu=on'
+   in order to remove this blanket protection and use VT-d's
+   page-level protection.
+o  Tboot will populate a shared page with some data about itself and
+   pass this to the Linux kernel as it transfers control.
+   -  The location of the shared page is passed via the boot_params
+      struct as a physical address.
+o  The kernel will look for the tboot shared page address and, if it
+   exists, map it.
+o  As one of the checks/protections provided by TXT, it makes a copy
+   of the VT-d DMARs in a DMA-protected region of memory and verifies
+   them for correctness.  The VT-d code will detect if the kernel was
+   launched with tboot and use this copy instead of the one in the
+   ACPI table.
+o  At this point, tboot and TXT are out of the picture until a
+   shutdown (S<n>)
+o  In order to put a system into any of the sleep states after a TXT
+   launch, TXT must first be exited.  This is to prevent attacks that
+   attempt to crash the system to gain control on reboot and steal
+   data left in memory.
+   -  The kernel will perform all of its sleep preparation and
+      populate the shared page with the ACPI data needed to put the
+      platform in the desired sleep state.
+   -  Then the kernel jumps into tboot via the vector specified in the
+      shared page.
+   -  Tboot will clean up the environment and disable TXT, then use the
+      kernel-provided ACPI information to actually place the platform
+      into the desired sleep state.
+   -  In the case of S3, tboot will also register itself as the resume
+      vector.  This is necessary because it must re-establish the
+      measured environment upon resume.  Once the TXT environment
+      has been restored, it will restore the TPM PCRs and then
+      transfer control back to the kernel's S3 resume vector.
+      In order to preserve system integrity across S3, the kernel
+      provides tboot with a set of memory ranges (kernel
+      code/data/bss, S3 resume code, and AP trampoline) that tboot
+      will calculate a MAC (message authentication code) over and then
+      seal with the TPM.  On resume and once the measured environment
+      has been re-established, tboot will re-calculate the MAC and
+      verify it against the sealed value.  Tboot's policy determines
+      what happens if the verification fails.
+
+That's pretty much it for TXT support.
+
+
+Configuring the System:
+======================
+
+This code works with 32bit, 32bit PAE, and 64bit (x86_64) kernels.
+
+In BIOS, the user must enable:  TPM, TXT, VT-x, VT-d.  Not all BIOSes
+allow these to be individually enabled/disabled and the screens in
+which to find them are BIOS-specific.
+
+grub.conf needs to be modified as follows:
+        title Linux 2.6.29-tip w/ tboot
+          root (hd0,0)
+                kernel /tboot.gz logging=serial,vga,memory
+                module /vmlinuz-2.6.29-tip intel_iommu=on ro
+                       root=LABEL=/ rhgb console=ttyS0,115200 3
+                module /initrd-2.6.29-tip.img
+                module /Q35_SINIT_17.BIN
+
+The kernel option for enabling Intel TXT support is found under the
+Security top-level menu and is called "Enable Intel(R) Trusted
+Execution Technology (TXT)".  It is marked as EXPERIMENTAL and
+depends on the generic x86 support (to allow maximum flexibility in
+kernel build options), since the tboot code will detect whether the
+platform actually supports Intel TXT and thus whether any of the
+kernel code is executed.
+
+The Q35_SINIT_17.BIN file is what Intel TXT refers to as an
+Authenticated Code Module.  It is specific to the chipset in the
+system and can also be found on the Trusted Boot site.  It is an
+(unencrypted) module signed by Intel that is used as part of the
+DRTM process to verify and configure the system.  It is signed
+because it operates at a higher privilege level in the system than
+any other macrocode and its correct operation is critical to the
+establishment of the DRTM.  The process for determining the correct
+SINIT ACM for a system is documented in the SINIT-guide.txt file
+that is on the tboot SourceForge site under the SINIT ACM downloads.
index 3a238644c81182571e63f6065fcfe9ccac988d98..4c12a290bee52a00186e4a4e4c4d726996320d8e 100644 (file)
@@ -1971,11 +1971,12 @@ and is between 256 and 4096 characters. It is defined in the file
                        Format: { 0 | 1 }
                        See arch/parisc/kernel/pdc_chassis.c
 
-       percpu_alloc=   [X86] Select which percpu first chunk allocator to use.
-                       Allowed values are one of "lpage", "embed" and "4k".
-                       See comments in arch/x86/kernel/setup_percpu.c for
-                       details on each allocator.  This parameter is primarily
-                       for debugging and performance comparison.
+       percpu_alloc=   Select which percpu first chunk allocator to use.
+                       Currently supported values are "embed" and "page".
+                       Archs may support subset or none of the selections.
+                       See comments in mm/percpu.c for details on each
+                       allocator.  This parameter is primarily for debugging
+                       and performance comparison.
 
        pf.             [PARIDE]
                        See Documentation/blockdev/paride.txt.
index 450b8f8c389bcb5eba41cc21515795429f0c2b5c..525edb37c758859d59dfb0e2c95bcef8039ce07d 100644 (file)
@@ -21,3 +21,5 @@
  20 -> Hauppauge WinTV-HVR1255                             [0070:2251]
  21 -> Hauppauge WinTV-HVR1210                             [0070:2291,0070:2295]
  22 -> Mygica X8506 DMB-TH                                 [14f1:8651]
+ 23 -> Magic-Pro ProHDTV Extreme 2                         [14f1:8657]
+ 24 -> Hauppauge WinTV-HVR1850                             [0070:8541]
index 0736518b2f8814114ecbf89d031b7d57ab757d7e..3385f8b094a5ef5a702c8b662e61b4052c846cc7 100644 (file)
@@ -80,3 +80,4 @@
  79 -> Terratec Cinergy HT PCI MKII                        [153b:1177]
  80 -> Hauppauge WinTV-IR Only                             [0070:9290]
  81 -> Leadtek WinFast DTV1800 Hybrid                      [107d:6654]
+ 82 -> WinFast DTV2000 H rev. J                            [107d:6f2b]
index e352d754875cae415b0c27d766336c00942cd241..b13fcbd5d94b198a176eecb11a72621c76df09eb 100644 (file)
@@ -7,7 +7,7 @@
   6 -> Terratec Cinergy 200 USB                 (em2800)
   7 -> Leadtek Winfast USB II                   (em2800)        [0413:6023]
   8 -> Kworld USB2800                           (em2800)
-  9 -> Pinnacle Dazzle DVC 90/100/101/107 / Kaiser Baas Video to DVD maker (em2820/em2840) [1b80:e302,2304:0207,2304:021a]
+  9 -> Pinnacle Dazzle DVC 90/100/101/107 / Kaiser Baas Video to DVD maker  (em2820/em2840) [1b80:e302,1b80:e304,2304:0207,2304:021a]
  10 -> Hauppauge WinTV HVR 900                  (em2880)        [2040:6500]
  11 -> Terratec Hybrid XS                       (em2880)        [0ccd:0042]
  12 -> Kworld PVR TV 2800 RF                    (em2820/em2840)
@@ -33,7 +33,7 @@
  34 -> Terratec Cinergy A Hybrid XS             (em2860)        [0ccd:004f]
  35 -> Typhoon DVD Maker                        (em2860)
  36 -> NetGMBH Cam                              (em2860)
- 37 -> Gadmei UTV330                            (em2860)
+ 37 -> Gadmei UTV330                            (em2860)        [eb1a:50a6]
  38 -> Yakumo MovieMixer                        (em2861)
  39 -> KWorld PVRTV 300U                        (em2861)        [eb1a:e300]
  40 -> Plextor ConvertX PX-TV100U               (em2861)        [093b:a005]
@@ -67,3 +67,4 @@
  69 -> KWorld ATSC 315U HDTV TV Box             (em2882)        [eb1a:a313]
  70 -> Evga inDtube                             (em2882)
  71 -> Silvercrest Webcam 1.3mpix               (em2820/em2840)
+ 72 -> Gadmei UTV330+                           (em2861)
index c913e5614195a9a359411ee163f8c2e081d24a2a..0ac4d2544778e250a70b14260c5e505bdf3c9221 100644 (file)
 166 -> Beholder BeholdTV 607 RDS                [5ace:6073]
 167 -> Beholder BeholdTV 609 RDS                [5ace:6092]
 168 -> Beholder BeholdTV 609 RDS                [5ace:6093]
+169 -> Compro VideoMate S350/S300               [185b:c900]
+170 -> AverMedia AverTV Studio 505              [1461:a115]
+171 -> Beholder BeholdTV X7                     [5ace:7595]
+172 -> RoverMedia TV Link Pro FM                [19d1:0138]
index be67844074dd1f3c31430dc75a70ccc9a53be24a..ba9fa679e2d362e66e998672a3029c7d350402c8 100644 (file)
@@ -78,3 +78,4 @@ tuner=77 - TCL tuner MF02GIP-5N-E
 tuner=78 - Philips FMD1216MEX MK3 Hybrid Tuner
 tuner=79 - Philips PAL/SECAM multi (FM1216 MK5)
 tuner=80 - Philips FQ1216LME MK3 PAL/SECAM w/active loopthrough
+tuner=81 - Partsnic (Daewoo) PTI-5NF05
index 04986efb731c443fcd16457d8e3638c8c15e9f81..d230878e473e3b230e9bc65a2d06cdfa73e9e0d7 100644 (file)
@@ -18,8 +18,8 @@ Table of Contents
 
 1.0 Introduction
 
-  The file ../drivers/char/c-qcam.c is a device driver for the
-Logitech (nee Connectix) parallel port interface color CCD camera.
+  The file ../../drivers/media/video/c-qcam.c is a device driver for
+the Logitech (nee Connectix) parallel port interface color CCD camera.
 This is a fairly inexpensive device for capturing images.  Logitech
 does not currently provide information for developers, but many people
 have engineered several solutions for non-Microsoft use of the Color
index 573f95b588079b6ae1ede70f479cf539e397e2eb..4686e84dd800e0b635d3bae7845542616bcf03f1 100644 (file)
@@ -140,6 +140,7 @@ spca500             04fc:7333       PalmPixDC85
 sunplus                04fc:ffff       Pure DigitalDakota
 spca501                0506:00df       3Com HomeConnect Lite
 sunplus                052b:1513       Megapix V4
+sunplus                052b:1803       MegaImage VI
 tv8532         0545:808b       Veo Stingray
 tv8532         0545:8333       Veo Stingray
 sunplus                0546:3155       Polaroid PDC3070
@@ -182,6 +183,7 @@ ov534               06f8:3002       Hercules Blog Webcam
 ov534          06f8:3003       Hercules Dualpix HD Weblog
 sonixj         06f8:3004       Hercules Classic Silver
 sonixj         06f8:3008       Hercules Deluxe Optical Glass
+pac7311                06f8:3009       Hercules Classic Link
 spca508                0733:0110       ViewQuest VQ110
 spca508                0130:0130       Clone Digital Webcam 11043
 spca501                0733:0401       Intel Create and Share
@@ -235,8 +237,10 @@ pac7311            093a:2621       PAC731x
 pac7311                093a:2622       Genius Eye 312
 pac7311                093a:2624       PAC7302
 pac7311                093a:2626       Labtec 2200
+pac7311                093a:2629       Genious iSlim 300
 pac7311                093a:262a       Webcam 300k
 pac7311                093a:262c       Philips SPC 230 NC
+jeilinj                0979:0280       Sakar 57379
 zc3xx          0ac8:0302       Z-star Vimicro zc0302
 vc032x         0ac8:0321       Vimicro generic vc0321
 vc032x         0ac8:0323       Vimicro Vc0323
@@ -247,6 +251,7 @@ zc3xx               0ac8:305b       Z-star Vimicro zc0305b
 zc3xx          0ac8:307b       Ldlc VC302+Ov7620
 vc032x         0ac8:c001       Sony embedded vimicro
 vc032x         0ac8:c002       Sony embedded vimicro
+vc032x         0ac8:c301       Samsung Q1 Ultra Premium
 spca508                0af9:0010       Hama USB Sightcam 100
 spca508                0af9:0011       Hama USB Sightcam 100
 sonixb         0c45:6001       Genius VideoCAM NB
@@ -284,6 +289,7 @@ sonixj              0c45:613a       Microdia Sonix PC Camera
 sonixj         0c45:613b       Surfer SN-206
 sonixj         0c45:613c       Sonix Pccam168
 sonixj         0c45:6143       Sonix Pccam168
+sonixj         0c45:6148       Digitus DA-70811/ZSMC USB PC Camera ZS211/Microdia
 sn9c20x                0c45:6240       PC Camera (SN9C201 + MT9M001)
 sn9c20x                0c45:6242       PC Camera (SN9C201 + MT9M111)
 sn9c20x                0c45:6248       PC Camera (SN9C201 + OV9655)
diff --git a/Documentation/video4linux/si4713.txt b/Documentation/video4linux/si4713.txt
new file mode 100644 (file)
index 0000000..25abdb7
--- /dev/null
@@ -0,0 +1,176 @@
+Driver for I2C radios for the Silicon Labs Si4713 FM Radio Transmitters
+
+Copyright (c) 2009 Nokia Corporation
+Contact: Eduardo Valentin <eduardo.valentin@nokia.com>
+
+
+Information about the Device
+============================
+This chip is a Silicon Labs product. It is a I2C device, currently on 0x63 address.
+Basically, it has transmission and signal noise level measurement features.
+
+The Si4713 integrates transmit functions for FM broadcast stereo transmission.
+The chip also allows integrated receive power scanning to identify low signal
+power FM channels.
+
+The chip is programmed using commands and responses. There are also several
+properties which can change the behavior of this chip.
+
+Users must comply with local regulations on radio frequency (RF) transmission.
+
+Device driver description
+=========================
+There are two modules to handle this device. One is a I2C device driver
+and the other is a platform driver.
+
+The I2C device driver exports a v4l2-subdev interface to the kernel.
+All properties can also be accessed by v4l2 extended controls interface, by
+using the v4l2-subdev calls (g_ext_ctrls, s_ext_ctrls).
+
+The platform device driver exports a v4l2 radio device interface to user land.
+So, it uses the I2C device driver as a sub device in order to send the user
+commands to the actual device. Basically it is a wrapper to the I2C device driver.
+
+Applications can use v4l2 radio API to specify frequency of operation, mute state,
+etc. But mostly of its properties will be present in the extended controls.
+
+When the v4l2 mute property is set to 1 (true), the driver will turn the chip off.
+
+Properties description
+======================
+
+The properties can be accessed using v4l2 extended controls.
+Here is an output from v4l2-ctl util:
+/ # v4l2-ctl -d /dev/radio0 --all -L
+Driver Info:
+       Driver name   : radio-si4713
+       Card type     : Silicon Labs Si4713 Modulator
+       Bus info      :
+       Driver version: 0
+       Capabilities  : 0x00080800
+               RDS Output
+               Modulator
+Audio output: 0 (FM Modulator Audio Out)
+Frequency: 1408000 (88.000000 MHz)
+Video Standard = 0x00000000
+Modulator:
+       Name                 : FM Modulator
+       Capabilities         : 62.5 Hz stereo rds
+       Frequency range      : 76.0 MHz - 108.0 MHz
+       Subchannel modulation: stereo+rds
+
+User Controls
+
+                          mute (bool) : default=1 value=0
+
+FM Radio Modulator Controls
+
+          rds_signal_deviation (int)  : min=0 max=90000 step=10 default=200 value=200 flags=slider
+                rds_program_id (int)  : min=0 max=65535 step=1 default=0 value=0
+              rds_program_type (int)  : min=0 max=31 step=1 default=0 value=0
+                   rds_ps_name (str)  : min=0 max=96 step=8 value='si4713  '
+                rds_radio_text (str)  : min=0 max=384 step=32 value=''
+  audio_limiter_feature_enabled (bool) : default=1 value=1
+     audio_limiter_release_time (int)  : min=250 max=102390 step=50 default=5010 value=5010 flags=slider
+       audio_limiter_deviation (int)  : min=0 max=90000 step=10 default=66250 value=66250 flags=slider
+audio_compression_feature_enabl (bool) : default=1 value=1
+        audio_compression_gain (int)  : min=0 max=20 step=1 default=15 value=15 flags=slider
+    audio_compression_threshold (int)  : min=-40 max=0 step=1 default=-40 value=-40 flags=slider
+  audio_compression_attack_time (int)  : min=0 max=5000 step=500 default=0 value=0 flags=slider
+ audio_compression_release_time (int)  : min=100000 max=1000000 step=100000 default=1000000 value=1000000 flags=slider
+     pilot_tone_feature_enabled (bool) : default=1 value=1
+          pilot_tone_deviation (int)  : min=0 max=90000 step=10 default=6750 value=6750 flags=slider
+          pilot_tone_frequency (int)  : min=0 max=19000 step=1 default=19000 value=19000 flags=slider
+         pre_emphasis_settings (menu) : min=0 max=2 default=1 value=1
+              tune_power_level (int)  : min=0 max=120 step=1 default=88 value=88 flags=slider
+        tune_antenna_capacitor (int)  : min=0 max=191 step=1 default=0 value=110 flags=slider
+/ #
+
+Here is a summary of them:
+
+* Pilot is an audible tone sent by the device.
+
+pilot_frequency - Configures the frequency of the stereo pilot tone.
+pilot_deviation - Configures pilot tone frequency deviation level.
+pilot_enabled - Enables or disables the pilot tone feature.
+
+* The si4713 device is capable of applying audio compression to the transmitted signal.
+
+acomp_enabled - Enables or disables the audio dynamic range control feature.
+acomp_gain - Sets the gain for audio dynamic range control.
+acomp_threshold - Sets the threshold level for audio dynamic range control.
+acomp_attack_time - Sets the attack time for audio dynamic range control.
+acomp_release_time - Sets the release time for audio dynamic range control.
+
+* Limiter setups audio deviation limiter feature. Once a over deviation occurs,
+it is possible to adjust the front-end gain of the audio input and always
+prevent over deviation.
+
+limiter_enabled - Enables or disables the limiter feature.
+limiter_deviation - Configures audio frequency deviation level.
+limiter_release_time - Sets the limiter release time.
+
+* Tuning power
+
+power_level - Sets the output power level for signal transmission.
+antenna_capacitor - This selects the value of antenna tuning capacitor manually
+or automatically if set to zero.
+
+* RDS related
+
+rds_ps_name - Sets the RDS ps name field for transmission.
+rds_radio_text - Sets the RDS radio text for transmission.
+rds_pi - Sets the RDS PI field for transmission.
+rds_pty - Sets the RDS PTY field for transmission.
+
+* Region related
+
+preemphasis - sets the preemphasis to be applied for transmission.
+
+RNL
+===
+
+This device also has an interface to measure received noise level. To do that, you should
+ioctl the device node. Here is an code of example:
+
+int main (int argc, char *argv[])
+{
+       struct si4713_rnl rnl;
+       int fd = open("/dev/radio0", O_RDWR);
+       int rval;
+
+       if (argc < 2)
+               return -EINVAL;
+
+       if (fd < 0)
+               return fd;
+
+       sscanf(argv[1], "%d", &rnl.frequency);
+
+       rval = ioctl(fd, SI4713_IOC_MEASURE_RNL, &rnl);
+       if (rval < 0)
+               return rval;
+
+       printf("received noise level: %d\n", rnl.rnl);
+
+       close(fd);
+}
+
+The struct si4713_rnl and SI4713_IOC_MEASURE_RNL are defined under
+include/media/si4713.h.
+
+Stereo/Mono and RDS subchannels
+===============================
+
+The device can also be configured using the available sub channels for
+transmission. To do that use S/G_MODULATOR ioctl and configure txsubchans properly.
+Refer to v4l2-spec for proper use of this ioctl.
+
+Testing
+=======
+Testing is usually done with v4l2-ctl utility for managing FM tuner cards.
+The tool can be found in v4l-dvb repository under v4l2-apps/util directory.
+
+Example for setting rds ps name:
+# v4l2-ctl -d /dev/radio0 --set-ctrl=rds_ps_name="Dummy"
+
index 4f913857b8a26bae558c5b0f30a6bba0799fcbf9..feb37e177010517f8f1f1d1edee3a96ed77f793f 100644 (file)
@@ -12,6 +12,7 @@ Offset        Proto   Name            Meaning
 000/040        ALL     screen_info     Text mode or frame buffer information
                                (struct screen_info)
 040/014        ALL     apm_bios_info   APM BIOS information (struct apm_bios_info)
+058/008        ALL     tboot_addr      Physical address of tboot shared page
 060/010        ALL     ist_info        Intel SpeedStep (IST) BIOS support information
                                (struct ist_info)
 080/010        ALL     hd0_info        hd0 disk parameter, OBSOLETE!!
index 837b5985ac40eea5490e85bb2cc5587be6220ef4..64b9e447545c2df6d9056cc5fd66fc360b623df3 100644 (file)
@@ -3317,7 +3317,7 @@ S:        Supported
 F:     drivers/net/wireless/mwl8k.c
 
 MARVELL SOC MMC/SD/SDIO CONTROLLER DRIVER
-M:     Nicolas Pitre <nico@cam.org>
+M:     Nicolas Pitre <nico@fluxnic.net>
 S:     Maintained
 
 MARVELL YUKON / SYSKONNECT DRIVER
@@ -4689,7 +4689,7 @@ F:        include/linux/sl?b*.h
 F:     mm/sl?b.c
 
 SMC91x ETHERNET DRIVER
-M:     Nicolas Pitre <nico@cam.org>
+M:     Nicolas Pitre <nico@fluxnic.net>
 S:     Maintained
 F:     drivers/net/smc91x.*
 
index 60de4ef312547da0264a363c87d0165626a6db8c..433493a2b77baacc36152f30f88fd2b1e7f83db4 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -325,7 +325,7 @@ CHECKFLAGS     := -D__linux__ -Dlinux -D__STDC__ -Dunix -D__unix__ \
 MODFLAGS       = -DMODULE
 CFLAGS_MODULE   = $(MODFLAGS)
 AFLAGS_MODULE   = $(MODFLAGS)
-LDFLAGS_MODULE  =
+LDFLAGS_MODULE  = -T $(srctree)/scripts/module-common.lds
 CFLAGS_KERNEL  =
 AFLAGS_KERNEL  =
 CFLAGS_GCOV    = -fprofile-arcs -ftest-coverage
index 26c17913529366ef0a5930b073c0e1f4648b6b70..a94d48b8677feba13f6e49b1b1b96c9f688b29d4 100644 (file)
@@ -9,10 +9,6 @@
 #define unmap_page_from_agp(page) 
 #define flush_agp_cache() mb()
 
-/* Convert a physical address to an address suitable for the GART. */
-#define phys_to_gart(x) (x)
-#define gart_to_phys(x) (x)
-
 /* GATT allocation. Returns/accepts GATT kernel virtual address. */
 #define alloc_gatt_pages(order)                \
        ((char *)__get_free_pages(GFP_KERNEL, (order)))
index b663f1f10b6a1011c7645580300951b977029acd..2c12378e3aa95404e6b7045db0aaf5aaacd550a8 100644 (file)
 #ifndef __ALPHA_PERCPU_H
 #define __ALPHA_PERCPU_H
 
-#include <linux/compiler.h>
-#include <linux/threads.h>
-#include <linux/percpu-defs.h>
-
-/*
- * Determine the real variable name from the name visible in the
- * kernel sources.
- */
-#define per_cpu_var(var) per_cpu__##var
-
-#ifdef CONFIG_SMP
-
-/*
- * per_cpu_offset() is the offset that has to be added to a
- * percpu variable to get to the instance for a certain processor.
- */
-extern unsigned long __per_cpu_offset[NR_CPUS];
-
-#define per_cpu_offset(x) (__per_cpu_offset[x])
-
-#define __my_cpu_offset per_cpu_offset(raw_smp_processor_id())
-#ifdef CONFIG_DEBUG_PREEMPT
-#define my_cpu_offset per_cpu_offset(smp_processor_id())
-#else
-#define my_cpu_offset __my_cpu_offset
-#endif
-
-#ifndef MODULE
-#define SHIFT_PERCPU_PTR(var, offset) RELOC_HIDE(&per_cpu_var(var), (offset))
-#define PER_CPU_DEF_ATTRIBUTES
-#else
 /*
- * To calculate addresses of locally defined variables, GCC uses 32-bit
- * displacement from the GP. Which doesn't work for per cpu variables in
- * modules, as an offset to the kernel per cpu area is way above 4G.
+ * To calculate addresses of locally defined variables, GCC uses
+ * 32-bit displacement from the GP. Which doesn't work for per cpu
+ * variables in modules, as an offset to the kernel per cpu area is
+ * way above 4G.
  *
- * This forces allocation of a GOT entry for per cpu variable using
- * ldq instruction with a 'literal' relocation.
- */
-#define SHIFT_PERCPU_PTR(var, offset) ({               \
-       extern int simple_identifier_##var(void);       \
-       unsigned long __ptr, tmp_gp;                    \
-       asm (  "br      %1, 1f                        \n\
-       1:      ldgp    %1, 0(%1)                     \n\
-               ldq %0, per_cpu__" #var"(%1)\t!literal"         \
-               : "=&r"(__ptr), "=&r"(tmp_gp));         \
-       (typeof(&per_cpu_var(var)))(__ptr + (offset)); })
-
-#define PER_CPU_DEF_ATTRIBUTES __used
-
-#endif /* MODULE */
-
-/*
- * A percpu variable may point to a discarded regions. The following are
- * established ways to produce a usable pointer from the percpu variable
- * offset.
+ * Always use weak definitions for percpu variables in modules.
  */
-#define per_cpu(var, cpu) \
-       (*SHIFT_PERCPU_PTR(var, per_cpu_offset(cpu)))
-#define __get_cpu_var(var) \
-       (*SHIFT_PERCPU_PTR(var, my_cpu_offset))
-#define __raw_get_cpu_var(var) \
-       (*SHIFT_PERCPU_PTR(var, __my_cpu_offset))
-
-#else /* ! SMP */
-
-#define per_cpu(var, cpu)              (*((void)(cpu), &per_cpu_var(var)))
-#define __get_cpu_var(var)             per_cpu_var(var)
-#define __raw_get_cpu_var(var)         per_cpu_var(var)
-
-#define PER_CPU_DEF_ATTRIBUTES
-
-#endif /* SMP */
-
-#ifdef CONFIG_SMP
-#define PER_CPU_BASE_SECTION ".data.percpu"
-#else
-#define PER_CPU_BASE_SECTION ".data"
-#endif
-
-#ifdef CONFIG_SMP
-
-#ifdef MODULE
-#define PER_CPU_SHARED_ALIGNED_SECTION ""
-#else
-#define PER_CPU_SHARED_ALIGNED_SECTION ".shared_aligned"
-#endif
-#define PER_CPU_FIRST_SECTION ".first"
-
-#else
-
-#define PER_CPU_SHARED_ALIGNED_SECTION ""
-#define PER_CPU_FIRST_SECTION ""
-
+#if defined(MODULE) && defined(CONFIG_SMP)
+#define ARCH_NEEDS_WEAK_PER_CPU
 #endif
 
-#define PER_CPU_ATTRIBUTES
+#include <asm-generic/percpu.h>
 
 #endif /* __ALPHA_PERCPU_H */
index 9d87aaa08c0df1cf093bbb90227a2f8470adb70e..e89e0c2e15b17f7eda39cd753b5e4f918a0fa902 100644 (file)
@@ -2,6 +2,7 @@
 #define _ALPHA_TLBFLUSH_H
 
 #include <linux/mm.h>
+#include <linux/sched.h>
 #include <asm/compiler.h>
 #include <asm/pgalloc.h>
 
index b9d6568e5f7f0eb68f7ecb2dac4207a705e0e47b..6dc03c35caa0246bb87dc69c0add025e1f46ab94 100644 (file)
@@ -134,13 +134,6 @@ SECTIONS
        __bss_stop = .;
        _end = .;
 
-       /* Sections to be discarded */
-       /DISCARD/ : {
-               EXIT_TEXT
-               EXIT_DATA
-               *(.exitcall.exit)
-       }
-
        .mdebug 0 : {
                *(.mdebug)
        }
@@ -150,4 +143,6 @@ SECTIONS
 
        STABS_DEBUG
        DWARF_DEBUG
+
+       DISCARDS
 }
index 4c8c0e46027d224458e104d4ceab0d4e607b9c3c..6179d94dd5c665a634e5e2913a916c96c9652c84 100644 (file)
@@ -1,7 +1,7 @@
 /* 
  * linux/arch/arm/boot/compressed/head-sa1100.S
  * 
- * Copyright (C) 1999 Nicolas Pitre <nico@cam.org>
+ * Copyright (C) 1999 Nicolas Pitre <nico@fluxnic.net>
  * 
  * SA1100 specific tweaks.  This is merged into head.S by the linker.
  *
index 69371028a2025a7f7b2f52fb32cdabadeae728e7..5cc4812c97635b9c4e723b87a93aabd009e6e8bb 100644 (file)
@@ -83,6 +83,7 @@ SECTIONS
                EXIT_TEXT
                EXIT_DATA
                *(.exitcall.exit)
+               *(.discard)
                *(.ARM.exidx.exit.text)
                *(.ARM.extab.exit.text)
 #ifndef CONFIG_HOTPLUG_CPU
index 67964bcfc854fde5fc46ed33294a189c4bb1f371..6dc06487f3c3e95359b2559163f24d8a8ca635cf 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * linux/arch/arm/lib/lib1funcs.S: Optimized ARM division routines
  *
- * Author: Nicolas Pitre <nico@cam.org>
+ * Author: Nicolas Pitre <nico@fluxnic.net>
  *   - contributed to gcc-3.4 on Sep 30, 2003
  *   - adapted for the Linux kernel on Oct 2, 2003
  */
index 09b548cac1a41fba1d04fb14d9b3f7cdd197c7f6..eb0edb80d7b84c8780168bd51b535b827dadba1d 100644 (file)
@@ -3,7 +3,7 @@
  *
  *  SHA transform optimized for ARM
  *
- *  Copyright: (C) 2005 by Nicolas Pitre <nico@cam.org>
+ *  Copyright: (C) 2005 by Nicolas Pitre <nico@fluxnic.net>
  *  Created:   September 17, 2005
  *
  *  This program is free software; you can redistribute it and/or modify
index 3959b20d5d1c221358a330844f3143b4b2b0ef55..28c2cf50c259e9275e605ce8c578bc133fa49429 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * arch/arm/mach-sa1100/include/mach/assabet.h
  *
- * Created 2000/06/05 by Nicolas Pitre <nico@cam.org>
+ * Created 2000/06/05 by Nicolas Pitre <nico@fluxnic.net>
  *
  * This file contains the hardware specific definitions for Assabet
  * Only include this file from SA1100-specific files.
index 60711822b1258dafee21d535b9255d2f583ea27c..99f5856d8de424ce006d09c090cf0810f649e811 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * arch/arm/mach-sa1100/include/mach/hardware.h
  *
- * Copyright (C) 1998 Nicolas Pitre <nico@cam.org>
+ * Copyright (C) 1998 Nicolas Pitre <nico@fluxnic.net>
  *
  * This file contains the hardware definitions for SA1100 architecture
  *
index e9f8eed900f5171f0ecdda0d625cf7399159086b..d5277f9bee77d8dc7a98b2acb60d494e5fcc9df1 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * arch/arm/mach-sa1100/include/mach/memory.h
  *
- * Copyright (C) 1999-2000 Nicolas Pitre <nico@cam.org>
+ * Copyright (C) 1999-2000 Nicolas Pitre <nico@fluxnic.net>
  */
 
 #ifndef __ASM_ARCH_MEMORY_H
index d3f044f92c00e943d0241b48213dbf2fc61a5238..ffe2bc45eed0a7b6fb4706251efef2b4d18691b6 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * arch/arm/mach-sa1100/include/mach/neponset.h
  *
- * Created 2000/06/05 by Nicolas Pitre <nico@cam.org>
+ * Created 2000/06/05 by Nicolas Pitre <nico@fluxnic.net>
  *
  * This file contains the hardware specific definitions for Assabet
  * Only include this file from SA1100-specific files.
index 942b153e251d601ffb9fc79a87a5a07fba9bb761..ba9da9f7f1837cc0a94667ad3e0377dbba762237 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * arch/arm/mach-sa1100/include/mach/system.h
  *
- * Copyright (c) 1999 Nicolas Pitre <nico@cam.org>
+ * Copyright (c) 1999 Nicolas Pitre <nico@fluxnic.net>
  */
 #include <mach/hardware.h>
 
index 714160b03d7a7dd2a9163115e44c000ca9260291..6cb39ddde6561a19dea18b7815ef0616f924497c 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * arch/arm/mach-sa1100/include/mach/uncompress.h
  *
- * (C) 1999 Nicolas Pitre <nico@cam.org>
+ * (C) 1999 Nicolas Pitre <nico@fluxnic.net>
  *
  * Reorganised to be machine independent.
  */
index 111cce67ad2fa8f33d97a4101ce70d44d3d880e5..c83fdc80edfd1226c8ddea56b700e047f099d218 100644 (file)
@@ -15,7 +15,7 @@
  *                     Save more value for the resume function! Support
  *                     Bitsy/Assabet/Freebird board
  *
- * 2001-08-29: Nicolas Pitre <nico@cam.org>
+ * 2001-08-29: Nicolas Pitre <nico@fluxnic.net>
  *                     Cleaned up, pushed platform dependent stuff
  *                     in the platform specific files.
  *
index 711c0295c66f1710de34e20f3d9a88c2eeb99609..95d92e8e56a81c820979d373cd87e4d152b09235 100644 (file)
@@ -4,7 +4,7 @@
  * Copyright (C) 1998 Deborah Wallach.
  * Twiddles  (C) 1999 Hugo Fiennes <hugo@empeg.com>
  *
- * 2000/03/29 (C) Nicolas Pitre <nico@cam.org>
+ * 2000/03/29 (C) Nicolas Pitre <nico@fluxnic.net>
  *     Rewritten: big cleanup, much simpler, better HZ accuracy.
  *
  */
index 0cce37b9393730b43b8adcf2a37ed9e2ee2f5bcd..423394260bcbd17fc863deecd225bf85f617025c 100644 (file)
@@ -17,7 +17,7 @@
  *
  * 2001 Sep 08:
  *     Completely revisited, many important fixes
- *     Nicolas Pitre <nico@cam.org>
+ *     Nicolas Pitre <nico@fluxnic.net>
  */
 
 #include <linux/linkage.h>
index 9e573e78176a65d4bfdb93ae19235f5e39d4ca2b..bade586fed0ff0e44587ebf682c162e41366294c 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * arch/arm/plat-iop/setup.c
  *
- * Author: Nicolas Pitre <nico@cam.org>
+ * Author: Nicolas Pitre <nico@fluxnic.net>
  * Copyright (C) 2001 MontaVista Software, Inc.
  * Copyright (C) 2004 Intel Corporation.
  *
index 1060e345423b5f9bf3f8f6da7fafcc38b8ade3c0..ed8ec747726139f6d9a2f934920c39a637f8f7b9 100644 (file)
@@ -1,6 +1,6 @@
 /*
  * Copied from arch/arm/mach-sa1100/include/mach/system.h
- * Copyright (c) 1999 Nicolas Pitre <nico@cam.org>
+ * Copyright (c) 1999 Nicolas Pitre <nico@fluxnic.net>
  */
 #ifndef __ASM_ARCH_SYSTEM_H
 #define __ASM_ARCH_SYSTEM_H
index 7910d41eb886358981cd32bfc5b36ba215d4b636..c4b56654349adbb8fb52fd2f4a12602a3942391c 100644 (file)
@@ -124,14 +124,11 @@ SECTIONS
                _end = .;
        }
 
+       DWARF_DEBUG
+
        /* When something in the kernel is NOT compiled as a module, the module
         * cleanup code and data are put into these segments. Both can then be
         * thrown away, as cleanup code is never called unless it's a module.
         */
-       /DISCARD/               : {
-               EXIT_DATA
-               *(.exitcall.exit)
-       }
-
-       DWARF_DEBUG
+       DISCARDS
 }
index 6ac307ca0d805a7487d1990b59978bcf9f834ec1..d7ffe299b979340de6264310434913ead137c775 100644 (file)
@@ -277,8 +277,5 @@ SECTIONS
 
        DWARF_DEBUG
 
-       /DISCARD/ :
-       {
-               *(.exitcall.exit)
-       }
+       DISCARDS
 }
index 0bc3c4ef0aad54664610b7713a7a9f9696845890..99e4dbb1dfd12502becc3d2506f3d51a1076433d 100644 (file)
@@ -42,9 +42,9 @@
 #include <asm/mem_map.h>
 #include "blackfin_sram.h"
 
-static DEFINE_PER_CPU(spinlock_t, l1sram_lock) ____cacheline_aligned_in_smp;
-static DEFINE_PER_CPU(spinlock_t, l1_data_sram_lock) ____cacheline_aligned_in_smp;
-static DEFINE_PER_CPU(spinlock_t, l1_inst_sram_lock) ____cacheline_aligned_in_smp;
+static DEFINE_PER_CPU_SHARED_ALIGNED(spinlock_t, l1sram_lock);
+static DEFINE_PER_CPU_SHARED_ALIGNED(spinlock_t, l1_data_sram_lock);
+static DEFINE_PER_CPU_SHARED_ALIGNED(spinlock_t, l1_inst_sram_lock);
 static spinlock_t l2_sram_lock ____cacheline_aligned_in_smp;
 
 /* the data structure for L1 scratchpad and DATA SRAM */
index 72ba08dcfd18c1336d19d2ef66893bd7658a8a4b..1d45fd6365b729416e2e53e00ee40a6c3405ab95 100644 (file)
@@ -17,7 +17,8 @@ extern void switch_mm(struct mm_struct *prev, struct mm_struct *next,
  * registers like cr3 on the i386
  */
 
-extern volatile DEFINE_PER_CPU(pgd_t *,current_pgd); /* defined in arch/cris/mm/fault.c */
+/* defined in arch/cris/mm/fault.c */
+DECLARE_PER_CPU(pgd_t *, current_pgd);
 
 static inline void enter_lazy_tlb(struct mm_struct *mm, struct task_struct *tsk)
 {
index 0d2adfc794d49d0bcb8e4a63f3671875dbd7e816..6c81836b9229cb473aece3a99468020085647cf5 100644 (file)
@@ -140,12 +140,7 @@ SECTIONS
        _end = .;
        __end = .;
 
-       /* Sections to be discarded */
-       /DISCARD/ : {
-               EXIT_TEXT
-               EXIT_DATA
-               *(.exitcall.exit)
-        }
-
        dram_end = dram_start + (CONFIG_ETRAX_DRAM_SIZE - __CONFIG_ETRAX_VMEM_SIZE)*1024*1024;
+
+       DISCARDS
 }
index f925115e3250e516e9118cc331cdd838c6b075df..4a7cdd9ea1ee70c2522c25f926233cf9101895b2 100644 (file)
@@ -29,7 +29,7 @@ extern void die_if_kernel(const char *, struct pt_regs *, long);
 
 /* current active page directory */
 
-volatile DEFINE_PER_CPU(pgd_t *,current_pgd);
+DEFINE_PER_CPU(pgd_t *, current_pgd);
 unsigned long cris_signal_return_page;
 
 /*
index 22d9787406ed9862f2ac0771c2345c13502751be..7dbf41f68b523a14f7c39b683689c51f53c99f4f 100644 (file)
@@ -177,6 +177,8 @@ SECTIONS
   .debug_ranges                0 : { *(.debug_ranges) }
 
   .comment 0 : { *(.comment) }
+
+  DISCARDS
 }
 
 __kernel_image_size_no_bss = __bss_start - __kernel_image_start;
index 43a87b9085b6b449cb7fbfb64bfb5d715551185c..662b02ecb86eacfd068e65b3c73a14e11760813d 100644 (file)
@@ -152,9 +152,6 @@ SECTIONS
        __end = . ;
        __ramstart = .;
        }
-       /DISCARD/ : {
-               *(.exitcall.exit)
-       }
         .romfs :       
        {
                *(.romfs*)
@@ -165,4 +162,6 @@ SECTIONS
        COMMAND_START = . - 0x200 ;
        __ramend = . ;
        }
+
+       DISCARDS
 }
index 170042b420d466829ff7baba523a7b357b43d7a5..011a1cdf0eb53d4c97c39427bd1f0461690a6e79 100644 (file)
@@ -89,6 +89,9 @@ config GENERIC_TIME_VSYSCALL
        bool
        default y
 
+config HAVE_LEGACY_PER_CPU_AREA
+       def_bool y
+
 config HAVE_SETUP_PER_CPU_AREA
        def_bool y
 
@@ -112,6 +115,10 @@ config IA64_UNCACHED_ALLOCATOR
        bool
        select GENERIC_ALLOCATOR
 
+config ARCH_USES_PG_UNCACHED
+       def_bool y
+       depends on IA64_UNCACHED_ALLOCATOR
+
 config AUDIT_ARCH
        bool
        default y
index c11fdd8ab4d7a88665c757a81c6e8c1a471bdf90..01d09c401c5c3b8c269b946ce31bee78edff9f23 100644 (file)
 #define unmap_page_from_agp(page)      /* nothing */
 #define flush_agp_cache()              mb()
 
-/* Convert a physical address to an address suitable for the GART. */
-#define phys_to_gart(x) (x)
-#define gart_to_phys(x) (x)
-
 /* GATT allocation. Returns/accepts GATT kernel virtual address. */
 #define alloc_gatt_pages(order)                \
        ((char *)__get_free_pages(GFP_KERNEL, (order)))
index 1b23ec126b637b204a4e43fd559ba7825cb14152..1de86c96801d60fe81ae2d6fc4930bdfdc190c45 100644 (file)
@@ -855,11 +855,17 @@ identify_cpu (struct cpuinfo_ia64 *c)
        c->unimpl_pa_mask = ~((1L<<63) | ((1L << phys_addr_size) - 1));
 }
 
+/*
+ * In UP configuration, setup_per_cpu_areas() is defined in
+ * include/linux/percpu.h
+ */
+#ifdef CONFIG_SMP
 void __init
 setup_per_cpu_areas (void)
 {
        /* start_kernel() requires this... */
 }
+#endif
 
 /*
  * Do the following calculations:
index f0c521b0ba4c2335af80a8f660c2d00cc3fc50f6..93ebfea43c6cecdb66a93372adc73f2825aaae77 100644 (file)
@@ -58,7 +58,8 @@ static struct local_tlb_flush_counts {
        unsigned int count;
 } __attribute__((__aligned__(32))) local_tlb_flush_counts[NR_CPUS];
 
-static DEFINE_PER_CPU(unsigned short, shadow_flush_counts[NR_CPUS]) ____cacheline_aligned;
+static DEFINE_PER_CPU_SHARED_ALIGNED(unsigned short [NR_CPUS],
+                                    shadow_flush_counts);
 
 #define IPI_CALL_FUNC          0
 #define IPI_CPU_STOP           1
index 4a95e86b9ac200bafd30ddca8b1d50be6aec5081..eb4214d1c5afe342729901da138870302676f6d9 100644 (file)
@@ -24,14 +24,14 @@ PHDRS {
 }
 SECTIONS
 {
-  /* Sections to be discarded */
+  /* unwind exit sections must be discarded before the rest of the
+     sections get included. */
   /DISCARD/ : {
-       EXIT_TEXT
-       EXIT_DATA
-       *(.exitcall.exit)
        *(.IA_64.unwind.exit.text)
        *(.IA_64.unwind_info.exit.text)
-       }
+       *(.comment)
+       *(.note)
+  }
 
   v = PAGE_OFFSET;     /* this symbol is here to make debugging easier... */
   phys_start = _start - LOAD_OFFSET;
@@ -316,7 +316,7 @@ SECTIONS
   .debug_funcnames 0 : { *(.debug_funcnames) }
   .debug_typenames 0 : { *(.debug_typenames) }
   .debug_varnames  0 : { *(.debug_varnames) }
-  /* These must appear regardless of  .  */
-  /DISCARD/ : { *(.comment) }
-  /DISCARD/ : { *(.note) }
+
+  /* Default discards */
+  DISCARDS
 }
index e456f062f2419deb5f2bfd9d0e968d88b1c79ac5..ece1bf994499a1d55e33cf64d2c7fd9f13e8dad4 100644 (file)
@@ -71,7 +71,7 @@ EXPORT_SYMBOL(sn_rtc_cycles_per_second);
 DEFINE_PER_CPU(struct sn_hub_info_s, __sn_hub_info);
 EXPORT_PER_CPU_SYMBOL(__sn_hub_info);
 
-DEFINE_PER_CPU(short, __sn_cnodeid_to_nasid[MAX_COMPACT_NODES]);
+DEFINE_PER_CPU(short [MAX_COMPACT_NODES], __sn_cnodeid_to_nasid);
 EXPORT_PER_CPU_SYMBOL(__sn_cnodeid_to_nasid);
 
 DEFINE_PER_CPU(struct nodepda_s *, __sn_nodepda);
index 4179adf6c624f0f6c5af62bf82bef34e761a17ed..de5e21cca6a5a323d6a5eb3232694863cef05a36 100644 (file)
@@ -120,13 +120,6 @@ SECTIONS
 
   _end = . ;
 
-  /* Sections to be discarded */
-  /DISCARD/ : {
-       EXIT_TEXT
-       EXIT_DATA
-       *(.exitcall.exit)
-       }
-
   /* Stabs debugging sections.  */
   .stab 0 : { *(.stab) }
   .stabstr 0 : { *(.stabstr) }
@@ -135,4 +128,7 @@ SECTIONS
   .stab.index 0 : { *(.stab.index) }
   .stab.indexstr 0 : { *(.stab.indexstr) }
   .comment 0 : { *(.comment) }
+
+  /* Sections to be discarded */
+  DISCARDS
 }
index 01d212bb05a6edcc965636f887b6117d3e92c863..47eac19e8f61d68c7ecbd26de4704e133e213852 100644 (file)
@@ -82,13 +82,6 @@ SECTIONS
 
   _end = . ;
 
-  /* Sections to be discarded */
-  /DISCARD/ : {
-       EXIT_TEXT
-       EXIT_DATA
-       *(.exitcall.exit)
-       }
-
   /* Stabs debugging sections.  */
   .stab 0 : { *(.stab) }
   .stabstr 0 : { *(.stabstr) }
@@ -97,4 +90,7 @@ SECTIONS
   .stab.index 0 : { *(.stab.index) }
   .stab.indexstr 0 : { *(.stab.indexstr) }
   .comment 0 : { *(.comment) }
+
+  /* Sections to be discarded */
+  DISCARDS
 }
index c192f773db9684a261a5d3529f501a1cd6c57c91..03efaf04d7d7dad17f37a1f95dd454a6b64ea8b3 100644 (file)
@@ -77,13 +77,6 @@ __init_begin = .;
 
   _end = . ;
 
-  /* Sections to be discarded */
-  /DISCARD/ : {
-       EXIT_TEXT
-       EXIT_DATA
-       *(.exitcall.exit)
-       }
-
   .crap : {
        /* Stabs debugging sections.  */
        *(.stab)
@@ -96,4 +89,6 @@ __init_begin = .;
        *(.note)
   }
 
+  /* Sections to be discarded */
+  DISCARDS
 }
index b7fe505e358d853e1d38d11b78826f1ee050169e..2736a5e309c0d1b386f2be27b3b3477d58e4a5c1 100644 (file)
@@ -184,12 +184,6 @@ SECTIONS {
                __init_end = .;
        } > INIT
 
-       /DISCARD/ : {
-               EXIT_TEXT
-               EXIT_DATA
-               *(.exitcall.exit)
-       }
-
        .bss : {
                . = ALIGN(4);
                _sbss = . ;
@@ -200,5 +194,6 @@ SECTIONS {
                _end = . ;
        } > BSS
 
+       DISCARDS
 }
 
index d34d38dcd12c71a733da03bee3b0e017f9320ca8..ec5fa91a48d83bf515912011bd0f48e6419113e6 100644 (file)
@@ -23,8 +23,8 @@ SECTIONS {
                _stext = . ;
                *(.text .text.*)
                *(.fixup)
-
-               *(.exitcall.exit)
+               EXIT_TEXT
+               EXIT_CALL
                SCHED_TEXT
                LOCK_TEXT
                KPROBES_TEXT
@@ -162,4 +162,6 @@ SECTIONS {
        }
        . = ALIGN(4096);
        _end = .;
+
+       DISCARDS
 }
index 58738c8d754feb09bf525fe6862c62e1f6bda39a..1474c18fb777d13c1d07f164f50ccef1304f156b 100644 (file)
@@ -176,17 +176,6 @@ SECTIONS
 
        _end = . ;
 
-       /* Sections to be discarded */
-       /DISCARD/ : {
-               *(.exitcall.exit)
-
-               /* ABI crap starts here */
-               *(.MIPS.options)
-               *(.options)
-               *(.pdr)
-               *(.reginfo)
-       }
-
        /* These mark the ABI of the kernel for debuggers.  */
        .mdebug.abi32 : {
                KEEP(*(.mdebug.abi32))
@@ -212,4 +201,14 @@ SECTIONS
                *(.gptab.bss)
                *(.gptab.sbss)
        }
+
+       /* Sections to be discarded */
+       DISCARDS
+       /DISCARD/ : {
+               /* ABI crap starts here */
+               *(.MIPS.options)
+               *(.options)
+               *(.pdr)
+               *(.reginfo)
+       }
 }
index f4aa079346543f4ecfc47388bec429c66cf35733..76f41bdb79c411359f526c86abd7ea84872b9a5e 100644 (file)
@@ -115,12 +115,10 @@ SECTIONS
   . = ALIGN(PAGE_SIZE);
   pg0 = .;
 
-  /* Sections to be discarded */
-  /DISCARD/ : {
-       EXIT_CALL
-       }
-
   STABS_DEBUG
 
   DWARF_DEBUG
+
+  /* Sections to be discarded */
+  DISCARDS
 }
index 9651660da639a32b6c0d20cc11aaafff2fce549b..d226ffa8fc12f60ec9ad3f45a9369237cbec1a5b 100644 (file)
 #define unmap_page_from_agp(page)      /* nothing */
 #define flush_agp_cache()              mb()
 
-/* Convert a physical address to an address suitable for the GART. */
-#define phys_to_gart(x) (x)
-#define gart_to_phys(x) (x)
-
 /* GATT allocation. Returns/accepts GATT kernel virtual address. */
 #define alloc_gatt_pages(order)                \
        ((char *)__get_free_pages(GFP_KERNEL, (order)))
index fd2cc4fd2b65adc5b84dd46639d4eaea1ea58d77..aea1784edbd122d0fd5533edd29fb3d9cd659c64 100644 (file)
@@ -237,9 +237,12 @@ SECTIONS
        /* freed after init ends here */
        _end = . ;
 
+       STABS_DEBUG
+       .note 0 : { *(.note) }
+
        /* Sections to be discarded */
+       DISCARDS
        /DISCARD/ : {
-               *(.exitcall.exit)
 #ifdef CONFIG_64BIT
                /* temporary hack until binutils is fixed to not emit these
                 * for static binaries
@@ -252,7 +255,4 @@ SECTIONS
                *(.gnu.hash)
 #endif
        }
-
-       STABS_DEBUG
-       .note 0 : { *(.note) }  
 }
index d00131ca0835e71cb8cd25d19f9f9f43557083df..8250902265c61c3c4da07c74e56d7b165793ceb4 100644 (file)
@@ -49,6 +49,9 @@ config GENERIC_HARDIRQS_NO__DO_IRQ
 config HAVE_SETUP_PER_CPU_AREA
        def_bool PPC64
 
+config NEED_PER_CPU_EMBED_FIRST_CHUNK
+       def_bool PPC64
+
 config IRQ_PER_CPU
        bool
        default y
@@ -120,7 +123,8 @@ config PPC
        select HAVE_KRETPROBES
        select HAVE_ARCH_TRACEHOOK
        select HAVE_LMB
-       select HAVE_DMA_ATTRS if PPC64
+       select HAVE_DMA_ATTRS
+       select HAVE_DMA_API_DEBUG
        select USE_GENERIC_SMP_HELPERS if SMP
        select HAVE_OPROFILE
        select HAVE_SYSCALL_WRAPPERS if PPC64
@@ -307,10 +311,6 @@ config SWIOTLB
          platforms where the size of a physical address is larger
          than the bus address.  Not all platforms support this.
 
-config PPC_NEED_DMA_SYNC_OPS
-       def_bool y
-       depends on (NOT_COHERENT_CACHE || SWIOTLB)
-
 config HOTPLUG_CPU
        bool "Support for enabling/disabling CPUs"
        depends on SMP && HOTPLUG && EXPERIMENTAL && (PPC_PSERIES || PPC_PMAC)
@@ -472,7 +472,7 @@ config PPC_16K_PAGES
        bool "16k page size" if 44x
 
 config PPC_64K_PAGES
-       bool "64k page size" if 44x || PPC_STD_MMU_64
+       bool "64k page size" if 44x || PPC_STD_MMU_64 || PPC_BOOK3E_64
        select PPC_HAS_HASH_64K if PPC_STD_MMU_64
 
 config PPC_256K_PAGES
@@ -492,16 +492,16 @@ endchoice
 
 config FORCE_MAX_ZONEORDER
        int "Maximum zone order"
-       range 9 64 if PPC_STD_MMU_64 && PPC_64K_PAGES
-       default "9" if PPC_STD_MMU_64 && PPC_64K_PAGES
-       range 13 64 if PPC_STD_MMU_64 && !PPC_64K_PAGES
-       default "13" if PPC_STD_MMU_64 && !PPC_64K_PAGES
-       range 9 64 if PPC_STD_MMU_32 && PPC_16K_PAGES
-       default "9" if PPC_STD_MMU_32 && PPC_16K_PAGES
-       range 7 64 if PPC_STD_MMU_32 && PPC_64K_PAGES
-       default "7" if PPC_STD_MMU_32 && PPC_64K_PAGES
-       range 5 64 if PPC_STD_MMU_32 && PPC_256K_PAGES
-       default "5" if PPC_STD_MMU_32 && PPC_256K_PAGES
+       range 9 64 if PPC64 && PPC_64K_PAGES
+       default "9" if PPC64 && PPC_64K_PAGES
+       range 13 64 if PPC64 && !PPC_64K_PAGES
+       default "13" if PPC64 && !PPC_64K_PAGES
+       range 9 64 if PPC32 && PPC_16K_PAGES
+       default "9" if PPC32 && PPC_16K_PAGES
+       range 7 64 if PPC32 && PPC_64K_PAGES
+       default "7" if PPC32 && PPC_64K_PAGES
+       range 5 64 if PPC32 && PPC_256K_PAGES
+       default "5" if PPC32 && PPC_256K_PAGES
        range 11 64
        default "11"
        help
index bc35f4e2b81cd0cfa65a536dfc99e877410f268e..952a3963e9e8b607e15fb7ffc21d8f8d5482dd8b 100644 (file)
@@ -77,7 +77,7 @@ CPP           = $(CC) -E $(KBUILD_CFLAGS)
 CHECKFLAGS     += -m$(CONFIG_WORD_SIZE) -D__powerpc__ -D__powerpc$(CONFIG_WORD_SIZE)__
 
 ifeq ($(CONFIG_PPC64),y)
-GCC_BROKEN_VEC := $(shell if [ $(call cc-version) -lt 0400 ] ; then echo "y"; fi)
+GCC_BROKEN_VEC := $(call cc-ifversion, -lt, 0400, y)
 
 ifeq ($(CONFIG_POWER4_ONLY),y)
 ifeq ($(CONFIG_ALTIVEC),y)
index 325b310573b955f52a47acf22dd2cb8b2227fa45..27db8938827aee7381cc065fade0d12fb0c2d528 100644 (file)
@@ -8,6 +8,10 @@
  *   Eugene Surovegin <eugene.surovegin@zultys.com> or <ebs@ebshome.net>
  *   Copyright (c) 2003, 2004 Zultys Technologies
  *
+ * Copyright (C) 2009 Wind River Systems, Inc.
+ *   Updated for supporting PPC405EX on Kilauea.
+ *   Tiejun Chen <tiejun.chen@windriver.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
@@ -659,3 +663,141 @@ void ibm405ep_fixup_clocks(unsigned int sys_clk)
        dt_fixup_clock("/plb/opb/serial@ef600300", uart0);
        dt_fixup_clock("/plb/opb/serial@ef600400", uart1);
 }
+
+static u8 ibm405ex_fwdv_multi_bits[] = {
+       /* values for:  1 - 16 */
+       0x01, 0x02, 0x0e, 0x09, 0x04, 0x0b, 0x10, 0x0d, 0x0c, 0x05,
+       0x06, 0x0f, 0x0a, 0x07, 0x08, 0x03
+};
+
+u32 ibm405ex_get_fwdva(unsigned long cpr_fwdv)
+{
+       u32 index;
+
+       for (index = 0; index < ARRAY_SIZE(ibm405ex_fwdv_multi_bits); index++)
+               if (cpr_fwdv == (u32)ibm405ex_fwdv_multi_bits[index])
+                       return index + 1;
+
+       return 0;
+}
+
+static u8 ibm405ex_fbdv_multi_bits[] = {
+       /* values for:  1 - 100 */
+       0x00, 0xff, 0x7e, 0xfd, 0x7a, 0xf5, 0x6a, 0xd5, 0x2a, 0xd4,
+       0x29, 0xd3, 0x26, 0xcc, 0x19, 0xb3, 0x67, 0xce, 0x1d, 0xbb,
+       0x77, 0xee, 0x5d, 0xba, 0x74, 0xe9, 0x52, 0xa5, 0x4b, 0x96,
+       0x2c, 0xd8, 0x31, 0xe3, 0x46, 0x8d, 0x1b, 0xb7, 0x6f, 0xde,
+       0x3d, 0xfb, 0x76, 0xed, 0x5a, 0xb5, 0x6b, 0xd6, 0x2d, 0xdb,
+       0x36, 0xec, 0x59, 0xb2, 0x64, 0xc9, 0x12, 0xa4, 0x48, 0x91,
+       0x23, 0xc7, 0x0e, 0x9c, 0x38, 0xf0, 0x61, 0xc2, 0x05, 0x8b,
+       0x17, 0xaf, 0x5f, 0xbe, 0x7c, 0xf9, 0x72, 0xe5, 0x4a, 0x95,
+       0x2b, 0xd7, 0x2e, 0xdc, 0x39, 0xf3, 0x66, 0xcd, 0x1a, 0xb4,
+       0x68, 0xd1, 0x22, 0xc4, 0x09, 0x93, 0x27, 0xcf, 0x1e, 0xbc,
+       /* values for:  101 - 200 */
+       0x78, 0xf1, 0x62, 0xc5, 0x0a, 0x94, 0x28, 0xd0, 0x21, 0xc3,
+       0x06, 0x8c, 0x18, 0xb0, 0x60, 0xc1, 0x02, 0x84, 0x08, 0x90,
+       0x20, 0xc0, 0x01, 0x83, 0x07, 0x8f, 0x1f, 0xbf, 0x7f, 0xfe,
+       0x7d, 0xfa, 0x75, 0xea, 0x55, 0xaa, 0x54, 0xa9, 0x53, 0xa6,
+       0x4c, 0x99, 0x33, 0xe7, 0x4e, 0x9d, 0x3b, 0xf7, 0x6e, 0xdd,
+       0x3a, 0xf4, 0x69, 0xd2, 0x25, 0xcb, 0x16, 0xac, 0x58, 0xb1,
+       0x63, 0xc6, 0x0d, 0x9b, 0x37, 0xef, 0x5e, 0xbd, 0x7b, 0xf6,
+       0x6d, 0xda, 0x35, 0xeb, 0x56, 0xad, 0x5b, 0xb6, 0x6c, 0xd9,
+       0x32, 0xe4, 0x49, 0x92, 0x24, 0xc8, 0x11, 0xa3, 0x47, 0x8e,
+       0x1c, 0xb8, 0x70, 0xe1, 0x42, 0x85, 0x0b, 0x97, 0x2f, 0xdf,
+       /* values for:  201 - 255 */
+       0x3e, 0xfc, 0x79, 0xf2, 0x65, 0xca, 0x15, 0xab, 0x57, 0xae,
+       0x5c, 0xb9, 0x73, 0xe6, 0x4d, 0x9a, 0x34, 0xe8, 0x51, 0xa2,
+       0x44, 0x89, 0x13, 0xa7, 0x4f, 0x9e, 0x3c, 0xf8, 0x71, 0xe2,
+       0x45, 0x8a, 0x14, 0xa8, 0x50, 0xa1, 0x43, 0x86, 0x0c, 0x98,
+       0x30, 0xe0, 0x41, 0x82, 0x04, 0x88, 0x10, 0xa0, 0x40, 0x81,
+       0x03, 0x87, 0x0f, 0x9f, 0x3f  /* END */
+};
+
+u32 ibm405ex_get_fbdv(unsigned long cpr_fbdv)
+{
+       u32 index;
+
+       for (index = 0; index < ARRAY_SIZE(ibm405ex_fbdv_multi_bits); index++)
+               if (cpr_fbdv == (u32)ibm405ex_fbdv_multi_bits[index])
+                       return index + 1;
+
+       return 0;
+}
+
+void ibm405ex_fixup_clocks(unsigned int sys_clk, unsigned int uart_clk)
+{
+       /* PLL config */
+       u32 pllc  = CPR0_READ(DCRN_CPR0_PLLC);
+       u32 plld  = CPR0_READ(DCRN_CPR0_PLLD);
+       u32 cpud  = CPR0_READ(DCRN_CPR0_PRIMAD);
+       u32 plbd  = CPR0_READ(DCRN_CPR0_PRIMBD);
+       u32 opbd  = CPR0_READ(DCRN_CPR0_OPBD);
+       u32 perd  = CPR0_READ(DCRN_CPR0_PERD);
+
+       /* Dividers */
+       u32 fbdv   = ibm405ex_get_fbdv(__fix_zero((plld >> 24) & 0xff, 1));
+
+       u32 fwdva  = ibm405ex_get_fwdva(__fix_zero((plld >> 16) & 0x0f, 1));
+
+       u32 cpudv0 = __fix_zero((cpud >> 24) & 7, 8);
+
+       /* PLBDV0 is hardwared to 010. */
+       u32 plbdv0 = 2;
+       u32 plb2xdv0 = __fix_zero((plbd >> 16) & 7, 8);
+
+       u32 opbdv0 = __fix_zero((opbd >> 24) & 3, 4);
+
+       u32 perdv0 = __fix_zero((perd >> 24) & 3, 4);
+
+       /* Resulting clocks */
+       u32 cpu, plb, opb, ebc, vco, tb, uart0, uart1;
+
+       /* PLL's VCO is the source for primary forward ? */
+       if (pllc & 0x40000000) {
+               u32 m;
+
+               /* Feedback path */
+               switch ((pllc >> 24) & 7) {
+               case 0:
+                       /* PLLOUTx */
+                       m = fbdv;
+                       break;
+               case 1:
+                       /* CPU */
+                       m = fbdv * fwdva * cpudv0;
+                       break;
+               case 5:
+                       /* PERClk */
+                       m = fbdv * fwdva * plb2xdv0 * plbdv0 * opbdv0 * perdv0;
+                       break;
+               default:
+                       printf("WARNING ! Invalid PLL feedback source !\n");
+                       goto bypass;
+               }
+
+               vco = (unsigned int)(sys_clk * m);
+       } else {
+bypass:
+               /* Bypass system PLL */
+               vco = 0;
+       }
+
+       /* CPU = VCO / ( FWDVA x CPUDV0) */
+       cpu = vco / (fwdva * cpudv0);
+       /* PLB = VCO / ( FWDVA x PLB2XDV0 x PLBDV0) */
+       plb = vco / (fwdva * plb2xdv0 * plbdv0);
+       /* OPB = PLB / OPBDV0 */
+       opb = plb / opbdv0;
+       /* EBC = OPB / PERDV0 */
+       ebc = opb / perdv0;
+
+       tb = cpu;
+       uart0 = uart1 = uart_clk;
+
+       dt_fixup_cpu_clocks(cpu, tb, 0);
+       dt_fixup_clock("/plb", plb);
+       dt_fixup_clock("/plb/opb", opb);
+       dt_fixup_clock("/plb/opb/ebc", ebc);
+       dt_fixup_clock("/plb/opb/serial@ef600200", uart0);
+       dt_fixup_clock("/plb/opb/serial@ef600300", uart1);
+}
index 2606e64f0c4b02b1d6cd85d801d8c762a32a6386..7dc5d45361bccf76251c66af3226ac374cfe966c 100644 (file)
@@ -21,6 +21,7 @@ void ibm4xx_fixup_ebc_ranges(const char *ebc);
 
 void ibm405gp_fixup_clocks(unsigned int sys_clk, unsigned int ser_clk);
 void ibm405ep_fixup_clocks(unsigned int sys_clk);
+void ibm405ex_fixup_clocks(unsigned int sys_clk, unsigned int uart_clk);
 void ibm440gp_fixup_clocks(unsigned int sys_clk, unsigned int ser_clk);
 void ibm440ep_fixup_clocks(unsigned int sys_clk, unsigned int ser_clk,
                           unsigned int tmr_clk);
index 9ae7b7e2ba71d287d935adabbf042e58004221a3..7bfc8ad8779876e33b2ea6522ba4651dfbcccde6 100644 (file)
@@ -39,6 +39,7 @@ DTS_FLAGS     ?= -p 1024
 
 $(obj)/4xx.o: BOOTCFLAGS += -mcpu=405
 $(obj)/ebony.o: BOOTCFLAGS += -mcpu=405
+$(obj)/cuboot-hotfoot.o: BOOTCFLAGS += -mcpu=405
 $(obj)/cuboot-taishan.o: BOOTCFLAGS += -mcpu=405
 $(obj)/cuboot-katmai.o: BOOTCFLAGS += -mcpu=405
 $(obj)/cuboot-acadia.o: BOOTCFLAGS += -mcpu=405
@@ -67,7 +68,7 @@ src-wlib := string.S crt0.S crtsavres.S stdio.c main.c \
                cpm-serial.c stdlib.c mpc52xx-psc.c planetcore.c uartlite.c \
                fsl-soc.c mpc8xx.c pq2.c
 src-plat := of.c cuboot-52xx.c cuboot-824x.c cuboot-83xx.c cuboot-85xx.c holly.c \
-               cuboot-ebony.c treeboot-ebony.c prpmc2800.c \
+               cuboot-ebony.c cuboot-hotfoot.c treeboot-ebony.c prpmc2800.c \
                ps3-head.S ps3-hvcall.S ps3.c treeboot-bamboo.c cuboot-8xx.c \
                cuboot-pq2.c cuboot-sequoia.c treeboot-walnut.c \
                cuboot-bamboo.c cuboot-mpc7448hpc2.c cuboot-taishan.c \
@@ -75,7 +76,7 @@ src-plat := of.c cuboot-52xx.c cuboot-824x.c cuboot-83xx.c cuboot-85xx.c holly.c
                cuboot-katmai.c cuboot-rainier.c redboot-8xx.c ep8248e.c \
                cuboot-warp.c cuboot-85xx-cpm2.c cuboot-yosemite.c simpleboot.c \
                virtex405-head.S virtex.c redboot-83xx.c cuboot-sam440ep.c \
-               cuboot-acadia.c cuboot-amigaone.c
+               cuboot-acadia.c cuboot-amigaone.c cuboot-kilauea.c
 src-boot := $(src-wlib) $(src-plat) empty.c
 
 src-boot := $(addprefix $(obj)/, $(src-boot))
@@ -190,6 +191,7 @@ image-$(CONFIG_DEFAULT_UIMAGE)              += uImage
 
 # Board ports in arch/powerpc/platform/40x/Kconfig
 image-$(CONFIG_EP405)                  += dtbImage.ep405
+image-$(CONFIG_HOTFOOT)                        += cuImage.hotfoot
 image-$(CONFIG_WALNUT)                 += treeImage.walnut
 image-$(CONFIG_ACADIA)                 += cuImage.acadia
 
diff --git a/arch/powerpc/boot/cuboot-hotfoot.c b/arch/powerpc/boot/cuboot-hotfoot.c
new file mode 100644 (file)
index 0000000..8f697b9
--- /dev/null
@@ -0,0 +1,142 @@
+/*
+ * Old U-boot compatibility for Esteem 195E Hotfoot CPU Board
+ *
+ * Author: Solomon Peachy <solomon@linux-wlan.com>
+ *
+ * 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.
+ */
+
+#include "ops.h"
+#include "stdio.h"
+#include "reg.h"
+#include "dcr.h"
+#include "4xx.h"
+#include "cuboot.h"
+
+#define TARGET_4xx
+#define TARGET_HOTFOOT
+
+#include "ppcboot-hotfoot.h"
+
+static bd_t bd;
+
+#define NUM_REGS 3
+
+static void hotfoot_fixups(void)
+{
+       u32 uart = mfdcr(DCRN_CPC0_UCR) & 0x7f;
+
+       dt_fixup_memory(bd.bi_memstart, bd.bi_memsize); 
+
+       dt_fixup_cpu_clocks(bd.bi_procfreq, bd.bi_procfreq, 0);
+       dt_fixup_clock("/plb", bd.bi_plb_busfreq);
+       dt_fixup_clock("/plb/opb", bd.bi_opbfreq);
+       dt_fixup_clock("/plb/ebc", bd.bi_pci_busfreq);
+       dt_fixup_clock("/plb/opb/serial@ef600300", bd.bi_procfreq / uart); 
+       dt_fixup_clock("/plb/opb/serial@ef600400", bd.bi_procfreq / uart); 
+       
+       dt_fixup_mac_address_by_alias("ethernet0", bd.bi_enetaddr);
+       dt_fixup_mac_address_by_alias("ethernet1", bd.bi_enet1addr);
+
+       /* Is this a single eth/serial board? */
+       if ((bd.bi_enet1addr[0] == 0) && 
+           (bd.bi_enet1addr[1] == 0) &&
+           (bd.bi_enet1addr[2] == 0) &&
+           (bd.bi_enet1addr[3] == 0) &&
+           (bd.bi_enet1addr[4] == 0) &&
+           (bd.bi_enet1addr[5] == 0)) {
+               void *devp;
+
+               printf("Trimming devtree for single serial/eth board\n");
+
+               devp = finddevice("/plb/opb/serial@ef600300");
+               if (!devp)
+                       fatal("Can't find node for /plb/opb/serial@ef600300");
+               del_node(devp);
+
+               devp = finddevice("/plb/opb/ethernet@ef600900");
+               if (!devp)
+                       fatal("Can't find node for /plb/opb/ethernet@ef600900");
+               del_node(devp);
+       }
+
+       ibm4xx_quiesce_eth((u32 *)0xef600800, (u32 *)0xef600900);
+
+       /* Fix up flash size in fdt for 4M boards. */
+       if (bd.bi_flashsize < 0x800000) {
+               u32 regs[NUM_REGS];
+               void *devp = finddevice("/plb/ebc/nor_flash@0");
+               if (!devp)
+                       fatal("Can't find FDT node for nor_flash!??");
+
+               printf("Fixing devtree for 4M Flash\n");
+               
+               /* First fix up the base addresse */
+               getprop(devp, "reg", regs, sizeof(regs));
+               regs[0] = 0;
+               regs[1] = 0xffc00000;
+               regs[2] = 0x00400000;
+               setprop(devp, "reg", regs, sizeof(regs));
+               
+               /* Then the offsets */
+               devp = finddevice("/plb/ebc/nor_flash@0/partition@0");
+               if (!devp)
+                       fatal("Can't find FDT node for partition@0");
+               getprop(devp, "reg", regs, 2*sizeof(u32));
+               regs[0] -= 0x400000;
+               setprop(devp, "reg", regs,  2*sizeof(u32));
+
+               devp = finddevice("/plb/ebc/nor_flash@0/partition@1");
+               if (!devp)
+                       fatal("Can't find FDT node for partition@1");
+               getprop(devp, "reg", regs, 2*sizeof(u32));
+               regs[0] -= 0x400000;
+               setprop(devp, "reg", regs,  2*sizeof(u32));
+
+               devp = finddevice("/plb/ebc/nor_flash@0/partition@2");
+               if (!devp)
+                       fatal("Can't find FDT node for partition@2");
+               getprop(devp, "reg", regs, 2*sizeof(u32));
+               regs[0] -= 0x400000;
+               setprop(devp, "reg", regs,  2*sizeof(u32));
+
+               devp = finddevice("/plb/ebc/nor_flash@0/partition@3");
+               if (!devp)
+                       fatal("Can't find FDT node for partition@3");
+               getprop(devp, "reg", regs, 2*sizeof(u32));
+               regs[0] -= 0x400000;
+               setprop(devp, "reg", regs,  2*sizeof(u32));
+
+               devp = finddevice("/plb/ebc/nor_flash@0/partition@4");
+               if (!devp)
+                       fatal("Can't find FDT node for partition@4");
+               getprop(devp, "reg", regs, 2*sizeof(u32));
+               regs[0] -= 0x400000;
+               setprop(devp, "reg", regs,  2*sizeof(u32));
+
+               devp = finddevice("/plb/ebc/nor_flash@0/partition@6");
+               if (!devp)
+                       fatal("Can't find FDT node for partition@6");
+               getprop(devp, "reg", regs, 2*sizeof(u32));
+               regs[0] -= 0x400000;
+               setprop(devp, "reg", regs,  2*sizeof(u32));
+
+               /* Delete the FeatFS node */
+               devp = finddevice("/plb/ebc/nor_flash@0/partition@5");
+               if (!devp)
+                       fatal("Can't find FDT node for partition@5");
+               del_node(devp);
+       }
+}
+
+void platform_init(unsigned long r3, unsigned long r4, unsigned long r5,
+                  unsigned long r6, unsigned long r7)
+{
+       CUBOOT_INIT();
+       platform_ops.fixups = hotfoot_fixups;
+        platform_ops.exit = ibm40x_dbcr_reset;
+       fdt_init(_dtb_start);
+       serial_console_init();
+}
diff --git a/arch/powerpc/boot/cuboot-kilauea.c b/arch/powerpc/boot/cuboot-kilauea.c
new file mode 100644 (file)
index 0000000..80cdad6
--- /dev/null
@@ -0,0 +1,49 @@
+/*
+ * Old U-boot compatibility for PPC405EX. This image is already included
+ * a dtb.
+ *
+ * Author: Tiejun Chen <tiejun.chen@windriver.com>
+ *
+ * Copyright (C) 2009 Wind River Systems, Inc.
+ *
+ * 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.
+ */
+
+#include "ops.h"
+#include "io.h"
+#include "dcr.h"
+#include "stdio.h"
+#include "4xx.h"
+#include "44x.h"
+#include "cuboot.h"
+
+#define TARGET_4xx
+#define TARGET_44x
+#include "ppcboot.h"
+
+#define KILAUEA_SYS_EXT_SERIAL_CLOCK     11059200        /* ext. 11.059MHz clk */
+
+static bd_t bd;
+
+static void kilauea_fixups(void)
+{
+       unsigned long sysclk = 33333333;
+
+       ibm405ex_fixup_clocks(sysclk, KILAUEA_SYS_EXT_SERIAL_CLOCK);
+       dt_fixup_memory(bd.bi_memstart, bd.bi_memsize);
+       ibm4xx_fixup_ebc_ranges("/plb/opb/ebc");
+       dt_fixup_mac_address_by_alias("ethernet0", bd.bi_enetaddr);
+       dt_fixup_mac_address_by_alias("ethernet1", bd.bi_enet1addr);
+}
+
+void platform_init(unsigned long r3, unsigned long r4, unsigned long r5,
+               unsigned long r6, unsigned long r7)
+{
+       CUBOOT_INIT();
+       platform_ops.fixups = kilauea_fixups;
+       platform_ops.exit = ibm40x_dbcr_reset;
+       fdt_init(_dtb_start);
+       serial_console_init();
+}
index 95b9f5344016a619d97d413d738dc89394c28511..645a7c964e5fce7221e7ef12f04ec5423188df59 100644 (file)
@@ -153,9 +153,7 @@ static const unsigned long sdram_bxcr[] = { SDRAM0_B0CR, SDRAM0_B1CR,
 #define DCRN_CPC0_PLLMR1  0xf4
 #define DCRN_CPC0_UCR     0xf5
 
-/* 440GX Clock control etc */
-
-
+/* 440GX/405EX Clock Control reg */
 #define DCRN_CPR0_CLKUPD                               0x020
 #define DCRN_CPR0_PLLC                                 0x040
 #define DCRN_CPR0_PLLD                                 0x060
index d9113b1e8c1d75fe95bb1cfb44569cd2d9501d02..414ef8b7e5753b7f5b31a2c26ec7f7e54dbc8cb5 100644 (file)
                dcr-reg = <0x00c 0x002>;
        };
 
+       L2C0: l2c {
+               compatible = "ibm,l2-cache-460gt", "ibm,l2-cache";
+               dcr-reg = <0x020 0x008          /* Internal SRAM DCR's */
+                          0x030 0x008>;        /* L2 cache DCR's */
+               cache-line-size = <32>;         /* 32 bytes */
+               cache-size = <262144>;          /* L2, 256K */
+               interrupt-parent = <&UIC1>;
+               interrupts = <11 1>;
+       };
+
        plb {
                compatible = "ibm,plb-460gt", "ibm,plb4";
                #address-cells = <2>;
                                /* ranges property is supplied by U-Boot */
                                interrupts = <0x6 0x4>;
                                interrupt-parent = <&UIC1>;
+
+                               nor_flash@0,0 {
+                                       compatible = "amd,s29gl256n", "cfi-flash";
+                                       bank-width = <2>;
+                                       reg = <0x00000000 0x00000000 0x02000000>;
+                                       #address-cells = <1>;
+                                       #size-cells = <1>;
+                                       partition@0 {
+                                               label = "kernel";
+                                               reg = <0x00000000 0x001e0000>;
+                                       };
+                                       partition@1e0000 {
+                                               label = "dtb";
+                                               reg = <0x001e0000 0x00020000>;
+                                       };
+                                       partition@200000 {
+                                               label = "root";
+                                               reg = <0x00200000 0x00200000>;
+                                       };
+                                       partition@400000 {
+                                               label = "user";
+                                               reg = <0x00400000 0x01b60000>;
+                                       };
+                                       partition@1f60000 {
+                                               label = "env";
+                                               reg = <0x01f60000 0x00040000>;
+                                       };
+                                       partition@1fa0000 {
+                                               label = "u-boot";
+                                               reg = <0x01fa0000 0x00060000>;
+                                       };
+                               };
                        };
 
                        UART0: serial@ef600300 {
                                reg = <0xef600700 0x00000014>;
                                interrupt-parent = <&UIC0>;
                                interrupts = <0x2 0x4>;
+                               #address-cells = <1>;
+                               #size-cells = <0>;
+                               sttm@4a {
+                                       compatible = "ad,ad7414";
+                                       reg = <0x4a>;
+                                       interrupt-parent = <&UIC1>;
+                                       interrupts = <0x0 0x8>;
+                               };
                        };
 
                        IIC1: i2c@ef600800 {
index 5fd1ad09bdf2c1661b0293fd19fcff9f58f71767..c920170b7dfefd9d70bb29e1a2d71e6ccb860b88 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * Device Tree Source for AMCC Canyonlands (460EX)
  *
- * Copyright 2008 DENX Software Engineering, Stefan Roese <sr@denx.de>
+ * Copyright 2008-2009 DENX Software Engineering, Stefan Roese <sr@denx.de>
  *
  * This file is licensed under the terms of the GNU General Public
  * License version 2.  This program is licensed "as is" without
                                        /*RXDE*/  0x5 0x4>;
                };
 
-                USB0: ehci@bffd0400 {
-                        compatible = "ibm,usb-ehci-460ex", "usb-ehci";
-                        interrupt-parent = <&UIC2>;
-                        interrupts = <0x1d 4>;
-                        reg = <4 0xbffd0400 0x90 4 0xbffd0490 0x70>;
-                };
+               USB0: ehci@bffd0400 {
+                       compatible = "ibm,usb-ehci-460ex", "usb-ehci";
+                       interrupt-parent = <&UIC2>;
+                       interrupts = <0x1d 4>;
+                       reg = <4 0xbffd0400 0x90 4 0xbffd0490 0x70>;
+               };
 
-                USB1: usb@bffd0000 {
-                        compatible = "ohci-le";
-                        reg = <4 0xbffd0000 0x60>;
-                        interrupt-parent = <&UIC2>;
-                        interrupts = <0x1e 4>;
-                };
+               USB1: usb@bffd0000 {
+                       compatible = "ohci-le";
+                       reg = <4 0xbffd0000 0x60>;
+                       interrupt-parent = <&UIC2>;
+                       interrupts = <0x1e 4>;
+               };
 
                POB0: opb {
                        compatible = "ibm,opb-460ex", "ibm,opb";
                                                reg = <0x03fa0000 0x00060000>;
                                        };
                                };
+
+                               ndfc@3,0 {
+                                       compatible = "ibm,ndfc";
+                                       reg = <0x00000003 0x00000000 0x00002000>;
+                                       ccr = <0x00001000>;
+                                       bank-settings = <0x80002222>;
+                                       #address-cells = <1>;
+                                       #size-cells = <1>;
+
+                                       nand {
+                                               #address-cells = <1>;
+                                               #size-cells = <1>;
+
+                                               partition@0 {
+                                                       label = "u-boot";
+                                                       reg = <0x00000000 0x00100000>;
+                                               };
+                                               partition@100000 {
+                                                       label = "user";
+                                                       reg = <0x00000000 0x03f00000>;
+                                               };
+                                       };
+                               };
                        };
 
                        UART0: serial@ef600300 {
diff --git a/arch/powerpc/boot/dts/eiger.dts b/arch/powerpc/boot/dts/eiger.dts
new file mode 100644 (file)
index 0000000..c4a934f
--- /dev/null
@@ -0,0 +1,421 @@
+/*
+ * Device Tree Source for AMCC (AppliedMicro) Eiger(460SX)
+ *
+ * Copyright 2009 AMCC (AppliedMicro) <ttnguyen@amcc.com>
+ *
+ * This file is licensed under the terms of the GNU General Public
+ * License version 2.  This program is licensed "as is" without
+ * any warranty of any kind, whether express or implied.
+ */
+
+/dts-v1/;
+
+/ {
+       #address-cells = <2>;
+       #size-cells = <1>;
+       model = "amcc,eiger";
+       compatible = "amcc,eiger";
+       dcr-parent = <&{/cpus/cpu@0}>;
+
+       aliases {
+               ethernet0 = &EMAC0;
+               ethernet1 = &EMAC1;
+               ethernet2 = &EMAC2;
+               ethernet3 = &EMAC3;
+               serial0 = &UART0;
+               serial1 = &UART1;
+       };
+
+       cpus {
+               #address-cells = <1>;
+               #size-cells = <0>;
+
+               cpu@0 {
+                       device_type = "cpu";
+                       model = "PowerPC,460SX";
+                       reg = <0x00000000>;
+                       clock-frequency = <0>; /* Filled in by U-Boot */
+                       timebase-frequency = <0>; /* Filled in by U-Boot */
+                       i-cache-line-size = <32>;
+                       d-cache-line-size = <32>;
+                       i-cache-size = <32768>;
+                       d-cache-size = <32768>;
+                       dcr-controller;
+                       dcr-access-method = "native";
+               };
+       };
+
+       memory {
+               device_type = "memory";
+               reg = <0x00000000 0x00000000 0x00000000>; /* Filled in by U-Boot */
+       };
+
+       UIC0: interrupt-controller0 {
+               compatible = "ibm,uic-460sx","ibm,uic";
+               interrupt-controller;
+               cell-index = <0>;
+               dcr-reg = <0x0c0 0x009>;
+               #address-cells = <0>;
+               #size-cells = <0>;
+               #interrupt-cells = <2>;
+       };
+
+       UIC1: interrupt-controller1 {
+               compatible = "ibm,uic-460sx","ibm,uic";
+               interrupt-controller;
+               cell-index = <1>;
+               dcr-reg = <0x0d0 0x009>;
+               #address-cells = <0>;
+               #size-cells = <0>;
+               #interrupt-cells = <2>;
+               interrupts = <0x1e 0x4 0x1f 0x4>; /* cascade */
+               interrupt-parent = <&UIC0>;
+       };
+
+       UIC2: interrupt-controller2 {
+               compatible = "ibm,uic-460sx","ibm,uic";
+               interrupt-controller;
+               cell-index = <2>;
+               dcr-reg = <0x0e0 0x009>;
+               #address-cells = <0>;
+               #size-cells = <0>;
+               #interrupt-cells = <2>;
+               interrupts = <0xa 0x4 0xb 0x4>; /* cascade */
+               interrupt-parent = <&UIC0>;
+       };
+
+       UIC3: interrupt-controller3 {
+               compatible = "ibm,uic-460sx","ibm,uic";
+               interrupt-controller;
+               cell-index = <3>;
+               dcr-reg = <0x0f0 0x009>;
+               #address-cells = <0>;
+               #size-cells = <0>;
+               #interrupt-cells = <2>;
+               interrupts = <0x10 0x4 0x11 0x4>; /* cascade */
+               interrupt-parent = <&UIC0>;
+       };
+
+       SDR0: sdr {
+               compatible = "ibm,sdr-460sx";
+               dcr-reg = <0x00e 0x002>;
+       };
+
+       CPR0: cpr {
+               compatible = "ibm,cpr-460sx";
+               dcr-reg = <0x00c 0x002>;
+       };
+
+       plb {
+               compatible = "ibm,plb-460sx", "ibm,plb4";
+               #address-cells = <2>;
+               #size-cells = <1>;
+               ranges;
+               clock-frequency = <0>; /* Filled in by U-Boot */
+
+               SDRAM0: sdram {
+                       compatible = "ibm,sdram-460sx", "ibm,sdram-405gp";
+                       dcr-reg = <0x010 0x002>;
+               };
+
+               MAL0: mcmal {
+                       compatible = "ibm,mcmal-460sx", "ibm,mcmal2";
+                       dcr-reg = <0x180 0x62>;
+                       num-tx-chans = <4>;
+                       num-rx-chans = <32>;
+                       #address-cells = <1>;
+                       #size-cells = <1>;
+                       interrupt-parent = <&UIC1>;
+                       interrupts = <  /*TXEOB*/ 0x6 0x4
+                                       /*RXEOB*/ 0x7 0x4
+                                       /*SERR*/  0x1 0x4
+                                       /*TXDE*/  0x2 0x4
+                                       /*RXDE*/  0x3 0x4
+                                       /*COAL TX0*/ 0x18 0x2
+                                       /*COAL TX1*/ 0x19 0x2
+                                       /*COAL TX2*/ 0x1a 0x2
+                                       /*COAL TX3*/ 0x1b 0x2
+                                       /*COAL RX0*/ 0x1c 0x2
+                                       /*COAL RX1*/ 0x1d 0x2
+                                       /*COAL RX2*/ 0x1e 0x2
+                                       /*COAL RX3*/ 0x1f 0x2>;
+               };
+
+               POB0: opb {
+                       compatible = "ibm,opb-460sx", "ibm,opb";
+                       #address-cells = <1>;
+                       #size-cells = <1>;
+                       ranges = <0xb0000000 0x00000004 0xb0000000 0x50000000>;
+                       clock-frequency = <0>; /* Filled in by U-Boot */
+
+                       EBC0: ebc {
+                               compatible = "ibm,ebc-460sx", "ibm,ebc";
+                               dcr-reg = <0x012 0x002>;
+                               #address-cells = <2>;
+                               #size-cells = <1>;
+                               clock-frequency = <0>; /* Filled in by U-Boot */
+                               /* ranges property is supplied by U-Boot */
+                               interrupts = <0x6 0x4>;
+                               interrupt-parent = <&UIC1>;
+
+                               nor_flash@0,0 {
+                                       compatible = "amd,s29gl512n", "cfi-flash";
+                                       bank-width = <2>;
+                                       /* reg property is supplied in by U-Boot */
+                                       #address-cells = <1>;
+                                       #size-cells = <1>;
+                                       partition@0 {
+                                               label = "kernel";
+                                               reg = <0x00000000 0x001e0000>;
+                                       };
+                                       partition@1e0000 {
+                                               label = "dtb";
+                                               reg = <0x001e0000 0x00020000>;
+                                       };
+                                       partition@200000 {
+                                               label = "ramdisk";
+                                               reg = <0x00200000 0x01400000>;
+                                       };
+                                       partition@1600000 {
+                                               label = "jffs2";
+                                               reg = <0x01600000 0x00400000>;
+                                       };
+                                       partition@1a00000 {
+                                               label = "user";
+                                               reg = <0x01a00000 0x02560000>;
+                                       };
+                                       partition@3f60000 {
+                                               label = "env";
+                                               reg = <0x03f60000 0x00040000>;
+                                       };
+                                       partition@3fa0000 {
+                                               label = "u-boot";
+                                               reg = <0x03fa0000 0x00060000>;
+                                       };
+                               };
+
+                               ndfc@1,0 {
+                                       compatible = "ibm,ndfc";
+                                       /* reg property is supplied by U-boot */
+                                       ccr = <0x00003000>;
+                                       bank-settings = <0x80002222>;
+                                       #address-cells = <1>;
+                                       #size-cells = <1>;
+
+                                       nand {
+                                               #address-cells = <1>;
+                                               #size-cells = <1>;
+                                               partition@0 {
+                                                       label = "uboot";
+                                                       reg = <0x00000000 0x00200000>;
+                                               };
+                                               partition@200000 {
+                                                       label = "uboot-environment";
+                                                       reg = <0x00200000 0x00100000>;
+                                               };
+                                               partition@300000 {
+                                                       label = "linux";
+                                                       reg = <0x00300000 0x00300000>;
+                                               };
+                                               partition@600000 {
+                                                       label = "root-file-system";
+                                                       reg = <0x00600000 0x01900000>;
+                                               };
+                                               partition@1f00000 {
+                                                       label = "device-tree";
+                                                       reg = <0x01f00000 0x00020000>;
+                                               };
+                                               partition@1f20000 {
+                                                       label = "data";
+                                                       reg = <0x01f20000 0x060E0000>;
+                                               };
+                                       };
+                               };
+                       };
+
+                       UART0: serial@ef600200 {
+                               device_type = "serial";
+                               compatible = "ns16550";
+                               reg = <0xef600200 0x00000008>;
+                               virtual-reg = <0xef600200>;
+                               clock-frequency = <0>; /* Filled in by U-Boot */
+                               current-speed = <0>; /* Filled in by U-Boot */
+                               interrupt-parent = <&UIC0>;
+                               interrupts = <0x0 0x4>;
+                       };
+
+                       UART1: serial@ef600300 {
+                               device_type = "serial";
+                               compatible = "ns16550";
+                               reg = <0xef600300 0x00000008>;
+                               virtual-reg = <0xef600300>;
+                               clock-frequency = <0>; /* Filled in by U-Boot */
+                               current-speed = <0>; /* Filled in by U-Boot */
+                               interrupt-parent = <&UIC0>;
+                               interrupts = <0x1 0x4>;
+                       };
+
+                       IIC0: i2c@ef600400 {
+                               compatible = "ibm,iic-460sx", "ibm,iic";
+                               reg = <0xef600400 0x00000014>;
+                               interrupt-parent = <&UIC0>;
+                               interrupts = <0x2 0x4>;
+                               #address-cells = <1>;
+                               #size-cells = <0>;
+                               index = <0>;
+                       };
+
+                       IIC1: i2c@ef600500 {
+                               compatible = "ibm,iic-460sx", "ibm,iic";
+                               reg = <0xef600500 0x00000014>;
+                               interrupt-parent = <&UIC0>;
+                               interrupts = <0x3 0x4>;
+                               #address-cells = <1>;
+                               #size-cells = <0>;
+                               index = <1>;
+                       };
+
+                       RGMII0: emac-rgmii@ef600900 {
+                               compatible = "ibm,rgmii-460sx", "ibm,rgmii";
+                               reg = <0xef600900 0x00000008>;
+                               has-mdio;
+                       };
+
+                       RGMII1: emac-rgmii@ef600920 {
+                               compatible = "ibm,rgmii-460sx", "ibm,rgmii";
+                               reg = <0xef600920 0x00000008>;
+                               has-mdio;
+                       };
+
+                       TAH0: emac-tah@ef600e50 {
+                               compatible = "ibm,tah-460sx", "ibm,tah";
+                               reg = <0xef600e50 0x00000030>;
+                       };
+
+                       TAH1: emac-tah@ef600f50 {
+                               compatible = "ibm,tah-460sx", "ibm,tah";
+                               reg = <0xef600f50 0x00000030>;
+                       };
+
+                       EMAC0: ethernet@ef600a00 {
+                               device_type = "network";
+                               compatible = "ibm,emac-460sx", "ibm,emac4";
+                               interrupt-parent = <&EMAC0>;
+                               interrupts = <0x0 0x1>;
+                               #interrupt-cells = <1>;
+                               #address-cells = <0>;
+                               #size-cells = <0>;
+                               interrupt-map = </*Status*/ 0x0 &UIC0 0x13 0x4
+                                                /*Wake*/   0x1 &UIC2 0x1d 0x4>;
+                               reg = <0xef600a00 0x00000070>;
+                               local-mac-address = [000000000000]; /* Filled in by U-Boot */
+                               mal-device = <&MAL0>;
+                               mal-tx-channel = <0>;
+                               mal-rx-channel = <0>;
+                               cell-index = <0>;
+                               max-frame-size = <9000>;
+                               rx-fifo-size = <4096>;
+                               tx-fifo-size = <2048>;
+                               phy-mode = "rgmii";
+                               phy-map = <0x00000000>;
+                               rgmii-device = <&RGMII0>;
+                               rgmii-channel = <0>;
+                               tah-device = <&TAH0>;
+                               tah-channel = <0>;
+                               has-inverted-stacr-oc;
+                               has-new-stacr-staopc;
+                       };
+
+                       EMAC1: ethernet@ef600b00 {
+                               device_type = "network";
+                               compatible = "ibm,emac-460sx", "ibm,emac4";
+                               interrupt-parent = <&EMAC1>;
+                               interrupts = <0x0 0x1>;
+                               #interrupt-cells = <1>;
+                               #address-cells = <0>;
+                               #size-cells = <0>;
+                               interrupt-map = </*Status*/ 0x0 &UIC0 0x14 0x4
+                                                /*Wake*/   0x1 &UIC2 0x1d 0x4>;
+                               reg = <0xef600b00 0x00000070>;
+                               local-mac-address = [000000000000]; /* Filled in by U-Boot */
+                               mal-device = <&MAL0>;
+                               mal-tx-channel = <1>;
+                               mal-rx-channel = <8>;
+                               cell-index = <1>;
+                               max-frame-size = <9000>;
+                               rx-fifo-size = <4096>;
+                               tx-fifo-size = <2048>;
+                               phy-mode = "rgmii";
+                               phy-map = <0x00000000>;
+                               rgmii-device = <&RGMII0>;
+                               rgmii-channel = <1>;
+                               tah-device = <&TAH1>;
+                               tah-channel = <1>;
+                               has-inverted-stacr-oc;
+                               has-new-stacr-staopc;
+                               mdio-device = <&EMAC0>;
+                       };
+
+                       EMAC2: ethernet@ef600c00 {
+                               device_type = "network";
+                               compatible = "ibm,emac-460sx", "ibm,emac4";
+                               interrupt-parent = <&EMAC2>;
+                               interrupts = <0x0 0x1>;
+                               #interrupt-cells = <1>;
+                               #address-cells = <0>;
+                               #size-cells = <0>;
+                               interrupt-map = </*Status*/ 0x0 &UIC0 0x15 0x4
+                                                /*Wake*/   0x1 &UIC2 0x1d 0x4>;
+                               reg = <0xef600c00 0x00000070>;
+                               local-mac-address = [000000000000]; /* Filled in by U-Boot */
+                               mal-device = <&MAL0>;
+                               mal-tx-channel = <2>;
+                               mal-rx-channel = <16>;
+                               cell-index = <2>;
+                               max-frame-size = <9000>;
+                               rx-fifo-size = <4096>;
+                               tx-fifo-size = <2048>;
+                               phy-mode = "rgmii";
+                               phy-map = <0x00000000>;
+                               rgmii-device = <&RGMII1>;
+                               rgmii-channel = <0>;
+                               has-inverted-stacr-oc;
+                               has-new-stacr-staopc;
+                               mdio-device = <&EMAC0>;
+                       };
+
+                       EMAC3: ethernet@ef600d00 {
+                               device_type = "network";
+                               compatible = "ibm,emac-460sx", "ibm,emac4";
+                               interrupt-parent = <&EMAC3>;
+                               interrupts = <0x0 0x1>;
+                               #interrupt-cells = <1>;
+                               #address-cells = <0>;
+                               #size-cells = <0>;
+                               interrupt-map = </*Status*/ 0x0 &UIC0 0x16 0x4
+                                                /*Wake*/   0x1 &UIC2 0x1d 0x4>;
+                               reg = <0xef600d00 0x00000070>;
+                               local-mac-address = [000000000000]; /* Filled in by U-Boot */
+                               mal-device = <&MAL0>;
+                               mal-tx-channel = <3>;
+                               mal-rx-channel = <24>;
+                               cell-index = <3>;
+                               max-frame-size = <9000>;
+                               rx-fifo-size = <4096>;
+                               tx-fifo-size = <2048>;
+                               phy-mode = "rgmii";
+                               phy-map = <0x00000000>;
+                               rgmii-device = <&RGMII1>;
+                               rgmii-channel = <1>;
+                               has-inverted-stacr-oc;
+                               has-new-stacr-staopc;
+                               mdio-device = <&EMAC0>;
+                       };
+               };
+
+       };
+       chosen {
+               linux,stdout-path = "/plb/opb/serial@ef600200";
+       };
+
+};
index 0f4c9ec2c3a619523108360f315b1fc0dd83fa73..2107d3c7cfe1d61bb6632c9445cee03a301fcbb5 100644 (file)
 
                /* flash@0,0 is a mirror of part of the memory in flash@1,0
                flash@0,0 {
-                       compatible = "cfi-flash";
-                       reg = <0 0 0x01000000>;
+                       compatible = "gef,sbc310-firmware-mirror", "cfi-flash";
+                       reg = <0x0 0x0 0x01000000>;
                        bank-width = <2>;
                        device-width = <2>;
                        #address-cells = <1>;
                        #size-cells = <1>;
                        partition@0 {
                                label = "firmware";
-                               reg = <0x00000000 0x01000000>;
+                               reg = <0x0 0x01000000>;
                                read-only;
                        };
                };
                */
 
                flash@1,0 {
-                       compatible = "cfi-flash";
-                       reg = <0 0x8000000>;
+                       compatible = "gef,sbc310-paged-flash", "cfi-flash";
+                       reg = <0x1 0x0 0x8000000>;
                        bank-width = <2>;
                        device-width = <2>;
                        #address-cells = <1>;
                        #size-cells = <1>;
                        partition@0 {
                                label = "user";
-                               reg = <0x00000000 0x07800000>;
+                               reg = <0x0 0x7800000>;
                        };
                        partition@7800000 {
                                label = "firmware";
-                               reg = <0x07800000 0x00800000>;
+                               reg = <0x7800000 0x800000>;
                                read-only;
                        };
                };
                };
 
                wdt@4,2000 {
-                       #interrupt-cells = <2>;
-                       device_type = "watchdog";
-                       compatible = "gef,fpga-wdt";
+                       compatible = "gef,sbc310-fpga-wdt", "gef,fpga-wdt-1.00",
+                               "gef,fpga-wdt";
                        reg = <0x4 0x2000 0x8>;
                        interrupts = <0x1a 0x4>;
                        interrupt-parent = <&gef_pic>;
                };
 /*
                wdt@4,2010 {
-                       #interrupt-cells = <2>;
-                       device_type = "watchdog";
-                       compatible = "gef,fpga-wdt";
+                       compatible = "gef,sbc310-fpga-wdt", "gef,fpga-wdt-1.00",
+                               "gef,fpga-wdt";
                        reg = <0x4 0x2010 0x8>;
                        interrupts = <0x1b 0x4>;
                        interrupt-parent = <&gef_pic>;
                gef_pic: pic@4,4000 {
                        #interrupt-cells = <1>;
                        interrupt-controller;
-                       compatible = "gef,fpga-pic";
+                       compatible = "gef,sbc310-fpga-pic", "gef,fpga-pic";
                        reg = <0x4 0x4000 0x20>;
                        interrupts = <0x8
                                      0x9>;
                #size-cells = <1>;
                #interrupt-cells = <2>;
                device_type = "soc";
-               compatible = "simple-bus";
+               compatible = "fsl,mpc8641-soc", "simple-bus";
                ranges = <0x0 0xfef00000 0x00100000>;
                bus-frequency = <33333333>;
 
                                  0x0 0x00400000>;
                };
        };
+
+       pci1: pcie@fef09000 {
+               compatible = "fsl,mpc8641-pcie";
+               device_type = "pci";
+               #interrupt-cells = <1>;
+               #size-cells = <2>;
+               #address-cells = <3>;
+               reg = <0xfef09000 0x1000>;
+               bus-range = <0x0 0xff>;
+               ranges = <0x02000000 0x0 0xc0000000 0xc0000000 0x0 0x20000000
+                         0x01000000 0x0 0x00000000 0xfe400000 0x0 0x00400000>;
+               clock-frequency = <33333333>;
+               interrupt-parent = <&mpic>;
+               interrupts = <0x19 0x2>;
+               interrupt-map-mask = <0xf800 0x0 0x0 0x7>;
+               interrupt-map = <
+                       0x0000 0x0 0x0 0x1 &mpic 0x4 0x2
+                       0x0000 0x0 0x0 0x2 &mpic 0x5 0x2
+                       0x0000 0x0 0x0 0x3 &mpic 0x6 0x2
+                       0x0000 0x0 0x0 0x4 &mpic 0x7 0x2
+                       >;
+
+               pcie@0 {
+                       reg = <0 0 0 0 0>;
+                       #size-cells = <2>;
+                       #address-cells = <3>;
+                       device_type = "pci";
+                       ranges = <0x02000000 0x0 0xc0000000
+                                 0x02000000 0x0 0xc0000000
+                                 0x0 0x20000000
+
+                                 0x01000000 0x0 0x00000000
+                                 0x01000000 0x0 0x00000000
+                                 0x0 0x00400000>;
+               };
+       };
 };
diff --git a/arch/powerpc/boot/dts/hotfoot.dts b/arch/powerpc/boot/dts/hotfoot.dts
new file mode 100644 (file)
index 0000000..cad9c38
--- /dev/null
@@ -0,0 +1,294 @@
+/*
+ * Device Tree Source for ESTeem 195E Hotfoot
+ *
+ * Copyright 2009 AbsoluteValue Systems <solomon@linux-wlan.com>
+ *
+ * This file is licensed under the terms of the GNU General Public
+ * License version 2.  This program is licensed "as is" without
+ * any warranty of any kind, whether express or implied.
+ */
+
+/dts-v1/;
+
+/ {
+       #address-cells = <1>;
+       #size-cells = <1>;
+       model = "est,hotfoot";
+       compatible = "est,hotfoot";
+       dcr-parent = <&{/cpus/cpu@0}>;
+
+       aliases {
+               ethernet0 = &EMAC0;
+               ethernet1 = &EMAC1;
+               serial0 = &UART0;
+               serial1 = &UART1;
+       };
+
+       cpus {
+               #address-cells = <1>;
+               #size-cells = <0>;
+
+               cpu@0 {
+                       device_type = "cpu";
+                       model = "PowerPC,405EP";
+                       reg = <0x00000000>;
+                       clock-frequency = <0>; /* Filled in by zImage */
+                       timebase-frequency = <0>; /* Filled in by zImage */
+                       i-cache-line-size = <0x20>;
+                       d-cache-line-size = <0x20>;
+                       i-cache-size = <0x4000>;
+                       d-cache-size = <0x4000>;
+                       dcr-controller;
+                       dcr-access-method = "native";
+               };
+       };
+
+       memory {
+               device_type = "memory";
+               reg = <0x00000000 0x00000000>; /* Filled in by zImage */
+       };
+
+       UIC0: interrupt-controller {
+               compatible = "ibm,uic";
+               interrupt-controller;
+               cell-index = <0>;
+               dcr-reg = <0x0c0 0x009>;
+               #address-cells = <0>;
+               #size-cells = <0>;
+               #interrupt-cells = <2>;
+       };
+
+       plb {
+               compatible = "ibm,plb3";
+               #address-cells = <1>;
+               #size-cells = <1>;
+               ranges;
+               clock-frequency = <0>; /* Filled in by zImage */
+
+               SDRAM0: memory-controller {
+                       compatible = "ibm,sdram-405ep";
+                       dcr-reg = <0x010 0x002>;
+               };
+
+               MAL: mcmal {
+                       compatible = "ibm,mcmal-405ep", "ibm,mcmal";
+                       dcr-reg = <0x180 0x062>;
+                       num-tx-chans = <4>;
+                       num-rx-chans = <2>;
+                       interrupt-parent = <&UIC0>;
+                       interrupts = <
+                               0xb 0x4 /* TXEOB */
+                               0xc 0x4 /* RXEOB */
+                               0xa 0x4 /* SERR */
+                               0xd 0x4 /* TXDE */
+                               0xe 0x4 /* RXDE */>;
+               };
+
+               POB0: opb {
+                       compatible = "ibm,opb-405ep", "ibm,opb";
+                       #address-cells = <1>;
+                       #size-cells = <1>;
+                       ranges = <0xef600000 0xef600000 0x00a00000>;
+                       dcr-reg = <0x0a0 0x005>;
+                       clock-frequency = <0>; /* Filled in by zImage */
+
+                       /* Hotfoot has UART0/UART1 swapped */
+
+                       UART0: serial@ef600400 {
+                               device_type = "serial";
+                               compatible = "ns16550";
+                               reg = <0xef600400 0x00000008>;
+                               virtual-reg = <0xef600400>;
+                               clock-frequency = <0>; /* Filled in by zImage */
+                               current-speed = <0x9600>;
+                               interrupt-parent = <&UIC0>;
+                               interrupts = <0x1 0x4>;
+                       };
+
+                       UART1: serial@ef600300 {
+                               device_type = "serial";
+                               compatible = "ns16550";
+                               reg = <0xef600300 0x00000008>;
+                               virtual-reg = <0xef600300>;
+                               clock-frequency = <0>; /* Filled in by zImage */
+                               current-speed = <0x9600>;
+                               interrupt-parent = <&UIC0>;
+                               interrupts = <0x0 0x4>;
+                       };
+
+                       IIC: i2c@ef600500 {
+                               compatible = "ibm,iic-405ep", "ibm,iic";
+                               reg = <0xef600500 0x00000011>;
+                               interrupt-parent = <&UIC0>;
+                               interrupts = <0x2 0x4>;
+
+                               rtc@68 {
+                                       /* Actually a DS1339 */
+                                       compatible = "dallas,ds1307";
+                                       reg = <0x68>;
+                               };
+
+                               temp@4a {
+                                       /* Not present on all boards */
+                                       compatible = "national,lm75";
+                                       reg = <0x4a>;
+                               };
+                       };
+
+                       GPIO: gpio@ef600700 {
+                               #gpio-cells = <2>;
+                               compatible = "ibm,ppc4xx-gpio";
+                               reg = <0xef600700 0x00000020>;
+                               gpio-controller;
+                       };
+
+                       gpio-leds {
+                               compatible = "gpio-leds";
+                               status {
+                                       label = "Status";
+                                       gpios = <&GPIO 1 0>;
+                               };
+                               radiorx {
+                                       label = "Rx";
+                                       gpios = <&GPIO 0xe 0>;
+                               };
+                       };
+
+                       EMAC0: ethernet@ef600800 {
+                               linux,network-index = <0x0>;
+                               device_type = "network";
+                               compatible = "ibm,emac-405ep", "ibm,emac";
+                               interrupt-parent = <&UIC0>;
+                               interrupts = <
+                                       0xf 0x4 /* Ethernet */
+                                       0x9 0x4 /* Ethernet Wake Up */>;
+                               local-mac-address = [000000000000]; /* Filled in by zImage */
+                               reg = <0xef600800 0x00000070>;
+                               mal-device = <&MAL>;
+                               mal-tx-channel = <0>;
+                               mal-rx-channel = <0>;
+                               cell-index = <0>;
+                               max-frame-size = <0x5dc>;
+                               rx-fifo-size = <0x1000>;
+                               tx-fifo-size = <0x800>;
+                               phy-mode = "mii";
+                               phy-map = <0x00000000>;
+                       };
+
+                       EMAC1: ethernet@ef600900 {
+                               linux,network-index = <0x1>;
+                               device_type = "network";
+                               compatible = "ibm,emac-405ep", "ibm,emac";
+                               interrupt-parent = <&UIC0>;
+                               interrupts = <
+                                       0x11 0x4 /* Ethernet */
+                                       0x9 0x4 /* Ethernet Wake Up */>;
+                               local-mac-address = [000000000000]; /* Filled in by zImage */
+                               reg = <0xef600900 0x00000070>;
+                               mal-device = <&MAL>;
+                               mal-tx-channel = <2>;
+                               mal-rx-channel = <1>;
+                               cell-index = <1>;
+                               max-frame-size = <0x5dc>;
+                               rx-fifo-size = <0x1000>;
+                               tx-fifo-size = <0x800>;
+                               mdio-device = <&EMAC0>;
+                               phy-mode = "mii";
+                               phy-map = <0x0000001>;
+                       };
+               };
+
+               EBC0: ebc {
+                       compatible = "ibm,ebc-405ep", "ibm,ebc";
+                       dcr-reg = <0x012 0x002>;
+                       #address-cells = <2>;
+                       #size-cells = <1>;
+
+                       /* The ranges property is supplied by the bootwrapper
+                        * and is based on the firmware's configuration of the
+                        * EBC bridge
+                        */
+                       clock-frequency = <0>; /* Filled in by zImage */
+
+                       nor_flash@0 {
+                               compatible = "cfi-flash";
+                               bank-width = <2>;
+                               reg = <0x0 0xff800000 0x00800000>;
+                               #address-cells = <1>;
+                               #size-cells = <1>;
+
+                               /* This mapping is for the 8M flash
+                                  4M flash has all ofssets -= 4M,
+                                  and FeatFS partition is not present */
+                               partition@0 {
+                                       label = "Bootloader";
+                                       reg = <0x7c0000 0x40000>;
+                                       /* read-only; */
+                               };
+                               partition@1 {
+                                       label = "Env_and_Config_Primary";
+                                       reg = <0x400000 0x10000>;
+                               };
+                               partition@2 {
+                                       label = "Kernel";
+                                       reg = <0x420000 0x100000>;
+                               };
+                               partition@3 {
+                                       label = "Filesystem";
+                                       reg = <0x520000 0x2a0000>;
+                               };
+                               partition@4 {
+                                       label = "Env_and_Config_Secondary";
+                                       reg = <0x410000 0x10000>;
+                               };
+                               partition@5 {
+                                       label = "FeatFS";
+                                       reg = <0x000000 0x400000>;
+                               };
+                               partition@6 {
+                                       label = "Bootloader_Env";
+                                       reg = <0x7d0000 0x10000>;
+                               };
+                       };
+               };
+
+               PCI0: pci@ec000000 {
+                       device_type = "pci";
+                       #interrupt-cells = <1>;
+                       #size-cells = <2>;
+                       #address-cells = <3>;
+                       compatible = "ibm,plb405ep-pci", "ibm,plb-pci";
+                       primary;
+                       reg = <0xeec00000 0x00000008    /* Config space access */
+                               0xeed80000 0x00000004    /* IACK */
+                               0xeed80000 0x00000004    /* Special cycle */
+                               0xef480000 0x00000040>;  /* Internal registers */
+
+                       /* Outbound ranges, one memory and one IO,
+                        * later cannot be changed. Chip supports a second
+                        * IO range but we don't use it for now
+                        */
+                       ranges = <0x02000000 0x00000000 0x80000000 0x80000000 0x00000000 0x20000000
+                               0x01000000 0x00000000 0x00000000 0xe8000000 0x00000000 0x00010000>;
+
+                       /* Inbound 2GB range starting at 0 */
+                       dma-ranges = <0x42000000 0x0 0x0 0x0 0x0 0x80000000>;
+
+                       interrupt-parent = <&UIC0>;
+                       interrupt-map-mask = <0xf800 0x0 0x0 0x7>;
+                       interrupt-map = <
+                               /* IDSEL 3 -- slot1 (optional) 27/29 A/B IRQ2/4 */
+                               0x1800 0x0 0x0 0x1 &UIC0 0x1b 0x8
+                               0x1800 0x0 0x0 0x2 &UIC0 0x1d 0x8
+
+                               /* IDSEL 4 -- slot0, 26/28 A/B IRQ1/3 */
+                               0x2000 0x0 0x0 0x1 &UIC0 0x1a 0x8
+                               0x2000 0x0 0x0 0x2 &UIC0 0x1c 0x8
+                               >;
+               };
+       };
+
+       chosen {
+               linux,stdout-path = &UART0;
+       };
+};
index 5e6b08ff6f6701e158aa94241cabe3681024d520..c46561456ede3e25758b3ee57077036940d7ebe2 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * Device Tree Source for AMCC Kilauea (405EX)
  *
- * Copyright 2007 DENX Software Engineering, Stefan Roese <sr@denx.de>
+ * Copyright 2007-2009 DENX Software Engineering, Stefan Roese <sr@denx.de>
  *
  * This file is licensed under the terms of the GNU General Public
  * License version 2.  This program is licensed "as is" without
                                        #size-cells = <1>;
                                        partition@0 {
                                                label = "kernel";
-                                               reg = <0x00000000 0x00200000>;
+                                               reg = <0x00000000 0x001e0000>;
+                                       };
+                                       partition@1e0000 {
+                                               label = "dtb";
+                                               reg = <0x001e0000 0x00020000>;
                                        };
                                        partition@200000 {
                                                label = "root";
                                                reg = <0x03fa0000 0x00060000>;
                                        };
                                };
+
+                               ndfc@1,0 {
+                                       compatible = "ibm,ndfc";
+                                       reg = <0x00000001 0x00000000 0x00002000>;
+                                       ccr = <0x00001000>;
+                                       bank-settings = <0x80002222>;
+                                       #address-cells = <1>;
+                                       #size-cells = <1>;
+
+                                       nand {
+                                               #address-cells = <1>;
+                                               #size-cells = <1>;
+
+                                               partition@0 {
+                                                       label = "u-boot";
+                                                       reg = <0x00000000 0x00100000>;
+                                               };
+                                               partition@100000 {
+                                                       label = "user";
+                                                       reg = <0x00000000 0x03f00000>;
+                                               };
+                                       };
+                               };
                        };
 
                        UART0: serial@ef600200 {
                                reg = <0xef600400 0x00000014>;
                                interrupt-parent = <&UIC0>;
                                interrupts = <0x2 0x4>;
+                               #address-cells = <1>;
+                               #size-cells = <0>;
+
+                               rtc@68 {
+                                       compatible = "dallas,ds1338";
+                                       reg = <0x68>;
+                               };
+
+                               dtt@48 {
+                                       compatible = "dallas,ds1775";
+                                       reg = <0x48>;
+                               };
                        };
 
                        IIC1: i2c@ef600500 {
                                interrupts = <0x7 0x4>;
                        };
 
-
                        RGMII0: emac-rgmii@ef600b00 {
                                compatible = "ibm,rgmii-405ex", "ibm,rgmii";
                                reg = <0xef600b00 0x00000104>;
index 633255a975576f4e8f853504ebc0d4d6268bf11f..0ce96644176da3758b00b1ba1a5ecc34ac156879 100644 (file)
                                fixed-link = <0 0 10 0 0>;
                        };
 
+                       i2c@11860 {
+                               compatible = "fsl,mpc8272-i2c",
+                                            "fsl,cpm2-i2c";
+                               reg = <0x11860 0x20 0x8afc 0x2>;
+                               interrupts = <1 8>;
+                               interrupt-parent = <&PIC>;
+                               fsl,cpm-command = <0x29600000>;
+                               #address-cells = <1>;
+                               #size-cells = <0>;
+                       };
+
+                       mdio@10d40 {
+                               compatible = "fsl,cpm2-mdio-bitbang";
+                               reg = <0x10d00 0x14>;
+                               #address-cells = <1>;
+                               #size-cells = <0>;
+                               fsl,mdio-pin = <12>;
+                               fsl,mdc-pin = <13>;
+
+                               phy0: ethernet-phy@0 {
+                                       reg = <0x0>;
+                               };
+
+                               phy1: ethernet-phy@1 {
+                                       reg = <0x1>;
+                               };
+                       };
+
+                       /* FCC1 management to switch */
+                       ethernet@11300 {
+                               device_type = "network";
+                               compatible = "fsl,cpm2-fcc-enet";
+                               reg = <0x11300 0x20 0x8400 0x100 0x11390 0x1>;
+                               local-mac-address = [ 00 01 02 03 04 07 ];
+                               interrupts = <32 8>;
+                               interrupt-parent = <&PIC>;
+                               phy-handle = <&phy0>;
+                               linux,network-index = <1>;
+                               fsl,cpm-command = <0x12000300>;
+                       };
+
+                       /* FCC2 to redundant core unit over backplane */
+                       ethernet@11320 {
+                               device_type = "network";
+                               compatible = "fsl,cpm2-fcc-enet";
+                               reg = <0x11320 0x20 0x8500 0x100 0x113b0 0x1>;
+                               local-mac-address = [ 00 01 02 03 04 08 ];
+                               interrupts = <33 8>;
+                               interrupt-parent = <&PIC>;
+                               phy-handle = <&phy1>;
+                               linux,network-index = <2>;
+                               fsl,cpm-command = <0x16200300>;
+                       };
                };
 
                PIC: interrupt-controller@10c00 {
index 60f332778e41f480c2841bd2454337c6a060e5b4..e802ebd88cb1f01c7a426037261aa83840e25226 100644 (file)
                                fsl,cpm-command = <0xce00000>;
                        };
 
+                       usb@11b60 {
+                               compatible = "fsl,mpc8272-cpm-usb";
+                               reg = <0x11b60 0x40 0x8b00 0x100>;
+                               interrupts = <11 8>;
+                               interrupt-parent = <&PIC>;
+                               mode = "peripheral";
+                       };
+
                        mdio@10d40 {
                                device_type = "mdio";
                                compatible = "fsl,mpc8272ads-mdio-bitbang",
index 4f06dbc0d27e8e96a454175c969c26a28f7be037..28e022ac41796fb83d057060d61c8728de4d238a 100644 (file)
                                interrupts = <42 0x8>;
                                interrupt-parent = <&ipic>;
                                /* Filled in by U-Boot */
-                               clock-frequency = <0>;
+                               clock-frequency = <111111111>;
                        };
                };
 
diff --git a/arch/powerpc/boot/dts/mpc8377_wlan.dts b/arch/powerpc/boot/dts/mpc8377_wlan.dts
new file mode 100644 (file)
index 0000000..3febc4e
--- /dev/null
@@ -0,0 +1,464 @@
+/*
+ * MPC8377E WLAN Device Tree Source
+ *
+ * Copyright 2007-2009 Freescale Semiconductor Inc.
+ * Copyright 2009 MontaVista Software, 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 of the  License, or (at your
+ * option) any later version.
+ */
+
+/dts-v1/;
+
+/ {
+       compatible = "fsl,mpc8377wlan";
+       #address-cells = <1>;
+       #size-cells = <1>;
+
+       aliases {
+               ethernet0 = &enet0;
+               ethernet1 = &enet1;
+               serial0 = &serial0;
+               serial1 = &serial1;
+               pci0 = &pci0;
+               pci1 = &pci1;
+               pci2 = &pci2;
+       };
+
+       cpus {
+               #address-cells = <1>;
+               #size-cells = <0>;
+
+               PowerPC,8377@0 {
+                       device_type = "cpu";
+                       reg = <0x0>;
+                       d-cache-line-size = <32>;
+                       i-cache-line-size = <32>;
+                       d-cache-size = <32768>;
+                       i-cache-size = <32768>;
+                       timebase-frequency = <0>;
+                       bus-frequency = <0>;
+                       clock-frequency = <0>;
+               };
+       };
+
+       memory {
+               device_type = "memory";
+               reg = <0x00000000 0x20000000>;  // 512MB at 0
+       };
+
+       localbus@e0005000 {
+               #address-cells = <2>;
+               #size-cells = <1>;
+               compatible = "fsl,mpc8377-elbc", "fsl,elbc", "simple-bus";
+               reg = <0xe0005000 0x1000>;
+               interrupts = <77 0x8>;
+               interrupt-parent = <&ipic>;
+               ranges = <0x0 0x0 0xfc000000 0x04000000>;
+
+               flash@0,0 {
+                       #address-cells = <1>;
+                       #size-cells = <1>;
+                       compatible = "cfi-flash";
+                       reg = <0x0 0x0 0x4000000>;
+                       bank-width = <2>;
+                       device-width = <1>;
+
+                       partition@0 {
+                               reg = <0 0x8000>;
+                               label = "u-boot";
+                               read-only;
+                       };
+
+                       partition@a0000 {
+                               reg = <0xa0000 0x300000>;
+                               label = "kernel";
+                       };
+
+                       partition@3a0000 {
+                               reg = <0x3a0000 0x3c60000>;
+                               label = "rootfs";
+                       };
+               };
+       };
+
+       immr@e0000000 {
+               #address-cells = <1>;
+               #size-cells = <1>;
+               device_type = "soc";
+               compatible = "simple-bus";
+               ranges = <0x0 0xe0000000 0x00100000>;
+               reg = <0xe0000000 0x00000200>;
+               bus-frequency = <0>;
+
+               wdt@200 {
+                       device_type = "watchdog";
+                       compatible = "mpc83xx_wdt";
+                       reg = <0x200 0x100>;
+               };
+
+               gpio1: gpio-controller@c00 {
+                       #gpio-cells = <2>;
+                       compatible = "fsl,mpc8377-gpio", "fsl,mpc8349-gpio";
+                       reg = <0xc00 0x100>;
+                       interrupts = <74 0x8>;
+                       interrupt-parent = <&ipic>;
+                       gpio-controller;
+               };
+
+               gpio2: gpio-controller@d00 {
+                       #gpio-cells = <2>;
+                       compatible = "fsl,mpc8377-gpio", "fsl,mpc8349-gpio";
+                       reg = <0xd00 0x100>;
+                       interrupts = <75 0x8>;
+                       interrupt-parent = <&ipic>;
+                       gpio-controller;
+               };
+
+               sleep-nexus {
+                       #address-cells = <1>;
+                       #size-cells = <1>;
+                       compatible = "simple-bus";
+                       sleep = <&pmc 0x0c000000>;
+                       ranges;
+
+                       i2c@3000 {
+                               #address-cells = <1>;
+                               #size-cells = <0>;
+                               cell-index = <0>;
+                               compatible = "fsl-i2c";
+                               reg = <0x3000 0x100>;
+                               interrupts = <14 0x8>;
+                               interrupt-parent = <&ipic>;
+                               dfsrr;
+
+                               at24@50 {
+                                       compatible = "at24,24c256";
+                                       reg = <0x50>;
+                               };
+
+                               rtc@68 {
+                                       compatible = "dallas,ds1339";
+                                       reg = <0x68>;
+                               };
+                       };
+
+                       sdhci@2e000 {
+                               compatible = "fsl,mpc8377-esdhc", "fsl,esdhc";
+                               reg = <0x2e000 0x1000>;
+                               interrupts = <42 0x8>;
+                               interrupt-parent = <&ipic>;
+                               clock-frequency = <133333333>;
+                       };
+               };
+
+               i2c@3100 {
+                       #address-cells = <1>;
+                       #size-cells = <0>;
+                       cell-index = <1>;
+                       compatible = "fsl-i2c";
+                       reg = <0x3100 0x100>;
+                       interrupts = <15 0x8>;
+                       interrupt-parent = <&ipic>;
+                       dfsrr;
+               };
+
+               spi@7000 {
+                       cell-index = <0>;
+                       compatible = "fsl,spi";
+                       reg = <0x7000 0x1000>;
+                       interrupts = <16 0x8>;
+                       interrupt-parent = <&ipic>;
+                       mode = "cpu";
+               };
+
+               dma@82a8 {
+                       #address-cells = <1>;
+                       #size-cells = <1>;
+                       compatible = "fsl,mpc8377-dma", "fsl,elo-dma";
+                       reg = <0x82a8 4>;
+                       ranges = <0 0x8100 0x1a8>;
+                       interrupt-parent = <&ipic>;
+                       interrupts = <71 8>;
+                       cell-index = <0>;
+                       dma-channel@0 {
+                               compatible = "fsl,mpc8377-dma-channel", "fsl,elo-dma-channel";
+                               reg = <0 0x80>;
+                               cell-index = <0>;
+                               interrupt-parent = <&ipic>;
+                               interrupts = <71 8>;
+                       };
+                       dma-channel@80 {
+                               compatible = "fsl,mpc8377-dma-channel", "fsl,elo-dma-channel";
+                               reg = <0x80 0x80>;
+                               cell-index = <1>;
+                               interrupt-parent = <&ipic>;
+                               interrupts = <71 8>;
+                       };
+                       dma-channel@100 {
+                               compatible = "fsl,mpc8377-dma-channel", "fsl,elo-dma-channel";
+                               reg = <0x100 0x80>;
+                               cell-index = <2>;
+                               interrupt-parent = <&ipic>;
+                               interrupts = <71 8>;
+                       };
+                       dma-channel@180 {
+                               compatible = "fsl,mpc8377-dma-channel", "fsl,elo-dma-channel";
+                               reg = <0x180 0x28>;
+                               cell-index = <3>;
+                               interrupt-parent = <&ipic>;
+                               interrupts = <71 8>;
+                       };
+               };
+
+               usb@23000 {
+                       compatible = "fsl-usb2-dr";
+                       reg = <0x23000 0x1000>;
+                       #address-cells = <1>;
+                       #size-cells = <0>;
+                       interrupt-parent = <&ipic>;
+                       interrupts = <38 0x8>;
+                       phy_type = "ulpi";
+                       sleep = <&pmc 0x00c00000>;
+               };
+
+               enet0: ethernet@24000 {
+                       #address-cells = <1>;
+                       #size-cells = <1>;
+                       cell-index = <0>;
+                       device_type = "network";
+                       model = "eTSEC";
+                       compatible = "gianfar";
+                       reg = <0x24000 0x1000>;
+                       ranges = <0x0 0x24000 0x1000>;
+                       local-mac-address = [ 00 00 00 00 00 00 ];
+                       interrupts = <32 0x8 33 0x8 34 0x8>;
+                       phy-connection-type = "mii";
+                       interrupt-parent = <&ipic>;
+                       tbi-handle = <&tbi0>;
+                       phy-handle = <&phy2>;
+                       sleep = <&pmc 0xc0000000>;
+                       fsl,magic-packet;
+
+                       mdio@520 {
+                               #address-cells = <1>;
+                               #size-cells = <0>;
+                               compatible = "fsl,gianfar-mdio";
+                               reg = <0x520 0x20>;
+
+                               phy2: ethernet-phy@2 {
+                                       interrupt-parent = <&ipic>;
+                                       interrupts = <17 0x8>;
+                                       reg = <0x2>;
+                                       device_type = "ethernet-phy";
+                               };
+
+                               phy3: ethernet-phy@3 {
+                                       interrupt-parent = <&ipic>;
+                                       interrupts = <18 0x8>;
+                                       reg = <0x3>;
+                                       device_type = "ethernet-phy";
+                               };
+
+                               tbi0: tbi-phy@11 {
+                                       reg = <0x11>;
+                                       device_type = "tbi-phy";
+                               };
+                       };
+               };
+
+               enet1: ethernet@25000 {
+                       #address-cells = <1>;
+                       #size-cells = <1>;
+                       cell-index = <1>;
+                       device_type = "network";
+                       model = "eTSEC";
+                       compatible = "gianfar";
+                       reg = <0x25000 0x1000>;
+                       ranges = <0x0 0x25000 0x1000>;
+                       local-mac-address = [ 00 00 00 00 00 00 ];
+                       interrupts = <35 0x8 36 0x8 37 0x8>;
+                       phy-connection-type = "mii";
+                       interrupt-parent = <&ipic>;
+                       phy-handle = <&phy3>;
+                       tbi-handle = <&tbi1>;
+                       sleep = <&pmc 0x30000000>;
+                       fsl,magic-packet;
+
+                       mdio@520 {
+                               #address-cells = <1>;
+                               #size-cells = <0>;
+                               compatible = "fsl,gianfar-tbi";
+                               reg = <0x520 0x20>;
+
+                               tbi1: tbi-phy@11 {
+                                       reg = <0x11>;
+                                       device_type = "tbi-phy";
+                               };
+                       };
+               };
+
+               serial0: serial@4500 {
+                       cell-index = <0>;
+                       device_type = "serial";
+                       compatible = "ns16550";
+                       reg = <0x4500 0x100>;
+                       clock-frequency = <0>;
+                       interrupts = <9 0x8>;
+                       interrupt-parent = <&ipic>;
+               };
+
+               serial1: serial@4600 {
+                       cell-index = <1>;
+                       device_type = "serial";
+                       compatible = "ns16550";
+                       reg = <0x4600 0x100>;
+                       clock-frequency = <0>;
+                       interrupts = <10 0x8>;
+                       interrupt-parent = <&ipic>;
+               };
+
+               crypto@30000 {
+                       compatible = "fsl,sec3.0", "fsl,sec2.4", "fsl,sec2.2",
+                                    "fsl,sec2.1", "fsl,sec2.0";
+                       reg = <0x30000 0x10000>;
+                       interrupts = <11 0x8>;
+                       interrupt-parent = <&ipic>;
+                       fsl,num-channels = <4>;
+                       fsl,channel-fifo-len = <24>;
+                       fsl,exec-units-mask = <0x9fe>;
+                       fsl,descriptor-types-mask = <0x3ab0ebf>;
+                       sleep = <&pmc 0x03000000>;
+               };
+
+               sata@18000 {
+                       compatible = "fsl,mpc8377-sata", "fsl,pq-sata";
+                       reg = <0x18000 0x1000>;
+                       interrupts = <44 0x8>;
+                       interrupt-parent = <&ipic>;
+                       sleep = <&pmc 0x000000c0>;
+               };
+
+               sata@19000 {
+                       compatible = "fsl,mpc8377-sata", "fsl,pq-sata";
+                       reg = <0x19000 0x1000>;
+                       interrupts = <45 0x8>;
+                       interrupt-parent = <&ipic>;
+                       sleep = <&pmc 0x00000030>;
+               };
+
+               /* IPIC
+                * interrupts cell = <intr #, sense>
+                * sense values match linux IORESOURCE_IRQ_* defines:
+                * sense == 8: Level, low assertion
+                * sense == 2: Edge, high-to-low change
+                */
+               ipic: interrupt-controller@700 {
+                       compatible = "fsl,ipic";
+                       interrupt-controller;
+                       #address-cells = <0>;
+                       #interrupt-cells = <2>;
+                       reg = <0x700 0x100>;
+               };
+
+               pmc: power@b00 {
+                       compatible = "fsl,mpc8377-pmc", "fsl,mpc8349-pmc";
+                       reg = <0xb00 0x100 0xa00 0x100>;
+                       interrupts = <80 0x8>;
+                       interrupt-parent = <&ipic>;
+               };
+       };
+
+       pci0: pci@e0008500 {
+               interrupt-map-mask = <0xf800 0 0 7>;
+               interrupt-map = <
+                               /* IRQ5 = 21 = 0x15, IRQ6 = 0x16, IRQ7 = 23 = 0x17 */
+
+                               /* IDSEL AD14 IRQ6 inta */
+                                0x7000 0x0 0x0 0x1 &ipic 22 0x8
+
+                               /* IDSEL AD15 IRQ5 inta */
+                                0x7800 0x0 0x0 0x1 &ipic 21 0x8>;
+               interrupt-parent = <&ipic>;
+               interrupts = <66 0x8>;
+               bus-range = <0 0>;
+               ranges = <0x02000000 0x0 0x90000000 0x90000000 0x0 0x10000000
+                         0x42000000 0x0 0x80000000 0x80000000 0x0 0x10000000
+                         0x01000000 0x0 0x00000000 0xe0300000 0x0 0x00100000>;
+               sleep = <&pmc 0x00010000>;
+               clock-frequency = <66666666>;
+               #interrupt-cells = <1>;
+               #size-cells = <2>;
+               #address-cells = <3>;
+               reg = <0xe0008500 0x100         /* internal registers */
+                      0xe0008300 0x8>;         /* config space access registers */
+               compatible = "fsl,mpc8349-pci";
+               device_type = "pci";
+       };
+
+       pci1: pcie@e0009000 {
+               #address-cells = <3>;
+               #size-cells = <2>;
+               #interrupt-cells = <1>;
+               device_type = "pci";
+               compatible = "fsl,mpc8377-pcie", "fsl,mpc8314-pcie";
+               reg = <0xe0009000 0x00001000>;
+               ranges = <0x02000000 0 0xa8000000 0xa8000000 0 0x10000000
+                         0x01000000 0 0x00000000 0xb8000000 0 0x00800000>;
+               bus-range = <0 255>;
+               interrupt-map-mask = <0xf800 0 0 7>;
+               interrupt-map = <0 0 0 1 &ipic 1 8
+                                0 0 0 2 &ipic 1 8
+                                0 0 0 3 &ipic 1 8
+                                0 0 0 4 &ipic 1 8>;
+               sleep = <&pmc 0x00300000>;
+               clock-frequency = <0>;
+
+               pcie@0 {
+                       #address-cells = <3>;
+                       #size-cells = <2>;
+                       device_type = "pci";
+                       reg = <0 0 0 0 0>;
+                       ranges = <0x02000000 0 0xa8000000
+                                 0x02000000 0 0xa8000000
+                                 0 0x10000000
+                                 0x01000000 0 0x00000000
+                                 0x01000000 0 0x00000000
+                                 0 0x00800000>;
+               };
+       };
+
+       pci2: pcie@e000a000 {
+               #address-cells = <3>;
+               #size-cells = <2>;
+               #interrupt-cells = <1>;
+               device_type = "pci";
+               compatible = "fsl,mpc8377-pcie", "fsl,mpc8314-pcie";
+               reg = <0xe000a000 0x00001000>;
+               ranges = <0x02000000 0 0xc8000000 0xc8000000 0 0x10000000
+                         0x01000000 0 0x00000000 0xd8000000 0 0x00800000>;
+               bus-range = <0 255>;
+               interrupt-map-mask = <0xf800 0 0 7>;
+               interrupt-map = <0 0 0 1 &ipic 2 8
+                                0 0 0 2 &ipic 2 8
+                                0 0 0 3 &ipic 2 8
+                                0 0 0 4 &ipic 2 8>;
+               sleep = <&pmc 0x000c0000>;
+               clock-frequency = <0>;
+
+               pcie@0 {
+                       #address-cells = <3>;
+                       #size-cells = <2>;
+                       device_type = "pci";
+                       reg = <0 0 0 0 0>;
+                       ranges = <0x02000000 0 0xc8000000
+                                 0x02000000 0 0xc8000000
+                                 0 0x10000000
+                                 0x01000000 0 0x00000000
+                                 0x01000000 0 0x00000000
+                                 0 0x00800000>;
+               };
+       };
+};
index aabf3437cadf6f38426c10cf672b3ca2e8ef5dc9..a11ead8214b4d699ef2e6e6740c19cbc08f4bb61 100644 (file)
                                interrupts = <42 0x8>;
                                interrupt-parent = <&ipic>;
                                /* Filled in by U-Boot */
-                               clock-frequency = <0>;
+                               clock-frequency = <111111111>;
                        };
                };
 
index 9b1da864d89043c0887fa6e69ace6a6c25b28b81..e35dfba587c8d33425d80eb940f0d63a3fe38ba2 100644 (file)
                                interrupts = <42 0x8>;
                                interrupt-parent = <&ipic>;
                                /* Filled in by U-Boot */
-                               clock-frequency = <0>;
+                               clock-frequency = <111111111>;
                        };
                };
 
index e781ad2f1f8aca20d0312636ac9f974b8898ab81..815cebb2e3e593641feae4101fde07d419641110 100644 (file)
@@ -14,8 +14,8 @@
 / {
        model = "fsl,mpc8536ds";
        compatible = "fsl,mpc8536ds";
-       #address-cells = <1>;
-       #size-cells = <1>;
+       #address-cells = <2>;
+       #size-cells = <2>;
 
        aliases {
                ethernet0 = &enet0;
@@ -42,7 +42,7 @@
 
        memory {
                device_type = "memory";
-               reg = <00000000 00000000>;      // Filled by U-Boot
+               reg = <0 0 0 0>;        // Filled by U-Boot
        };
 
        soc@ffe00000 {
@@ -50,7 +50,7 @@
                #size-cells = <1>;
                device_type = "soc";
                compatible = "simple-bus";
-               ranges = <0x0 0xffe00000 0x100000>;
+               ranges = <0x0 0 0xffe00000 0x100000>;
                bus-frequency = <0>;            // Filled out by uboot.
 
                ecm-law@0 {
                        phy_type = "ulpi";
                };
 
+               sdhci@2e000 {
+                       compatible = "fsl,mpc8536-esdhc", "fsl,esdhc";
+                       reg = <0x2e000 0x1000>;
+                       interrupts = <72 0x2>;
+                       interrupt-parent = <&mpic>;
+                       clock-frequency = <250000000>;
+               };
+
                serial0: serial@4500 {
                        cell-index = <0>;
                        device_type = "serial";
                interrupt-parent = <&mpic>;
                interrupts = <24 0x2>;
                bus-range = <0 0xff>;
-               ranges = <0x02000000 0 0x80000000 0x80000000 0 0x10000000
-                         0x01000000 0 0x00000000 0xffc00000 0 0x00010000>;
+               ranges = <0x02000000 0 0x80000000 0 0x80000000 0 0x10000000
+                         0x01000000 0 0x00000000 0 0xffc00000 0 0x00010000>;
                clock-frequency = <66666666>;
                #interrupt-cells = <1>;
                #size-cells = <2>;
                #address-cells = <3>;
-               reg = <0xffe08000 0x1000>;
+               reg = <0 0xffe08000 0 0x1000>;
        };
 
        pci1: pcie@ffe09000 {
                #interrupt-cells = <1>;
                #size-cells = <2>;
                #address-cells = <3>;
-               reg = <0xffe09000 0x1000>;
+               reg = <0 0xffe09000 0 0x1000>;
                bus-range = <0 0xff>;
-               ranges = <0x02000000 0 0x98000000 0x98000000 0 0x08000000
-                         0x01000000 0 0x00000000 0xffc20000 0 0x00010000>;
+               ranges = <0x02000000 0 0x98000000 0 0x98000000 0 0x08000000
+                         0x01000000 0 0x00000000 0 0xffc20000 0 0x00010000>;
                clock-frequency = <33333333>;
                interrupt-parent = <&mpic>;
                interrupts = <25 0x2>;
                #interrupt-cells = <1>;
                #size-cells = <2>;
                #address-cells = <3>;
-               reg = <0xffe0a000 0x1000>;
+               reg = <0 0xffe0a000 0 0x1000>;
                bus-range = <0 0xff>;
-               ranges = <0x02000000 0 0x90000000 0x90000000 0 0x08000000
-                         0x01000000 0 0x00000000 0xffc10000 0 0x00010000>;
+               ranges = <0x02000000 0 0x90000000 0 0x90000000 0 0x08000000
+                         0x01000000 0 0x00000000 0 0xffc10000 0 0x00010000>;
                clock-frequency = <33333333>;
                interrupt-parent = <&mpic>;
                interrupts = <26 0x2>;
                #interrupt-cells = <1>;
                #size-cells = <2>;
                #address-cells = <3>;
-               reg = <0xffe0b000 0x1000>;
+               reg = <0 0xffe0b000 0 0x1000>;
                bus-range = <0 0xff>;
-               ranges = <0x02000000 0 0xa0000000 0xa0000000 0 0x20000000
-                         0x01000000 0 0x00000000 0xffc30000 0 0x00010000>;
+               ranges = <0x02000000 0 0xa0000000 0 0xa0000000 0 0x20000000
+                         0x01000000 0 0x00000000 0 0xffc30000 0 0x00010000>;
                clock-frequency = <33333333>;
                interrupt-parent = <&mpic>;
                interrupts = <27 0x2>;
diff --git a/arch/powerpc/boot/dts/mpc8536ds_36b.dts b/arch/powerpc/boot/dts/mpc8536ds_36b.dts
new file mode 100644 (file)
index 0000000..d95b260
--- /dev/null
@@ -0,0 +1,475 @@
+/*
+ * MPC8536 DS Device Tree Source
+ *
+ * Copyright 2008-2009 Freescale Semiconductor, 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 of the  License, or (at your
+ * option) any later version.
+ */
+
+/dts-v1/;
+
+/ {
+       model = "fsl,mpc8536ds";
+       compatible = "fsl,mpc8536ds";
+       #address-cells = <2>;
+       #size-cells = <2>;
+
+       aliases {
+               ethernet0 = &enet0;
+               ethernet1 = &enet1;
+               serial0 = &serial0;
+               serial1 = &serial1;
+               pci0 = &pci0;
+               pci1 = &pci1;
+               pci2 = &pci2;
+               pci3 = &pci3;
+       };
+
+       cpus {
+               #cpus = <1>;
+               #address-cells = <1>;
+               #size-cells = <0>;
+
+               PowerPC,8536@0 {
+                       device_type = "cpu";
+                       reg = <0>;
+                       next-level-cache = <&L2>;
+               };
+       };
+
+       memory {
+               device_type = "memory";
+               reg = <0 0 0 0>;        // Filled by U-Boot
+       };
+
+       soc@fffe00000 {
+               #address-cells = <1>;
+               #size-cells = <1>;
+               device_type = "soc";
+               compatible = "simple-bus";
+               ranges = <0x0 0xf 0xffe00000 0x100000>;
+               bus-frequency = <0>;            // Filled out by uboot.
+
+               ecm-law@0 {
+                       compatible = "fsl,ecm-law";
+                       reg = <0x0 0x1000>;
+                       fsl,num-laws = <12>;
+               };
+
+               ecm@1000 {
+                       compatible = "fsl,mpc8536-ecm", "fsl,ecm";
+                       reg = <0x1000 0x1000>;
+                       interrupts = <17 2>;
+                       interrupt-parent = <&mpic>;
+               };
+
+               memory-controller@2000 {
+                       compatible = "fsl,mpc8536-memory-controller";
+                       reg = <0x2000 0x1000>;
+                       interrupt-parent = <&mpic>;
+                       interrupts = <18 0x2>;
+               };
+
+               L2: l2-cache-controller@20000 {
+                       compatible = "fsl,mpc8536-l2-cache-controller";
+                       reg = <0x20000 0x1000>;
+                       interrupt-parent = <&mpic>;
+                       interrupts = <16 0x2>;
+               };
+
+               i2c@3000 {
+                       #address-cells = <1>;
+                       #size-cells = <0>;
+                       cell-index = <0>;
+                       compatible = "fsl-i2c";
+                       reg = <0x3000 0x100>;
+                       interrupts = <43 0x2>;
+                       interrupt-parent = <&mpic>;
+                       dfsrr;
+               };
+
+               i2c@3100 {
+                       #address-cells = <1>;
+                       #size-cells = <0>;
+                       cell-index = <1>;
+                       compatible = "fsl-i2c";
+                       reg = <0x3100 0x100>;
+                       interrupts = <43 0x2>;
+                       interrupt-parent = <&mpic>;
+                       dfsrr;
+                       rtc@68 {
+                               compatible = "dallas,ds3232";
+                               reg = <0x68>;
+                               interrupts = <0 0x1>;
+                               interrupt-parent = <&mpic>;
+                       };
+               };
+
+               dma@21300 {
+                       #address-cells = <1>;
+                       #size-cells = <1>;
+                       compatible = "fsl,mpc8536-dma", "fsl,eloplus-dma";
+                       reg = <0x21300 4>;
+                       ranges = <0 0x21100 0x200>;
+                       cell-index = <0>;
+                       dma-channel@0 {
+                               compatible = "fsl,mpc8536-dma-channel",
+                                            "fsl,eloplus-dma-channel";
+                               reg = <0x0 0x80>;
+                               cell-index = <0>;
+                               interrupt-parent = <&mpic>;
+                               interrupts = <20 2>;
+                       };
+                       dma-channel@80 {
+                               compatible = "fsl,mpc8536-dma-channel",
+                                            "fsl,eloplus-dma-channel";
+                               reg = <0x80 0x80>;
+                               cell-index = <1>;
+                               interrupt-parent = <&mpic>;
+                               interrupts = <21 2>;
+                       };
+                       dma-channel@100 {
+                               compatible = "fsl,mpc8536-dma-channel",
+                                            "fsl,eloplus-dma-channel";
+                               reg = <0x100 0x80>;
+                               cell-index = <2>;
+                               interrupt-parent = <&mpic>;
+                               interrupts = <22 2>;
+                       };
+                       dma-channel@180 {
+                               compatible = "fsl,mpc8536-dma-channel",
+                                            "fsl,eloplus-dma-channel";
+                               reg = <0x180 0x80>;
+                               cell-index = <3>;
+                               interrupt-parent = <&mpic>;
+                               interrupts = <23 2>;
+                       };
+               };
+
+               usb@22000 {
+                       compatible = "fsl,mpc8536-usb2-mph", "fsl-usb2-mph";
+                       reg = <0x22000 0x1000>;
+                       #address-cells = <1>;
+                       #size-cells = <0>;
+                       interrupt-parent = <&mpic>;
+                       interrupts = <28 0x2>;
+                       phy_type = "ulpi";
+               };
+
+               usb@23000 {
+                       compatible = "fsl,mpc8536-usb2-mph", "fsl-usb2-mph";
+                       reg = <0x23000 0x1000>;
+                       #address-cells = <1>;
+                       #size-cells = <0>;
+                       interrupt-parent = <&mpic>;
+                       interrupts = <46 0x2>;
+                       phy_type = "ulpi";
+               };
+
+               enet0: ethernet@24000 {
+                       #address-cells = <1>;
+                       #size-cells = <1>;
+                       cell-index = <0>;
+                       device_type = "network";
+                       model = "eTSEC";
+                       compatible = "gianfar";
+                       reg = <0x24000 0x1000>;
+                       ranges = <0x0 0x24000 0x1000>;
+                       local-mac-address = [ 00 00 00 00 00 00 ];
+                       interrupts = <29 2 30 2 34 2>;
+                       interrupt-parent = <&mpic>;
+                       tbi-handle = <&tbi0>;
+                       phy-handle = <&phy1>;
+                       phy-connection-type = "rgmii-id";
+
+                       mdio@520 {
+                               #address-cells = <1>;
+                               #size-cells = <0>;
+                               compatible = "fsl,gianfar-mdio";
+                               reg = <0x520 0x20>;
+
+                               phy0: ethernet-phy@0 {
+                                       interrupt-parent = <&mpic>;
+                                       interrupts = <10 0x1>;
+                                       reg = <0>;
+                                       device_type = "ethernet-phy";
+                               };
+                               phy1: ethernet-phy@1 {
+                                       interrupt-parent = <&mpic>;
+                                       interrupts = <10 0x1>;
+                                       reg = <1>;
+                                       device_type = "ethernet-phy";
+                               };
+                               tbi0: tbi-phy@11 {
+                                       reg = <0x11>;
+                                       device_type = "tbi-phy";
+                               };
+                       };
+               };
+
+               enet1: ethernet@26000 {
+                       #address-cells = <1>;
+                       #size-cells = <1>;
+                       cell-index = <1>;
+                       device_type = "network";
+                       model = "eTSEC";
+                       compatible = "gianfar";
+                       reg = <0x26000 0x1000>;
+                       ranges = <0x0 0x26000 0x1000>;
+                       local-mac-address = [ 00 00 00 00 00 00 ];
+                       interrupts = <31 2 32 2 33 2>;
+                       interrupt-parent = <&mpic>;
+                       tbi-handle = <&tbi1>;
+                       phy-handle = <&phy0>;
+                       phy-connection-type = "rgmii-id";
+
+                       mdio@520 {
+                               #address-cells = <1>;
+                               #size-cells = <0>;
+                               compatible = "fsl,gianfar-tbi";
+                               reg = <0x520 0x20>;
+
+                               tbi1: tbi-phy@11 {
+                                       reg = <0x11>;
+                                       device_type = "tbi-phy";
+                               };
+                       };
+               };
+
+               usb@2b000 {
+                       compatible = "fsl,mpc8536-usb2-dr", "fsl-usb2-dr";
+                       reg = <0x2b000 0x1000>;
+                       #address-cells = <1>;
+                       #size-cells = <0>;
+                       interrupt-parent = <&mpic>;
+                       interrupts = <60 0x2>;
+                       dr_mode = "peripheral";
+                       phy_type = "ulpi";
+               };
+
+               sdhci@2e000 {
+                       compatible = "fsl,mpc8536-esdhc", "fsl,esdhc";
+                       reg = <0x2e000 0x1000>;
+                       interrupts = <72 0x2>;
+                       interrupt-parent = <&mpic>;
+                       clock-frequency = <250000000>;
+               };
+
+               serial0: serial@4500 {
+                       cell-index = <0>;
+                       device_type = "serial";
+                       compatible = "ns16550";
+                       reg = <0x4500 0x100>;
+                       clock-frequency = <0>;
+                       interrupts = <42 0x2>;
+                       interrupt-parent = <&mpic>;
+               };
+
+               serial1: serial@4600 {
+                       cell-index = <1>;
+                       device_type = "serial";
+                       compatible = "ns16550";
+                       reg = <0x4600 0x100>;
+                       clock-frequency = <0>;
+                       interrupts = <42 0x2>;
+                       interrupt-parent = <&mpic>;
+               };
+
+               crypto@30000 {
+                       compatible = "fsl,sec3.0", "fsl,sec2.4", "fsl,sec2.2",
+                                    "fsl,sec2.1", "fsl,sec2.0";
+                       reg = <0x30000 0x10000>;
+                       interrupts = <45 2 58 2>;
+                       interrupt-parent = <&mpic>;
+                       fsl,num-channels = <4>;
+                       fsl,channel-fifo-len = <24>;
+                       fsl,exec-units-mask = <0x9fe>;
+                       fsl,descriptor-types-mask = <0x3ab0ebf>;
+               };
+
+               sata@18000 {
+                       compatible = "fsl,mpc8536-sata", "fsl,pq-sata";
+                       reg = <0x18000 0x1000>;
+                       cell-index = <1>;
+                       interrupts = <74 0x2>;
+                       interrupt-parent = <&mpic>;
+               };
+
+               sata@19000 {
+                       compatible = "fsl,mpc8536-sata", "fsl,pq-sata";
+                       reg = <0x19000 0x1000>;
+                       cell-index = <2>;
+                       interrupts = <41 0x2>;
+                       interrupt-parent = <&mpic>;
+               };
+
+               global-utilities@e0000 {        //global utilities block
+                       compatible = "fsl,mpc8548-guts";
+                       reg = <0xe0000 0x1000>;
+                       fsl,has-rstcr;
+               };
+
+               mpic: pic@40000 {
+                       clock-frequency = <0>;
+                       interrupt-controller;
+                       #address-cells = <0>;
+                       #interrupt-cells = <2>;
+                       reg = <0x40000 0x40000>;
+                       compatible = "chrp,open-pic";
+                       device_type = "open-pic";
+                       big-endian;
+               };
+
+               msi@41600 {
+                       compatible = "fsl,mpc8536-msi", "fsl,mpic-msi";
+                       reg = <0x41600 0x80>;
+                       msi-available-ranges = <0 0x100>;
+                       interrupts = <
+                               0xe0 0
+                               0xe1 0
+                               0xe2 0
+                               0xe3 0
+                               0xe4 0
+                               0xe5 0
+                               0xe6 0
+                               0xe7 0>;
+                       interrupt-parent = <&mpic>;
+               };
+       };
+
+       pci0: pci@fffe08000 {
+               compatible = "fsl,mpc8540-pci";
+               device_type = "pci";
+               interrupt-map-mask = <0xf800 0x0 0x0 0x7>;
+               interrupt-map = <
+
+                       /* IDSEL 0x11 J17 Slot 1 */
+                       0x8800 0 0 1 &mpic 1 1
+                       0x8800 0 0 2 &mpic 2 1
+                       0x8800 0 0 3 &mpic 3 1
+                       0x8800 0 0 4 &mpic 4 1>;
+
+               interrupt-parent = <&mpic>;
+               interrupts = <24 0x2>;
+               bus-range = <0 0xff>;
+               ranges = <0x02000000 0 0xf0000000 0xc 0x00000000 0 0x10000000
+                         0x01000000 0 0x00000000 0xf 0xffc00000 0 0x00010000>;
+               clock-frequency = <66666666>;
+               #interrupt-cells = <1>;
+               #size-cells = <2>;
+               #address-cells = <3>;
+               reg = <0xf 0xffe08000 0 0x1000>;
+       };
+
+       pci1: pcie@fffe09000 {
+               compatible = "fsl,mpc8548-pcie";
+               device_type = "pci";
+               #interrupt-cells = <1>;
+               #size-cells = <2>;
+               #address-cells = <3>;
+               reg = <0xf 0xffe09000 0 0x1000>;
+               bus-range = <0 0xff>;
+               ranges = <0x02000000 0 0xf8000000 0xc 0x18000000 0 0x08000000
+                         0x01000000 0 0x00000000 0xf 0xffc20000 0 0x00010000>;
+               clock-frequency = <33333333>;
+               interrupt-parent = <&mpic>;
+               interrupts = <25 0x2>;
+               interrupt-map-mask = <0xf800 0 0 7>;
+               interrupt-map = <
+                       /* IDSEL 0x0 */
+                       0000 0 0 1 &mpic 4 1
+                       0000 0 0 2 &mpic 5 1
+                       0000 0 0 3 &mpic 6 1
+                       0000 0 0 4 &mpic 7 1
+                       >;
+               pcie@0 {
+                       reg = <0 0 0 0 0>;
+                       #size-cells = <2>;
+                       #address-cells = <3>;
+                       device_type = "pci";
+                       ranges = <0x02000000 0 0xf8000000
+                                 0x02000000 0 0xf8000000
+                                 0 0x08000000
+
+                                 0x01000000 0 0x00000000
+                                 0x01000000 0 0x00000000
+                                 0 0x00010000>;
+               };
+       };
+
+       pci2: pcie@fffe0a000 {
+               compatible = "fsl,mpc8548-pcie";
+               device_type = "pci";
+               #interrupt-cells = <1>;
+               #size-cells = <2>;
+               #address-cells = <3>;
+               reg = <0xf 0xffe0a000 0 0x1000>;
+               bus-range = <0 0xff>;
+               ranges = <0x02000000 0 0xf8000000 0xc 0x10000000 0 0x08000000
+                         0x01000000 0 0x00000000 0xf 0xffc10000 0 0x00010000>;
+               clock-frequency = <33333333>;
+               interrupt-parent = <&mpic>;
+               interrupts = <26 0x2>;
+               interrupt-map-mask = <0xf800 0 0 7>;
+               interrupt-map = <
+                       /* IDSEL 0x0 */
+                       0000 0 0 1 &mpic 0 1
+                       0000 0 0 2 &mpic 1 1
+                       0000 0 0 3 &mpic 2 1
+                       0000 0 0 4 &mpic 3 1
+                       >;
+               pcie@0 {
+                       reg = <0 0 0 0 0>;
+                       #size-cells = <2>;
+                       #address-cells = <3>;
+                       device_type = "pci";
+                       ranges = <0x02000000 0 0xf8000000
+                                 0x02000000 0 0xf8000000
+                                 0 0x08000000
+
+                                 0x01000000 0 0x00000000
+                                 0x01000000 0 0x00000000
+                                 0 0x00010000>;
+               };
+       };
+
+       pci3: pcie@fffe0b000 {
+               compatible = "fsl,mpc8548-pcie";
+               device_type = "pci";
+               #interrupt-cells = <1>;
+               #size-cells = <2>;
+               #address-cells = <3>;
+               reg = <0xf 0xffe0b000 0 0x1000>;
+               bus-range = <0 0xff>;
+               ranges = <0x02000000 0 0xe0000000 0xc 0x20000000 0 0x20000000
+                         0x01000000 0 0x00000000 0xf 0xffc30000 0 0x00010000>;
+               clock-frequency = <33333333>;
+               interrupt-parent = <&mpic>;
+               interrupts = <27 0x2>;
+               interrupt-map-mask = <0xf800 0 0 7>;
+               interrupt-map = <
+                       /* IDSEL 0x0 */
+                       0000 0 0 1 &mpic 8 1
+                       0000 0 0 2 &mpic 9 1
+                       0000 0 0 3 &mpic 10 1
+                       0000 0 0 4 &mpic 11 1
+                       >;
+
+               pcie@0 {
+                       reg = <0 0 0 0 0>;
+                       #size-cells = <2>;
+                       #address-cells = <3>;
+                       device_type = "pci";
+                       ranges = <0x02000000 0 0xe0000000
+                                 0x02000000 0 0xe0000000
+                                 0 0x20000000
+
+                                 0x01000000 0 0x00000000
+                                 0x01000000 0 0x00000000
+                                 0 0x00100000>;
+               };
+       };
+};
index 475be1433fe104ce4484d46454344a0c929e039e..4173af387c6355ae8c50aa4d7141d98ad0901e76 100644 (file)
                        interrupts = <43 2>;
                        interrupt-parent = <&mpic>;
                        dfsrr;
+
+                       eeprom@50 {
+                               compatible = "atmel,24c64";
+                               reg = <0x50>;
+                       };
+
+                       eeprom@56 {
+                               compatible = "atmel,24c64";
+                               reg = <0x56>;
+                       };
+
+                       eeprom@57 {
+                               compatible = "atmel,24c64";
+                               reg = <0x57>;
+                       };
                };
 
                i2c@3100 {
                        interrupts = <43 2>;
                        interrupt-parent = <&mpic>;
                        dfsrr;
+
+                       eeprom@50 {
+                               compatible = "atmel,24c64";
+                               reg = <0x50>;
+                       };
                };
 
                dma@21300 {
index 9e4ce99e1613643f60430f001813f2da0977a6e1..06332d61830a094e181f3790e4314c007d9ef0df 100644 (file)
                };
 
                bcsr@1,0 {
+                       #address-cells = <1>;
+                       #size-cells = <1>;
                        compatible = "fsl,mpc8569mds-bcsr";
                        reg = <1 0 0x8000>;
+                       ranges = <0 1 0 0x8000>;
+
+                       bcsr17: gpio-controller@11 {
+                               #gpio-cells = <2>;
+                               compatible = "fsl,mpc8569mds-bcsr-gpio";
+                               reg = <0x11 0x1>;
+                               gpio-controller;
+                       };
                };
 
                nand@3,0 {
                                gpio-controller;
                        };
 
+                       qe_pio_f: gpio-controller@a0 {
+                               #gpio-cells = <2>;
+                               compatible = "fsl,mpc8569-qe-pario-bank",
+                                            "fsl,mpc8323-qe-pario-bank";
+                               reg = <0xa0 0x18>;
+                               gpio-controller;
+                       };
+
                        pio1: ucc_pin@01 {
                                pio-map = <
                        /* port  pin  dir  open_drain  assignment  has_irq */
                        interrupt-parent = <&mpic>;
                };
 
+               timer@440 {
+                       compatible = "fsl,mpc8569-qe-gtm",
+                                    "fsl,qe-gtm", "fsl,gtm";
+                       reg = <0x440 0x40>;
+                       interrupts = <12 13 14 15>;
+                       interrupt-parent = <&qeic>;
+                       /* Filled in by U-Boot */
+                       clock-frequency = <0>;
+               };
+
                spi@4c0 {
                        #address-cells = <1>;
                        #size-cells = <0>;
                        mode = "cpu";
                };
 
+               usb@6c0 {
+                       compatible = "fsl,mpc8569-qe-usb",
+                                    "fsl,mpc8323-qe-usb";
+                       reg = <0x6c0 0x40 0x8b00 0x100>;
+                       interrupts = <11>;
+                       interrupt-parent = <&qeic>;
+                       fsl,fullspeed-clock = "clk5";
+                       fsl,lowspeed-clock = "brg10";
+                       gpios = <&qe_pio_f 3 0   /* USBOE */
+                                &qe_pio_f 4 0   /* USBTP */
+                                &qe_pio_f 5 0   /* USBTN */
+                                &qe_pio_f 6 0   /* USBRP */
+                                &qe_pio_f 8 0   /* USBRN */
+                                &bcsr17   6 0   /* SPEED */
+                                &bcsr17   5 1>; /* POWER */
+               };
+
                enet0: ucc@2000 {
                        device_type = "network";
                        compatible = "ucc_geth";
diff --git a/arch/powerpc/boot/dts/p2020rdb.dts b/arch/powerpc/boot/dts/p2020rdb.dts
new file mode 100644 (file)
index 0000000..da4cb0d
--- /dev/null
@@ -0,0 +1,586 @@
+/*
+ * P2020 RDB Device Tree Source
+ *
+ * Copyright 2009 Freescale Semiconductor 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 of the  License, or (at your
+ * option) any later version.
+ */
+
+/dts-v1/;
+/ {
+       model = "fsl,P2020";
+       compatible = "fsl,P2020RDB";
+       #address-cells = <2>;
+       #size-cells = <2>;
+
+       aliases {
+               ethernet0 = &enet0;
+               ethernet1 = &enet1;
+               ethernet2 = &enet2;
+               serial0 = &serial0;
+               serial1 = &serial1;
+               pci0 = &pci0;
+               pci1 = &pci1;
+       };
+
+       cpus {
+               #address-cells = <1>;
+               #size-cells = <0>;
+
+               PowerPC,P2020@0 {
+                       device_type = "cpu";
+                       reg = <0x0>;
+                       next-level-cache = <&L2>;
+               };
+
+               PowerPC,P2020@1 {
+                       device_type = "cpu";
+                       reg = <0x1>;
+                       next-level-cache = <&L2>;
+               };
+       };
+
+       memory {
+               device_type = "memory";
+       };
+
+       localbus@ffe05000 {
+               #address-cells = <2>;
+               #size-cells = <1>;
+               compatible = "fsl,p2020-elbc", "fsl,elbc", "simple-bus";
+               reg = <0 0xffe05000 0 0x1000>;
+               interrupts = <19 2>;
+               interrupt-parent = <&mpic>;
+
+               /* NOR and NAND Flashes */
+               ranges = <0x0 0x0 0x0 0xef000000 0x01000000
+                         0x1 0x0 0x0 0xffa00000 0x00040000
+                         0x2 0x0 0x0 0xffb00000 0x00020000>;
+
+               nor@0,0 {
+                       #address-cells = <1>;
+                       #size-cells = <1>;
+                       compatible = "cfi-flash";
+                       reg = <0x0 0x0 0x1000000>;
+                       bank-width = <2>;
+                       device-width = <1>;
+
+                       partition@0 {
+                               /* This location must not be altered  */
+                               /* 256KB for Vitesse 7385 Switch firmware */
+                               reg = <0x0 0x00040000>;
+                               label = "NOR (RO) Vitesse-7385 Firmware";
+                               read-only;
+                       };
+
+                       partition@40000 {
+                               /* 256KB for DTB Image */
+                               reg = <0x00040000 0x00040000>;
+                               label = "NOR (RO) DTB Image";
+                               read-only;
+                       };
+
+                       partition@80000 {
+                               /* 3.5 MB for Linux Kernel Image */
+                               reg = <0x00080000 0x00380000>;
+                               label = "NOR (RO) Linux Kernel Image";
+                               read-only;
+                       };
+
+                       partition@400000 {
+                               /* 11MB for JFFS2 based Root file System */
+                               reg = <0x00400000 0x00b00000>;
+                               label = "NOR (RW) JFFS2 Root File System";
+                       };
+
+                       partition@f00000 {
+                               /* This location must not be altered  */
+                               /* 512KB for u-boot Bootloader Image */
+                               /* 512KB for u-boot Environment Variables */
+                               reg = <0x00f00000 0x00100000>;
+                               label = "NOR (RO) U-Boot Image";
+                               read-only;
+                       };
+               };
+
+               nand@1,0 {
+                       #address-cells = <1>;
+                       #size-cells = <1>;
+                       compatible = "fsl,p2020-fcm-nand",
+                                    "fsl,elbc-fcm-nand";
+                       reg = <0x1 0x0 0x40000>;
+
+                       partition@0 {
+                               /* This location must not be altered  */
+                               /* 1MB for u-boot Bootloader Image */
+                               reg = <0x0 0x00100000>;
+                               label = "NAND (RO) U-Boot Image";
+                               read-only;
+                       };
+
+                       partition@100000 {
+                               /* 1MB for DTB Image */
+                               reg = <0x00100000 0x00100000>;
+                               label = "NAND (RO) DTB Image";
+                               read-only;
+                       };
+
+                       partition@200000 {
+                               /* 4MB for Linux Kernel Image */
+                               reg = <0x00200000 0x00400000>;
+                               label = "NAND (RO) Linux Kernel Image";
+                               read-only;
+                       };
+
+                       partition@600000 {
+                               /* 4MB for Compressed Root file System Image */
+                               reg = <0x00600000 0x00400000>;
+                               label = "NAND (RO) Compressed RFS Image";
+                               read-only;
+                       };
+
+                       partition@a00000 {
+                               /* 7MB for JFFS2 based Root file System */
+                               reg = <0x00a00000 0x00700000>;
+                               label = "NAND (RW) JFFS2 Root File System";
+                       };
+
+                       partition@1100000 {
+                               /* 15MB for JFFS2 based Root file System */
+                               reg = <0x01100000 0x00f00000>;
+                               label = "NAND (RW) Writable User area";
+                       };
+               };
+
+               L2switch@2,0 {
+                       #address-cells = <1>;
+                       #size-cells = <1>;
+                       compatible = "vitesse-7385";
+                       reg = <0x2 0x0 0x20000>;
+               };
+
+       };
+
+       soc@ffe00000 {
+               #address-cells = <1>;
+               #size-cells = <1>;
+               device_type = "soc";
+               compatible = "fsl,p2020-immr", "simple-bus";
+               ranges = <0x0  0x0 0xffe00000 0x100000>;
+               bus-frequency = <0>;            // Filled out by uboot.
+
+               ecm-law@0 {
+                       compatible = "fsl,ecm-law";
+                       reg = <0x0 0x1000>;
+                       fsl,num-laws = <12>;
+               };
+
+               ecm@1000 {
+                       compatible = "fsl,p2020-ecm", "fsl,ecm";
+                       reg = <0x1000 0x1000>;
+                       interrupts = <17 2>;
+                       interrupt-parent = <&mpic>;
+               };
+
+               memory-controller@2000 {
+                       compatible = "fsl,p2020-memory-controller";
+                       reg = <0x2000 0x1000>;
+                       interrupt-parent = <&mpic>;
+                       interrupts = <18 2>;
+               };
+
+               i2c@3000 {
+                       #address-cells = <1>;
+                       #size-cells = <0>;
+                       cell-index = <0>;
+                       compatible = "fsl-i2c";
+                       reg = <0x3000 0x100>;
+                       interrupts = <43 2>;
+                       interrupt-parent = <&mpic>;
+                       dfsrr;
+                       rtc@68 {
+                               compatible = "dallas,ds1339";
+                               reg = <0x68>;
+                       };
+               };
+
+               i2c@3100 {
+                       #address-cells = <1>;
+                       #size-cells = <0>;
+                       cell-index = <1>;
+                       compatible = "fsl-i2c";
+                       reg = <0x3100 0x100>;
+                       interrupts = <43 2>;
+                       interrupt-parent = <&mpic>;
+                       dfsrr;
+               };
+
+               serial0: serial@4500 {
+                       cell-index = <0>;
+                       device_type = "serial";
+                       compatible = "ns16550";
+                       reg = <0x4500 0x100>;
+                       clock-frequency = <0>;
+                       interrupts = <42 2>;
+                       interrupt-parent = <&mpic>;
+               };
+
+               serial1: serial@4600 {
+                       cell-index = <1>;
+                       device_type = "serial";
+                       compatible = "ns16550";
+                       reg = <0x4600 0x100>;
+                       clock-frequency = <0>;
+                       interrupts = <42 2>;
+                       interrupt-parent = <&mpic>;
+               };
+
+               spi@7000 {
+                       cell-index = <0>;
+                       #address-cells = <1>;
+                       #size-cells = <0>;
+                       compatible = "fsl,espi";
+                       reg = <0x7000 0x1000>;
+                       interrupts = <59 0x2>;
+                       interrupt-parent = <&mpic>;
+                       mode = "cpu";
+
+                       fsl_m25p80@0 {
+                               #address-cells = <1>;
+                               #size-cells = <1>;
+                               compatible = "fsl,espi-flash";
+                               reg = <0>;
+                               linux,modalias = "fsl_m25p80";
+                               modal = "s25sl128b";
+                               spi-max-frequency = <50000000>;
+                               mode = <0>;
+
+                               partition@0 {
+                                       /* 512KB for u-boot Bootloader Image */
+                                       reg = <0x0 0x00080000>;
+                                       label = "SPI (RO) U-Boot Image";
+                                       read-only;
+                               };
+
+                               partition@80000 {
+                                       /* 512KB for DTB Image */
+                                       reg = <0x00080000 0x00080000>;
+                                       label = "SPI (RO) DTB Image";
+                                       read-only;
+                               };
+
+                               partition@100000 {
+                                       /* 4MB for Linux Kernel Image */
+                                       reg = <0x00100000 0x00400000>;
+                                       label = "SPI (RO) Linux Kernel Image";
+                                       read-only;
+                               };
+
+                               partition@500000 {
+                                       /* 4MB for Compressed RFS Image */
+                                       reg = <0x00500000 0x00400000>;
+                                       label = "SPI (RO) Compressed RFS Image";
+                                       read-only;
+                               };
+
+                               partition@900000 {
+                                       /* 7MB for JFFS2 based RFS */
+                                       reg = <0x00900000 0x00700000>;
+                                       label = "SPI (RW) JFFS2 RFS";
+                               };
+                       };
+               };
+
+               dma@c300 {
+                       #address-cells = <1>;
+                       #size-cells = <1>;
+                       compatible = "fsl,eloplus-dma";
+                       reg = <0xc300 0x4>;
+                       ranges = <0x0 0xc100 0x200>;
+                       cell-index = <1>;
+                       dma-channel@0 {
+                               compatible = "fsl,eloplus-dma-channel";
+                               reg = <0x0 0x80>;
+                               cell-index = <0>;
+                               interrupt-parent = <&mpic>;
+                               interrupts = <76 2>;
+                       };
+                       dma-channel@80 {
+                               compatible = "fsl,eloplus-dma-channel";
+                               reg = <0x80 0x80>;
+                               cell-index = <1>;
+                               interrupt-parent = <&mpic>;
+                               interrupts = <77 2>;
+                       };
+                       dma-channel@100 {
+                               compatible = "fsl,eloplus-dma-channel";
+                               reg = <0x100 0x80>;
+                               cell-index = <2>;
+                               interrupt-parent = <&mpic>;
+                               interrupts = <78 2>;
+                       };
+                       dma-channel@180 {
+                               compatible = "fsl,eloplus-dma-channel";
+                               reg = <0x180 0x80>;
+                               cell-index = <3>;
+                               interrupt-parent = <&mpic>;
+                               interrupts = <79 2>;
+                       };
+               };
+
+               gpio: gpio-controller@f000 {
+                       #gpio-cells = <2>;
+                       compatible = "fsl,mpc8572-gpio";
+                       reg = <0xf000 0x100>;
+                       interrupts = <47 0x2>;
+                       interrupt-parent = <&mpic>;
+                       gpio-controller;
+               };
+
+               L2: l2-cache-controller@20000 {
+                       compatible = "fsl,p2020-l2-cache-controller";
+                       reg = <0x20000 0x1000>;
+                       cache-line-size = <32>; // 32 bytes
+                       cache-size = <0x80000>; // L2,512K
+                       interrupt-parent = <&mpic>;
+                       interrupts = <16 2>;
+               };
+
+               dma@21300 {
+                       #address-cells = <1>;
+                       #size-cells = <1>;
+                       compatible = "fsl,eloplus-dma";
+                       reg = <0x21300 0x4>;
+                       ranges = <0x0 0x21100 0x200>;
+                       cell-index = <0>;
+                       dma-channel@0 {
+                               compatible = "fsl,eloplus-dma-channel";
+                               reg = <0x0 0x80>;
+                               cell-index = <0>;
+                               interrupt-parent = <&mpic>;
+                               interrupts = <20 2>;
+                       };
+                       dma-channel@80 {
+                               compatible = "fsl,eloplus-dma-channel";
+                               reg = <0x80 0x80>;
+                               cell-index = <1>;
+                               interrupt-parent = <&mpic>;
+                               interrupts = <21 2>;
+                       };
+                       dma-channel@100 {
+                               compatible = "fsl,eloplus-dma-channel";
+                               reg = <0x100 0x80>;
+                               cell-index = <2>;
+                               interrupt-parent = <&mpic>;
+                               interrupts = <22 2>;
+                       };
+                       dma-channel@180 {
+                               compatible = "fsl,eloplus-dma-channel";
+                               reg = <0x180 0x80>;
+                               cell-index = <3>;
+                               interrupt-parent = <&mpic>;
+                               interrupts = <23 2>;
+                       };
+               };
+
+               usb@22000 {
+                       #address-cells = <1>;
+                       #size-cells = <0>;
+                       compatible = "fsl-usb2-dr";
+                       reg = <0x22000 0x1000>;
+                       interrupt-parent = <&mpic>;
+                       interrupts = <28 0x2>;
+                       phy_type = "ulpi";
+               };
+
+               enet0: ethernet@24000 {
+                       #address-cells = <1>;
+                       #size-cells = <1>;
+                       cell-index = <0>;
+                       device_type = "network";
+                       model = "eTSEC";
+                       compatible = "gianfar";
+                       reg = <0x24000 0x1000>;
+                       ranges = <0x0 0x24000 0x1000>;
+                       local-mac-address = [ 00 00 00 00 00 00 ];
+                       interrupts = <29 2 30 2 34 2>;
+                       interrupt-parent = <&mpic>;
+                       fixed-link = <1 1 1000 0 0>;
+                       phy-connection-type = "rgmii-id";
+
+                       mdio@520 {
+                               #address-cells = <1>;
+                               #size-cells = <0>;
+                               compatible = "fsl,gianfar-mdio";
+                               reg = <0x520 0x20>;
+
+                               phy0: ethernet-phy@0 {
+                                       interrupt-parent = <&mpic>;
+                                       interrupts = <3 1>;
+                                       reg = <0x0>;
+                               };
+                               phy1: ethernet-phy@1 {
+                                       interrupt-parent = <&mpic>;
+                                       interrupts = <3 1>;
+                                       reg = <0x1>;
+                               };
+                       };
+               };
+
+               enet1: ethernet@25000 {
+                       #address-cells = <1>;
+                       #size-cells = <1>;
+                       cell-index = <1>;
+                       device_type = "network";
+                       model = "eTSEC";
+                       compatible = "gianfar";
+                       reg = <0x25000 0x1000>;
+                       ranges = <0x0 0x25000 0x1000>;
+                       local-mac-address = [ 00 00 00 00 00 00 ];
+                       interrupts = <35 2 36 2 40 2>;
+                       interrupt-parent = <&mpic>;
+                       tbi-handle = <&tbi0>;
+                       phy-handle = <&phy0>;
+                       phy-connection-type = "sgmii";
+
+                       mdio@520 {
+                               #address-cells = <1>;
+                               #size-cells = <0>;
+                               compatible = "fsl,gianfar-tbi";
+                               reg = <0x520 0x20>;
+
+                               tbi0: tbi-phy@11 {
+                                       reg = <0x11>;
+                                       device_type = "tbi-phy";
+                               };
+                       };
+               };
+
+               enet2: ethernet@26000 {
+                       #address-cells = <1>;
+                       #size-cells = <1>;
+                       cell-index = <2>;
+                       device_type = "network";
+                       model = "eTSEC";
+                       compatible = "gianfar";
+                       reg = <0x26000 0x1000>;
+                       ranges = <0x0 0x26000 0x1000>;
+                       local-mac-address = [ 00 00 00 00 00 00 ];
+                       interrupts = <31 2 32 2 33 2>;
+                       interrupt-parent = <&mpic>;
+                       phy-handle = <&phy1>;
+                       phy-connection-type = "rgmii-id";
+               };
+
+               sdhci@2e000 {
+                       compatible = "fsl,p2020-esdhc", "fsl,esdhc";
+                       reg = <0x2e000 0x1000>;
+                       interrupts = <72 0x2>;
+                       interrupt-parent = <&mpic>;
+                       /* Filled in by U-Boot */
+                       clock-frequency = <0>;
+               };
+
+               crypto@30000 {
+                       compatible = "fsl,sec3.1", "fsl,sec3.0", "fsl,sec2.4",
+                                    "fsl,sec2.2", "fsl,sec2.1", "fsl,sec2.0";
+                       reg = <0x30000 0x10000>;
+                       interrupts = <45 2 58 2>;
+                       interrupt-parent = <&mpic>;
+                       fsl,num-channels = <4>;
+                       fsl,channel-fifo-len = <24>;
+                       fsl,exec-units-mask = <0xbfe>;
+                       fsl,descriptor-types-mask = <0x3ab0ebf>;
+               };
+
+               mpic: pic@40000 {
+                       interrupt-controller;
+                       #address-cells = <0>;
+                       #interrupt-cells = <2>;
+                       reg = <0x40000 0x40000>;
+                       compatible = "chrp,open-pic";
+                       device_type = "open-pic";
+               };
+
+               msi@41600 {
+                       compatible = "fsl,p2020-msi", "fsl,mpic-msi";
+                       reg = <0x41600 0x80>;
+                       msi-available-ranges = <0 0x100>;
+                       interrupts = <
+                               0xe0 0
+                               0xe1 0
+                               0xe2 0
+                               0xe3 0
+                               0xe4 0
+                               0xe5 0
+                               0xe6 0
+                               0xe7 0>;
+                       interrupt-parent = <&mpic>;
+               };
+
+               global-utilities@e0000 {        //global utilities block
+                       compatible = "fsl,p2020-guts";
+                       reg = <0xe0000 0x1000>;
+                       fsl,has-rstcr;
+               };
+       };
+
+       pci0: pcie@ffe09000 {
+               compatible = "fsl,mpc8548-pcie";
+               device_type = "pci";
+               #interrupt-cells = <1>;
+               #size-cells = <2>;
+               #address-cells = <3>;
+               reg = <0 0xffe09000 0 0x1000>;
+               bus-range = <0 255>;
+               ranges = <0x2000000 0x0 0xa0000000 0 0xa0000000 0x0 0x20000000
+                         0x1000000 0x0 0x00000000 0 0xffc30000 0x0 0x10000>;
+               clock-frequency = <33333333>;
+               interrupt-parent = <&mpic>;
+               interrupts = <25 2>;
+               pcie@0 {
+                       reg = <0x0 0x0 0x0 0x0 0x0>;
+                       #size-cells = <2>;
+                       #address-cells = <3>;
+                       device_type = "pci";
+                       ranges = <0x2000000 0x0 0xa0000000
+                                 0x2000000 0x0 0xa0000000
+                                 0x0 0x20000000
+
+                                 0x1000000 0x0 0x0
+                                 0x1000000 0x0 0x0
+                                 0x0 0x100000>;
+               };
+       };
+
+       pci1: pcie@ffe0a000 {
+               compatible = "fsl,mpc8548-pcie";
+               device_type = "pci";
+               #interrupt-cells = <1>;
+               #size-cells = <2>;
+               #address-cells = <3>;
+               reg = <0 0xffe0a000 0 0x1000>;
+               bus-range = <0 255>;
+               ranges = <0x2000000 0x0 0xc0000000 0 0xc0000000 0x0 0x20000000
+                         0x1000000 0x0 0x00000000 0 0xffc20000 0x0 0x10000>;
+               clock-frequency = <33333333>;
+               interrupt-parent = <&mpic>;
+               interrupts = <26 2>;
+               pcie@0 {
+                       reg = <0x0 0x0 0x0 0x0 0x0>;
+                       #size-cells = <2>;
+                       #address-cells = <3>;
+                       device_type = "pci";
+                       ranges = <0x2000000 0x0 0xc0000000
+                                 0x2000000 0x0 0xc0000000
+                                 0x0 0x20000000
+
+                                 0x1000000 0x0 0x0
+                                 0x1000000 0x0 0x0
+                                 0x0 0x100000>;
+               };
+       };
+};
index 2d9fa68f641cec3c551b54a8059ebdac428094df..0dc90f9bd814981eabc18a32fd1c88cfaa547bb9 100644 (file)
                        phy_type = "ulpi";
                        port0;
                };
-               /* phy type (ULPI, UTMI, UTMI_WIDE, SERIAL) */
-               usb@23000 {
-                       device_type = "usb";
-                       compatible = "fsl-usb2-dr";
-                       reg = <0x23000 0x1000>;
-                       #address-cells = <1>;
-                       #size-cells = <0>;
-                       interrupt-parent = <&ipic>;
-                       interrupts = <38 0x8>;
-                       dr_mode = "otg";
-                       phy_type = "ulpi";
-               };
 
                enet0: ethernet@24000 {
                        #address-cells = <1>;
                };
        };
 
+       localbus@e0005000 {
+               #address-cells = <2>;
+               #size-cells = <1>;
+               compatible = "fsl,mpc8349-localbus", "simple-bus";
+               reg = <0xe0005000 0x1000>;
+               interrupts = <77 0x8>;
+               interrupt-parent = <&ipic>;
+               ranges = <0x0 0x0 0xff800000 0x00800000         /* 8MB Flash */
+                         0x1 0x0 0xf8000000 0x00002000         /* 8KB EEPROM */
+                         0x2 0x0 0x10000000 0x04000000         /* 64MB SDRAM */
+                         0x3 0x0 0x10000000 0x04000000>;       /* 64MB SDRAM */
+
+               flash@0,0 {
+                       #address-cells = <1>;
+                       #size-cells = <1>;
+                       compatible = "intel,28F640J3A", "cfi-flash";
+                       reg = <0x0 0x0 0x800000>;
+                       bank-width = <2>;
+                       device-width = <1>;
+
+                       partition@0 {
+                               label = "u-boot";
+                               reg = <0x00000000 0x00040000>;
+                               read-only;
+                       };
+
+                       partition@40000 {
+                               label = "user";
+                               reg = <0x00040000 0x006c0000>;
+                       };
+
+                       partition@700000 {
+                               label = "legacy u-boot";
+                               reg = <0x00700000 0x00100000>;
+                               read-only;
+                       };
+
+               };
+       };
+
        pci0: pci@e0008500 {
                interrupt-map-mask = <0xf800 0x0 0x0 0x7>;
                interrupt-map = <
 
                                /* IDSEL 0x11 */
-                                0x8800 0x0 0x0 0x1 &ipic 20 0x8
-                                0x8800 0x0 0x0 0x2 &ipic 21 0x8
-                                0x8800 0x0 0x0 0x3 &ipic 22 0x8
-                                0x8800 0x0 0x0 0x4 &ipic 23 0x8>;
+                                0x8800 0x0 0x0 0x1 &ipic 48 0x8
+                                0x8800 0x0 0x0 0x2 &ipic 17 0x8
+                                0x8800 0x0 0x0 0x3 &ipic 18 0x8
+                                0x8800 0x0 0x0 0x4 &ipic 19 0x8>;
 
                interrupt-parent = <&ipic>;
                interrupts = <0x42 0x8>;
index 239d57a55cf41e48b6d10fc66f40762d4bfcfaf5..9e13ed8a1193ff25fa0a60df7c9f61beead574ae 100644 (file)
                global-utilities@e0000 {
                        compatible = "fsl,mpc8560-guts";
                        reg = <0xe0000 0x1000>;
-                       fsl,has-rstcr;
                };
        };
 
index c2baae0a3d89da9d9e882d6d0ff99177431ab79b..e2ae24340fc8e0ba2b3db0856fffa2e213e75173 100644 (file)
@@ -36,7 +36,7 @@ typedef struct boot_block {
 } boot_block_t;
 
 #define IMGBLK 512
-char   tmpbuf[IMGBLK];
+unsigned int   tmpbuf[IMGBLK / sizeof(unsigned int)];
 
 int main(int argc, char *argv[])
 {
@@ -95,13 +95,13 @@ int main(int argc, char *argv[])
 
        /* Assume zImage is an ELF file, and skip the 64K header.
        */
-       if (read(in_fd, tmpbuf, IMGBLK) != IMGBLK) {
+       if (read(in_fd, tmpbuf, sizeof(tmpbuf)) != sizeof(tmpbuf)) {
                fprintf(stderr, "%s is too small to be an ELF image\n",
                                argv[1]);
                exit(4);
        }
 
-       if ((*(unsigned int *)tmpbuf) != htonl(0x7f454c46)) {
+       if (tmpbuf[0] != htonl(0x7f454c46)) {
                fprintf(stderr, "%s is not an ELF image\n", argv[1]);
                exit(4);
        }
@@ -121,11 +121,11 @@ int main(int argc, char *argv[])
        }
 
        while (nblks-- > 0) {
-               if (read(in_fd, tmpbuf, IMGBLK) < 0) {
+               if (read(in_fd, tmpbuf, sizeof(tmpbuf)) < 0) {
                        perror("zImage read");
                        exit(5);
                }
-               cp = (unsigned int *)tmpbuf;
+               cp = tmpbuf;
                for (i = 0; i < sizeof(tmpbuf) / sizeof(unsigned int); i++)
                        cksum += *cp++;
                if (write(out_fd, tmpbuf, sizeof(tmpbuf)) != sizeof(tmpbuf)) {
diff --git a/arch/powerpc/boot/ppcboot-hotfoot.h b/arch/powerpc/boot/ppcboot-hotfoot.h
new file mode 100644 (file)
index 0000000..1a3e80b
--- /dev/null
@@ -0,0 +1,133 @@
+/*
+ * This interface is used for compatibility with old U-boots *ONLY*.
+ * Please do not imitate or extend this.
+ */
+
+/* 
+ * Unfortunately, the ESTeem Hotfoot board uses a mangled version of 
+ * ppcboot.h for historical reasons, and in the interest of having a 
+ * mainline kernel boot on the production board+bootloader, this was the 
+ * least-offensive solution.  Please direct all flames to:
+ *
+ *  Solomon Peachy <solomon@linux-wlan.com>
+ *
+ * (This header is identical to ppcboot.h except for the 
+ *  TARGET_HOTFOOT bits)
+ */
+
+/*
+ * (C) Copyright 2000, 2001
+ * Wolfgang Denk, DENX Software Engineering, wd@denx.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
+ */
+
+#ifndef __PPCBOOT_H__
+#define __PPCBOOT_H__
+
+/*
+ * Board information passed to kernel from PPCBoot
+ *
+ * include/asm-ppc/ppcboot.h
+ */
+
+#include "types.h"
+
+typedef struct bd_info {
+       unsigned long   bi_memstart;    /* start of DRAM memory */
+       unsigned long   bi_memsize;     /* size  of DRAM memory in bytes */
+       unsigned long   bi_flashstart;  /* start of FLASH memory */
+       unsigned long   bi_flashsize;   /* size  of FLASH memory */
+       unsigned long   bi_flashoffset; /* reserved area for startup monitor */
+       unsigned long   bi_sramstart;   /* start of SRAM memory */
+       unsigned long   bi_sramsize;    /* size  of SRAM memory */
+#if defined(TARGET_8xx) || defined(TARGET_CPM2) || defined(TARGET_85xx) ||\
+       defined(TARGET_83xx)
+       unsigned long   bi_immr_base;   /* base of IMMR register */
+#endif
+#if defined(TARGET_PPC_MPC52xx)
+       unsigned long   bi_mbar_base;   /* base of internal registers */
+#endif
+       unsigned long   bi_bootflags;   /* boot / reboot flag (for LynxOS) */
+       unsigned long   bi_ip_addr;     /* IP Address */
+       unsigned char   bi_enetaddr[6]; /* Ethernet address */
+#if defined(TARGET_HOTFOOT)
+       /* second onboard ethernet port */
+       unsigned char   bi_enet1addr[6];
+#define HAVE_ENET1ADDR
+#endif /* TARGET_HOOTFOOT */
+       unsigned short  bi_ethspeed;    /* Ethernet speed in Mbps */
+       unsigned long   bi_intfreq;     /* Internal Freq, in MHz */
+       unsigned long   bi_busfreq;     /* Bus Freq, in MHz */
+#if defined(TARGET_CPM2)
+       unsigned long   bi_cpmfreq;     /* CPM_CLK Freq, in MHz */
+       unsigned long   bi_brgfreq;     /* BRG_CLK Freq, in MHz */
+       unsigned long   bi_sccfreq;     /* SCC_CLK Freq, in MHz */
+       unsigned long   bi_vco;         /* VCO Out from PLL, in MHz */
+#endif
+#if defined(TARGET_PPC_MPC52xx)
+       unsigned long   bi_ipbfreq;     /* IPB Bus Freq, in MHz */
+       unsigned long   bi_pcifreq;     /* PCI Bus Freq, in MHz */
+#endif
+       unsigned long   bi_baudrate;    /* Console Baudrate */
+#if defined(TARGET_4xx)
+       unsigned char   bi_s_version[4];        /* Version of this structure */
+       unsigned char   bi_r_version[32];       /* Version of the ROM (IBM) */
+       unsigned int    bi_procfreq;    /* CPU (Internal) Freq, in Hz */
+       unsigned int    bi_plb_busfreq; /* PLB Bus speed, in Hz */
+       unsigned int    bi_pci_busfreq; /* PCI Bus speed, in Hz */
+       unsigned char   bi_pci_enetaddr[6];     /* PCI Ethernet MAC address */
+#endif
+#if defined(TARGET_HOTFOOT)
+       unsigned int     bi_pllouta_freq;       /* PLL OUTA speed, in Hz */
+#endif
+#if defined(TARGET_HYMOD)
+       hymod_conf_t    bi_hymod_conf;  /* hymod configuration information */
+#endif
+#if defined(TARGET_EVB64260) || defined(TARGET_405EP) || defined(TARGET_44x) || \
+       defined(TARGET_85xx) || defined(TARGET_83xx) || defined(TARGET_HAS_ETH1)
+       /* second onboard ethernet port */
+       unsigned char   bi_enet1addr[6];
+#define HAVE_ENET1ADDR
+#endif
+#if defined(TARGET_EVB64260) || defined(TARGET_440GX) || \
+    defined(TARGET_85xx) || defined(TARGET_HAS_ETH2)
+       /* third onboard ethernet ports */
+       unsigned char   bi_enet2addr[6];
+#define HAVE_ENET2ADDR
+#endif
+#if defined(TARGET_440GX) || defined(TARGET_HAS_ETH3)
+       /* fourth onboard ethernet ports */
+       unsigned char   bi_enet3addr[6];
+#define HAVE_ENET3ADDR
+#endif
+#if defined(TARGET_HOTFOOT)
+        int             bi_phynum[2];           /* Determines phy mapping */
+        int             bi_phymode[2];          /* Determines phy mode */
+#endif
+#if defined(TARGET_4xx)
+       unsigned int    bi_opbfreq;             /* OB clock in Hz */
+       int             bi_iic_fast[2];         /* Use fast i2c mode */
+#endif
+#if defined(TARGET_440GX)
+       int             bi_phynum[4];           /* phy mapping */
+       int             bi_phymode[4];          /* phy mode */
+#endif
+} bd_t;
+
+#define bi_tbfreq      bi_intfreq
+
+#endif /* __PPCBOOT_H__ */
index 4db487d1d2a84f1c7707cde516bc6fa9984078a2..ac9e9a58b2b0587bfa1a9c5aaa4a0190fbdfc326 100755 (executable)
@@ -46,6 +46,7 @@ CROSS=
 # directory for object and other files used by this script
 object=arch/powerpc/boot
 objbin=$object
+dtc=scripts/dtc/dtc
 
 # directory for working files
 tmpdir=.
@@ -124,7 +125,7 @@ if [ -n "$dts" ]; then
     if [ -z "$dtb" ]; then
        dtb="$platform.dtb"
     fi
-    $object/dtc -O dtb -o "$dtb" -b 0 "$dts"
+    $dtc -O dtb -o "$dtb" -b 0 "$dts"
 fi
 
 if [ -z "$kernel" ]; then
index 865725effe93bdb4df4d4cc3fa5ed2544989b66e..9a05ec0ec312180fedfab9095980b1898b72f9dd 100644 (file)
@@ -1,14 +1,14 @@
 #
 # Automatically generated make config: don't edit
-# Linux kernel version: 2.6.30-rc7
-# Wed Jun  3 10:18:16 2009
+# Linux kernel version: 2.6.31-rc4
+# Wed Jul 29 13:28:37 2009
 #
 # CONFIG_PPC64 is not set
 
 #
 # Processor support
 #
-# CONFIG_6xx is not set
+# CONFIG_PPC_BOOK3S_32 is not set
 # CONFIG_PPC_85xx is not set
 # CONFIG_PPC_8xx is not set
 CONFIG_40x=y
@@ -32,11 +32,11 @@ CONFIG_GENERIC_HARDIRQS_NO__DO_IRQ=y
 CONFIG_IRQ_PER_CPU=y
 CONFIG_STACKTRACE_SUPPORT=y
 CONFIG_HAVE_LATENCYTOP_SUPPORT=y
+CONFIG_TRACE_IRQFLAGS_SUPPORT=y
 CONFIG_LOCKDEP_SUPPORT=y
 CONFIG_RWSEM_XCHGADD_ALGORITHM=y
 CONFIG_ARCH_HAS_ILOG2_U32=y
 CONFIG_GENERIC_HWEIGHT=y
-CONFIG_GENERIC_CALIBRATE_DELAY=y
 CONFIG_GENERIC_FIND_NEXT_BIT=y
 # CONFIG_ARCH_NO_VIRT_TO_BUS is not set
 CONFIG_PPC=y
@@ -57,6 +57,7 @@ CONFIG_PPC_DCR_NATIVE=y
 CONFIG_PPC_DCR=y
 CONFIG_ARCH_SUPPORTS_DEBUG_PAGEALLOC=y
 CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
+CONFIG_CONSTRUCTORS=y
 
 #
 # General setup
@@ -108,7 +109,6 @@ CONFIG_SYSCTL_SYSCALL=y
 CONFIG_KALLSYMS=y
 CONFIG_KALLSYMS_ALL=y
 CONFIG_KALLSYMS_EXTRA_PASS=y
-# CONFIG_STRIP_ASM_SYMS is not set
 CONFIG_HOTPLUG=y
 CONFIG_PRINTK=y
 CONFIG_BUG=y
@@ -121,9 +121,16 @@ CONFIG_TIMERFD=y
 CONFIG_EVENTFD=y
 CONFIG_SHMEM=y
 CONFIG_AIO=y
+CONFIG_HAVE_PERF_COUNTERS=y
+
+#
+# Performance Counters
+#
+# CONFIG_PERF_COUNTERS is not set
 CONFIG_VM_EVENT_COUNTERS=y
 CONFIG_PCI_QUIRKS=y
 CONFIG_SLUB_DEBUG=y
+# CONFIG_STRIP_ASM_SYMS is not set
 CONFIG_COMPAT_BRK=y
 # CONFIG_SLAB is not set
 CONFIG_SLUB=y
@@ -137,6 +144,11 @@ CONFIG_HAVE_IOREMAP_PROT=y
 CONFIG_HAVE_KPROBES=y
 CONFIG_HAVE_KRETPROBES=y
 CONFIG_HAVE_ARCH_TRACEHOOK=y
+
+#
+# GCOV-based kernel profiling
+#
+# CONFIG_GCOV_KERNEL is not set
 # CONFIG_SLOW_WORK is not set
 # CONFIG_HAVE_GENERIC_DMA_COHERENT is not set
 CONFIG_SLABINFO=y
@@ -149,7 +161,7 @@ CONFIG_MODULE_UNLOAD=y
 # CONFIG_MODVERSIONS is not set
 # CONFIG_MODULE_SRCVERSION_ALL is not set
 CONFIG_BLOCK=y
-CONFIG_LBD=y
+CONFIG_LBDAF=y
 # CONFIG_BLK_DEV_BSG is not set
 # CONFIG_BLK_DEV_INTEGRITY is not set
 
@@ -220,6 +232,7 @@ CONFIG_BINFMT_ELF=y
 # CONFIG_BINFMT_MISC is not set
 # CONFIG_MATH_EMULATION is not set
 # CONFIG_IOMMU_HELPER is not set
+# CONFIG_SWIOTLB is not set
 CONFIG_PPC_NEED_DMA_SYNC_OPS=y
 CONFIG_ARCH_ENABLE_MEMORY_HOTPLUG=y
 CONFIG_ARCH_HAS_WALK_MEMORY=y
@@ -239,9 +252,9 @@ CONFIG_MIGRATION=y
 CONFIG_ZONE_DMA_FLAG=1
 CONFIG_BOUNCE=y
 CONFIG_VIRT_TO_BUS=y
-CONFIG_UNEVICTABLE_LRU=y
 CONFIG_HAVE_MLOCK=y
 CONFIG_HAVE_MLOCKED_PAGE_BIT=y
+CONFIG_DEFAULT_MMAP_MIN_ADDR=4096
 CONFIG_PPC_4K_PAGES=y
 # CONFIG_PPC_16K_PAGES is not set
 # CONFIG_PPC_64K_PAGES is not set
@@ -344,6 +357,7 @@ CONFIG_DEFAULT_TCP_CONG="cubic"
 # CONFIG_ECONET is not set
 # CONFIG_WAN_ROUTER is not set
 # CONFIG_PHONET is not set
+# CONFIG_IEEE802154 is not set
 # CONFIG_NET_SCHED is not set
 # CONFIG_DCB is not set
 
@@ -393,9 +407,8 @@ CONFIG_MTD_OF_PARTS=y
 # User Modules And Translation Layers
 #
 CONFIG_MTD_CHAR=y
-CONFIG_MTD_BLKDEVS=m
-CONFIG_MTD_BLOCK=m
-# CONFIG_MTD_BLOCK_RO is not set
+CONFIG_MTD_BLKDEVS=y
+CONFIG_MTD_BLOCK=y
 # CONFIG_FTL is not set
 # CONFIG_NFTL is not set
 # CONFIG_INFTL is not set
@@ -452,7 +465,17 @@ CONFIG_MTD_PHYSMAP_OF=y
 # CONFIG_MTD_DOC2000 is not set
 # CONFIG_MTD_DOC2001 is not set
 # CONFIG_MTD_DOC2001PLUS is not set
-# CONFIG_MTD_NAND is not set
+CONFIG_MTD_NAND=y
+# CONFIG_MTD_NAND_VERIFY_WRITE is not set
+CONFIG_MTD_NAND_ECC_SMC=y
+# CONFIG_MTD_NAND_MUSEUM_IDS is not set
+CONFIG_MTD_NAND_IDS=y
+CONFIG_MTD_NAND_NDFC=y
+# CONFIG_MTD_NAND_DISKONCHIP is not set
+# CONFIG_MTD_NAND_CAFE is not set
+# CONFIG_MTD_NAND_NANDSIM is not set
+# CONFIG_MTD_NAND_PLATFORM is not set
+# CONFIG_MTD_NAND_FSL_ELBC is not set
 # CONFIG_MTD_ONENAND is not set
 
 #
@@ -465,6 +488,7 @@ CONFIG_MTD_PHYSMAP_OF=y
 #
 # CONFIG_MTD_UBI is not set
 CONFIG_OF_DEVICE=y
+CONFIG_OF_I2C=y
 # CONFIG_PARPORT is not set
 CONFIG_BLK_DEV=y
 # CONFIG_BLK_DEV_FD is not set
@@ -504,14 +528,17 @@ CONFIG_HAVE_IDE=y
 #
 
 #
-# Enable only one of the two stacks, unless you know what you are doing
+# You can enable one or both FireWire driver stacks.
+#
+
+#
+# See the help texts for more information.
 #
 # CONFIG_FIREWIRE is not set
 # CONFIG_IEEE1394 is not set
 # CONFIG_I2O is not set
 # CONFIG_MACINTOSH_DRIVERS is not set
 CONFIG_NETDEVICES=y
-CONFIG_COMPAT_NET_DEV_OPS=y
 # CONFIG_DUMMY is not set
 # CONFIG_BONDING is not set
 # CONFIG_MACVLAN is not set
@@ -546,6 +573,7 @@ CONFIG_IBM_NEW_EMAC_EMAC4=y
 # CONFIG_IBM_NEW_EMAC_MAL_COMMON_ERR is not set
 # CONFIG_NET_PCI is not set
 # CONFIG_B44 is not set
+# CONFIG_KS8842 is not set
 # CONFIG_ATL2 is not set
 # CONFIG_NETDEV_1000 is not set
 # CONFIG_NETDEV_10000 is not set
@@ -621,20 +649,150 @@ CONFIG_LEGACY_PTY_COUNT=256
 # CONFIG_IPMI_HANDLER is not set
 # CONFIG_HW_RANDOM is not set
 # CONFIG_NVRAM is not set
-# CONFIG_GEN_RTC is not set
 # CONFIG_R3964 is not set
 # CONFIG_APPLICOM is not set
 # CONFIG_RAW_DRIVER is not set
 # CONFIG_TCG_TPM is not set
 CONFIG_DEVPORT=y
-# CONFIG_I2C is not set
+CONFIG_I2C=y
+CONFIG_I2C_BOARDINFO=y
+CONFIG_I2C_CHARDEV=y
+CONFIG_I2C_HELPER_AUTO=y
+
+#
+# I2C Hardware Bus support
+#
+
+#
+# PC SMBus host controller drivers
+#
+# 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_ISCH is not set
+# CONFIG_I2C_PIIX4 is not set
+# CONFIG_I2C_NFORCE2 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
+
+#
+# I2C system bus drivers (mostly embedded / system-on-chip)
+#
+CONFIG_I2C_IBM_IIC=y
+# CONFIG_I2C_MPC is not set
+# CONFIG_I2C_OCORES is not set
+# CONFIG_I2C_SIMTEC is not set
+
+#
+# External I2C/SMBus adapter drivers
+#
+# CONFIG_I2C_PARPORT_LIGHT is not set
+# CONFIG_I2C_TAOS_EVM is not set
+
+#
+# Graphics adapter I2C/DDC channel drivers
+#
+# CONFIG_I2C_VOODOO3 is not set
+
+#
+# Other I2C/SMBus bus drivers
+#
+# CONFIG_I2C_PCA_PLATFORM is not set
+# CONFIG_I2C_STUB is not set
+
+#
+# Miscellaneous I2C Chip support
+#
+# CONFIG_DS1682 is not set
+# CONFIG_SENSORS_PCF8574 is not set
+# CONFIG_PCF8575 is not set
+# CONFIG_SENSORS_PCA9539 is not set
+# CONFIG_SENSORS_TSL2550 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
 # CONFIG_SPI is not set
+
+#
+# PPS support
+#
+# CONFIG_PPS is not set
 CONFIG_ARCH_WANT_OPTIONAL_GPIOLIB=y
 # CONFIG_GPIOLIB is not set
 # CONFIG_W1 is not set
 # CONFIG_POWER_SUPPLY is not set
-# CONFIG_HWMON is not set
+CONFIG_HWMON=y
+# CONFIG_HWMON_VID is not set
+# CONFIG_SENSORS_AD7414 is not set
+# CONFIG_SENSORS_AD7418 is not set
+# CONFIG_SENSORS_ADM1021 is not set
+# CONFIG_SENSORS_ADM1025 is not set
+# CONFIG_SENSORS_ADM1026 is not set
+# CONFIG_SENSORS_ADM1029 is not set
+# CONFIG_SENSORS_ADM1031 is not set
+# CONFIG_SENSORS_ADM9240 is not set
+# CONFIG_SENSORS_ADT7462 is not set
+# CONFIG_SENSORS_ADT7470 is not set
+# CONFIG_SENSORS_ADT7473 is not set
+# CONFIG_SENSORS_ADT7475 is not set
+# CONFIG_SENSORS_ATXP1 is not set
+# CONFIG_SENSORS_DS1621 is not set
+# CONFIG_SENSORS_I5K_AMB is not set
+# CONFIG_SENSORS_F71805F is not set
+# CONFIG_SENSORS_F71882FG is not set
+# CONFIG_SENSORS_F75375S is not set
+# CONFIG_SENSORS_G760A 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=y
+# CONFIG_SENSORS_LM77 is not set
+# CONFIG_SENSORS_LM78 is not set
+# CONFIG_SENSORS_LM80 is not set
+# CONFIG_SENSORS_LM83 is not set
+# 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_LM93 is not set
+# CONFIG_SENSORS_LTC4215 is not set
+# CONFIG_SENSORS_LTC4245 is not set
+# CONFIG_SENSORS_LM95241 is not set
+# CONFIG_SENSORS_MAX1619 is not set
+# CONFIG_SENSORS_MAX6650 is not set
+# CONFIG_SENSORS_PC87360 is not set
+# CONFIG_SENSORS_PC87427 is not set
+# CONFIG_SENSORS_PCF8591 is not set
+# CONFIG_SENSORS_SIS5595 is not set
+# CONFIG_SENSORS_DME1737 is not set
+# CONFIG_SENSORS_SMSC47M1 is not set
+# CONFIG_SENSORS_SMSC47M192 is not set
+# CONFIG_SENSORS_SMSC47B397 is not set
+# CONFIG_SENSORS_ADS7828 is not set
+# CONFIG_SENSORS_THMC50 is not set
+# CONFIG_SENSORS_TMP401 is not set
+# CONFIG_SENSORS_VIA686A is not set
+# CONFIG_SENSORS_VT1211 is not set
+# CONFIG_SENSORS_VT8231 is not set
+# CONFIG_SENSORS_W83781D is not set
+# CONFIG_SENSORS_W83791D is not set
+# CONFIG_SENSORS_W83792D is not set
+# CONFIG_SENSORS_W83793 is not set
+# CONFIG_SENSORS_W83L785TS is not set
+# CONFIG_SENSORS_W83L786NG is not set
+# CONFIG_SENSORS_W83627HF is not set
+# CONFIG_SENSORS_W83627EHF is not set
+# CONFIG_HWMON_DEBUG_CHIP is not set
 CONFIG_THERMAL=y
+# CONFIG_THERMAL_HWMON is not set
 # CONFIG_WATCHDOG is not set
 CONFIG_SSB_POSSIBLE=y
 
@@ -649,24 +807,15 @@ CONFIG_SSB_POSSIBLE=y
 # CONFIG_MFD_CORE is not set
 # CONFIG_MFD_SM501 is not set
 # CONFIG_HTC_PASIC3 is not set
+# CONFIG_TWL4030_CORE is not set
 # CONFIG_MFD_TMIO is not set
+# CONFIG_PMIC_DA903X is not set
+# CONFIG_MFD_WM8400 is not set
+# CONFIG_MFD_WM8350_I2C is not set
+# CONFIG_MFD_PCF50633 is not set
+# CONFIG_AB3100_CORE is not set
 # CONFIG_REGULATOR is not set
-
-#
-# Multimedia devices
-#
-
-#
-# Multimedia core support
-#
-# CONFIG_VIDEO_DEV is not set
-# CONFIG_DVB_CORE is not set
-# CONFIG_VIDEO_MEDIA is not set
-
-#
-# Multimedia drivers
-#
-# CONFIG_DAB is not set
+# CONFIG_MEDIA_SUPPORT is not set
 
 #
 # Graphics support
@@ -691,10 +840,69 @@ CONFIG_SSB_POSSIBLE=y
 # CONFIG_ACCESSIBILITY is not set
 # CONFIG_INFINIBAND is not set
 # CONFIG_EDAC is not set
-# CONFIG_RTC_CLASS is not set
+CONFIG_RTC_LIB=y
+CONFIG_RTC_CLASS=y
+CONFIG_RTC_HCTOSYS=y
+CONFIG_RTC_HCTOSYS_DEVICE="rtc0"
+# CONFIG_RTC_DEBUG is not set
+
+#
+# RTC interfaces
+#
+CONFIG_RTC_INTF_SYSFS=y
+CONFIG_RTC_INTF_PROC=y
+CONFIG_RTC_INTF_DEV=y
+# CONFIG_RTC_INTF_DEV_UIE_EMUL is not set
+# CONFIG_RTC_DRV_TEST is not set
+
+#
+# I2C RTC drivers
+#
+CONFIG_RTC_DRV_DS1307=y
+# CONFIG_RTC_DRV_DS1374 is not set
+# CONFIG_RTC_DRV_DS1672 is not set
+# CONFIG_RTC_DRV_MAX6900 is not set
+# CONFIG_RTC_DRV_RS5C372 is not set
+# CONFIG_RTC_DRV_ISL1208 is not set
+# CONFIG_RTC_DRV_X1205 is not set
+# CONFIG_RTC_DRV_PCF8563 is not set
+# CONFIG_RTC_DRV_PCF8583 is not set
+# CONFIG_RTC_DRV_M41T80 is not set
+# CONFIG_RTC_DRV_S35390A is not set
+# CONFIG_RTC_DRV_FM3130 is not set
+# CONFIG_RTC_DRV_RX8581 is not set
+# CONFIG_RTC_DRV_RX8025 is not set
+
+#
+# SPI RTC drivers
+#
+
+#
+# Platform RTC drivers
+#
+# CONFIG_RTC_DRV_CMOS is not set
+# CONFIG_RTC_DRV_DS1286 is not set
+# CONFIG_RTC_DRV_DS1511 is not set
+# CONFIG_RTC_DRV_DS1553 is not set
+# CONFIG_RTC_DRV_DS1742 is not set
+# CONFIG_RTC_DRV_STK17TA8 is not set
+# CONFIG_RTC_DRV_M48T86 is not set
+# CONFIG_RTC_DRV_M48T35 is not set
+# CONFIG_RTC_DRV_M48T59 is not set
+# CONFIG_RTC_DRV_BQ4802 is not set
+# CONFIG_RTC_DRV_V3020 is not set
+
+#
+# on-CPU RTC drivers
+#
+# CONFIG_RTC_DRV_GENERIC is not set
 # CONFIG_DMADEVICES is not set
 # CONFIG_AUXDISPLAY is not set
 # CONFIG_UIO is not set
+
+#
+# TI VLYNQ
+#
 # CONFIG_STAGING is not set
 
 #
@@ -708,11 +916,12 @@ CONFIG_EXT2_FS=y
 # CONFIG_REISERFS_FS is not set
 # CONFIG_JFS_FS is not set
 # CONFIG_FS_POSIX_ACL is not set
-CONFIG_FILE_LOCKING=y
 # CONFIG_XFS_FS is not set
 # CONFIG_GFS2_FS is not set
 # CONFIG_OCFS2_FS is not set
 # CONFIG_BTRFS_FS is not set
+CONFIG_FILE_LOCKING=y
+CONFIG_FSNOTIFY=y
 CONFIG_DNOTIFY=y
 CONFIG_INOTIFY=y
 CONFIG_INOTIFY_USER=y
@@ -818,6 +1027,7 @@ CONFIG_HAS_IOPORT=y
 CONFIG_HAS_DMA=y
 CONFIG_HAVE_LMB=y
 CONFIG_NLATTR=y
+CONFIG_GENERIC_ATOMIC64=y
 
 #
 # Kernel hacking
@@ -848,6 +1058,9 @@ CONFIG_SCHED_DEBUG=y
 # CONFIG_RT_MUTEX_TESTER is not set
 # CONFIG_DEBUG_SPINLOCK is not set
 # CONFIG_DEBUG_MUTEXES is not set
+# CONFIG_DEBUG_LOCK_ALLOC is not set
+# CONFIG_PROVE_LOCKING is not set
+# CONFIG_LOCK_STAT is not set
 # CONFIG_DEBUG_SPINLOCK_SLEEP is not set
 # CONFIG_DEBUG_LOCKING_API_SELFTESTS is not set
 # CONFIG_DEBUG_KOBJECT is not set
@@ -859,7 +1072,6 @@ CONFIG_DEBUG_BUGVERBOSE=y
 # CONFIG_DEBUG_LIST is not set
 # CONFIG_DEBUG_SG is not set
 # CONFIG_DEBUG_NOTIFIERS is not set
-# CONFIG_BOOT_PRINTK_DELAY is not set
 # CONFIG_RCU_TORTURE_TEST is not set
 # CONFIG_RCU_CPU_STALL_DETECTOR is not set
 # CONFIG_BACKTRACE_SELF_TEST is not set
@@ -873,16 +1085,15 @@ CONFIG_HAVE_FUNCTION_GRAPH_TRACER=y
 CONFIG_HAVE_DYNAMIC_FTRACE=y
 CONFIG_HAVE_FTRACE_MCOUNT_RECORD=y
 CONFIG_TRACING_SUPPORT=y
-
-#
-# Tracers
-#
+CONFIG_FTRACE=y
 # CONFIG_FUNCTION_TRACER is not set
+# CONFIG_IRQSOFF_TRACER is not set
 # CONFIG_SCHED_TRACER is not set
-# CONFIG_CONTEXT_SWITCH_TRACER is not set
-# CONFIG_EVENT_TRACER is not set
+# CONFIG_ENABLE_DEFAULT_TRACERS is not set
 # CONFIG_BOOT_TRACER is not set
-# CONFIG_TRACE_BRANCH_PROFILING is not set
+CONFIG_BRANCH_PROFILE_NONE=y
+# CONFIG_PROFILE_ANNOTATED_BRANCHES is not set
+# CONFIG_PROFILE_ALL_BRANCHES is not set
 # CONFIG_STACK_TRACER is not set
 # CONFIG_KMEMTRACE is not set
 # CONFIG_WORKQUEUE_TRACER is not set
@@ -891,6 +1102,9 @@ CONFIG_TRACING_SUPPORT=y
 # CONFIG_SAMPLES is not set
 CONFIG_HAVE_ARCH_KGDB=y
 # CONFIG_KGDB is not set
+# CONFIG_KMEMCHECK is not set
+# CONFIG_PPC_DISABLE_WERROR is not set
+CONFIG_PPC_WERROR=y
 CONFIG_PRINT_STACK_DEPTH=64
 # CONFIG_DEBUG_STACKOVERFLOW is not set
 # CONFIG_DEBUG_STACK_USAGE is not set
index f7fd32c09424295eeeb30009d24d46de0d84273c..6f976b51cdd05e0632d7005336bbbea39ffddcc5 100644 (file)
@@ -1,14 +1,14 @@
 #
 # Automatically generated make config: don't edit
-# Linux kernel version: 2.6.29-rc2
-# Tue Jan 20 08:22:31 2009
+# Linux kernel version: 2.6.31-rc5
+# Thu Aug 13 14:14:07 2009
 #
 # CONFIG_PPC64 is not set
 
 #
 # Processor support
 #
-# CONFIG_6xx is not set
+# CONFIG_PPC_BOOK3S_32 is not set
 # CONFIG_PPC_85xx is not set
 # CONFIG_PPC_8xx is not set
 # CONFIG_40x is not set
@@ -31,15 +31,16 @@ CONFIG_GENERIC_TIME=y
 CONFIG_GENERIC_TIME_VSYSCALL=y
 CONFIG_GENERIC_CLOCKEVENTS=y
 CONFIG_GENERIC_HARDIRQS=y
+CONFIG_GENERIC_HARDIRQS_NO__DO_IRQ=y
 # CONFIG_HAVE_SETUP_PER_CPU_AREA is not set
 CONFIG_IRQ_PER_CPU=y
 CONFIG_STACKTRACE_SUPPORT=y
 CONFIG_HAVE_LATENCYTOP_SUPPORT=y
+CONFIG_TRACE_IRQFLAGS_SUPPORT=y
 CONFIG_LOCKDEP_SUPPORT=y
 CONFIG_RWSEM_XCHGADD_ALGORITHM=y
 CONFIG_ARCH_HAS_ILOG2_U32=y
 CONFIG_GENERIC_HWEIGHT=y
-CONFIG_GENERIC_CALIBRATE_DELAY=y
 CONFIG_GENERIC_FIND_NEXT_BIT=y
 # CONFIG_ARCH_NO_VIRT_TO_BUS is not set
 CONFIG_PPC=y
@@ -53,11 +54,14 @@ CONFIG_PPC_UDBG_16550=y
 # CONFIG_GENERIC_TBSYNC is not set
 CONFIG_AUDIT_ARCH=y
 CONFIG_GENERIC_BUG=y
+CONFIG_DTC=y
 # CONFIG_DEFAULT_UIMAGE is not set
 CONFIG_PPC_DCR_NATIVE=y
 # CONFIG_PPC_DCR_MMIO is not set
 CONFIG_PPC_DCR=y
+CONFIG_ARCH_SUPPORTS_DEBUG_PAGEALLOC=y
 CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
+CONFIG_CONSTRUCTORS=y
 
 #
 # General setup
@@ -71,9 +75,19 @@ CONFIG_SWAP=y
 CONFIG_SYSVIPC=y
 CONFIG_SYSVIPC_SYSCTL=y
 CONFIG_POSIX_MQUEUE=y
+CONFIG_POSIX_MQUEUE_SYSCTL=y
 # CONFIG_BSD_PROCESS_ACCT is not set
 # CONFIG_TASKSTATS is not set
 # CONFIG_AUDIT is not set
+
+#
+# RCU Subsystem
+#
+CONFIG_CLASSIC_RCU=y
+# CONFIG_TREE_RCU is not set
+# CONFIG_PREEMPT_RCU is not set
+# CONFIG_TREE_RCU_TRACE is not set
+# CONFIG_PREEMPT_RCU_TRACE is not set
 # CONFIG_IKCONFIG is not set
 CONFIG_LOG_BUF_SHIFT=14
 # CONFIG_GROUP_SCHED is not set
@@ -84,8 +98,12 @@ CONFIG_SYSFS_DEPRECATED_V2=y
 # CONFIG_NAMESPACES is not set
 CONFIG_BLK_DEV_INITRD=y
 CONFIG_INITRAMFS_SOURCE=""
+CONFIG_RD_GZIP=y
+# CONFIG_RD_BZIP2 is not set
+# CONFIG_RD_LZMA is not set
 # CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
 CONFIG_SYSCTL=y
+CONFIG_ANON_INODES=y
 CONFIG_EMBEDDED=y
 CONFIG_SYSCTL_SYSCALL=y
 CONFIG_KALLSYMS=y
@@ -95,23 +113,30 @@ CONFIG_HOTPLUG=y
 CONFIG_PRINTK=y
 CONFIG_BUG=y
 CONFIG_ELF_CORE=y
-CONFIG_COMPAT_BRK=y
 CONFIG_BASE_FULL=y
 CONFIG_FUTEX=y
-CONFIG_ANON_INODES=y
 CONFIG_EPOLL=y
 CONFIG_SIGNALFD=y
 CONFIG_TIMERFD=y
 CONFIG_EVENTFD=y
 CONFIG_SHMEM=y
 CONFIG_AIO=y
+CONFIG_HAVE_PERF_COUNTERS=y
+
+#
+# Performance Counters
+#
+# CONFIG_PERF_COUNTERS is not set
 CONFIG_VM_EVENT_COUNTERS=y
 CONFIG_PCI_QUIRKS=y
 CONFIG_SLUB_DEBUG=y
+# CONFIG_STRIP_ASM_SYMS is not set
+CONFIG_COMPAT_BRK=y
 # CONFIG_SLAB is not set
 CONFIG_SLUB=y
 # CONFIG_SLOB is not set
 # CONFIG_PROFILING is not set
+# CONFIG_MARKERS is not set
 CONFIG_HAVE_OPROFILE=y
 # CONFIG_KPROBES is not set
 CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS=y
@@ -119,6 +144,12 @@ CONFIG_HAVE_IOREMAP_PROT=y
 CONFIG_HAVE_KPROBES=y
 CONFIG_HAVE_KRETPROBES=y
 CONFIG_HAVE_ARCH_TRACEHOOK=y
+
+#
+# GCOV-based kernel profiling
+#
+# CONFIG_GCOV_KERNEL is not set
+# CONFIG_SLOW_WORK is not set
 # CONFIG_HAVE_GENERIC_DMA_COHERENT is not set
 CONFIG_SLABINFO=y
 CONFIG_RT_MUTEXES=y
@@ -130,8 +161,7 @@ CONFIG_MODULE_UNLOAD=y
 # CONFIG_MODVERSIONS is not set
 # CONFIG_MODULE_SRCVERSION_ALL is not set
 CONFIG_BLOCK=y
-CONFIG_LBD=y
-# CONFIG_BLK_DEV_IO_TRACE is not set
+CONFIG_LBDAF=y
 # CONFIG_BLK_DEV_BSG is not set
 # CONFIG_BLK_DEV_INTEGRITY is not set
 
@@ -147,11 +177,6 @@ CONFIG_DEFAULT_AS=y
 # CONFIG_DEFAULT_CFQ is not set
 # CONFIG_DEFAULT_NOOP is not set
 CONFIG_DEFAULT_IOSCHED="anticipatory"
-CONFIG_CLASSIC_RCU=y
-# CONFIG_TREE_RCU is not set
-# CONFIG_PREEMPT_RCU is not set
-# CONFIG_TREE_RCU_TRACE is not set
-# CONFIG_PREEMPT_RCU_TRACE is not set
 # CONFIG_FREEZER is not set
 CONFIG_PPC4xx_PCI_EXPRESS=y
 
@@ -172,6 +197,7 @@ CONFIG_PPC4xx_PCI_EXPRESS=y
 CONFIG_ARCHES=y
 # CONFIG_CANYONLANDS is not set
 # CONFIG_GLACIER is not set
+# CONFIG_REDWOOD is not set
 # CONFIG_YOSEMITE is not set
 # CONFIG_XILINX_VIRTEX440_GENERIC_BOARD is not set
 CONFIG_PPC44x_SIMPLE=y
@@ -214,6 +240,7 @@ CONFIG_BINFMT_ELF=y
 # CONFIG_BINFMT_MISC is not set
 # CONFIG_MATH_EMULATION is not set
 # CONFIG_IOMMU_HELPER is not set
+# CONFIG_SWIOTLB is not set
 CONFIG_PPC_NEED_DMA_SYNC_OPS=y
 CONFIG_ARCH_ENABLE_MEMORY_HOTPLUG=y
 CONFIG_ARCH_HAS_WALK_MEMORY=y
@@ -233,10 +260,14 @@ CONFIG_PHYS_ADDR_T_64BIT=y
 CONFIG_ZONE_DMA_FLAG=1
 CONFIG_BOUNCE=y
 CONFIG_VIRT_TO_BUS=y
-CONFIG_UNEVICTABLE_LRU=y
+CONFIG_HAVE_MLOCK=y
+CONFIG_HAVE_MLOCKED_PAGE_BIT=y
+CONFIG_DEFAULT_MMAP_MIN_ADDR=4096
+CONFIG_STDBINUTILS=y
 CONFIG_PPC_4K_PAGES=y
 # CONFIG_PPC_16K_PAGES is not set
 # CONFIG_PPC_64K_PAGES is not set
+# CONFIG_PPC_256K_PAGES is not set
 CONFIG_FORCE_MAX_ZONEORDER=11
 CONFIG_PROC_DEVICETREE=y
 CONFIG_CMDLINE_BOOL=y
@@ -261,6 +292,7 @@ CONFIG_ARCH_SUPPORTS_MSI=y
 # CONFIG_PCI_LEGACY is not set
 # CONFIG_PCI_DEBUG is not set
 # CONFIG_PCI_STUB is not set
+# CONFIG_PCI_IOV is not set
 # CONFIG_PCCARD is not set
 # CONFIG_HOTPLUG_PCI is not set
 # CONFIG_HAS_RAPIDIO is not set
@@ -278,14 +310,12 @@ CONFIG_PAGE_OFFSET=0xc0000000
 CONFIG_KERNEL_START=0xc0000000
 CONFIG_PHYSICAL_START=0x00000000
 CONFIG_TASK_SIZE=0xc0000000
-CONFIG_CONSISTENT_START=0xff100000
 CONFIG_CONSISTENT_SIZE=0x00200000
 CONFIG_NET=y
 
 #
 # Networking options
 #
-CONFIG_COMPAT_NET_DEV_OPS=y
 CONFIG_PACKET=y
 # CONFIG_PACKET_MMAP is not set
 CONFIG_UNIX=y
@@ -335,6 +365,8 @@ CONFIG_DEFAULT_TCP_CONG="cubic"
 # CONFIG_LAPB is not set
 # CONFIG_ECONET is not set
 # CONFIG_WAN_ROUTER is not set
+# CONFIG_PHONET is not set
+# CONFIG_IEEE802154 is not set
 # CONFIG_NET_SCHED is not set
 # CONFIG_DCB is not set
 
@@ -347,7 +379,6 @@ CONFIG_DEFAULT_TCP_CONG="cubic"
 # CONFIG_IRDA is not set
 # CONFIG_BT is not set
 # CONFIG_AF_RXRPC is not set
-# CONFIG_PHONET is not set
 # CONFIG_WIRELESS is not set
 # CONFIG_WIMAX is not set
 # CONFIG_RFKILL is not set
@@ -371,8 +402,92 @@ CONFIG_EXTRA_FIRMWARE=""
 # CONFIG_SYS_HYPERVISOR is not set
 CONFIG_CONNECTOR=y
 CONFIG_PROC_EVENTS=y
-# CONFIG_MTD is not set
+CONFIG_MTD=y
+# CONFIG_MTD_DEBUG is not set
+# CONFIG_MTD_CONCAT is not set
+CONFIG_MTD_PARTITIONS=y
+# CONFIG_MTD_TESTS is not set
+# CONFIG_MTD_REDBOOT_PARTS is not set
+CONFIG_MTD_CMDLINE_PARTS=y
+CONFIG_MTD_OF_PARTS=y
+# CONFIG_MTD_AR7_PARTS is not set
+
+#
+# User Modules And Translation Layers
+#
+CONFIG_MTD_CHAR=y
+CONFIG_MTD_BLKDEVS=y
+CONFIG_MTD_BLOCK=y
+# CONFIG_FTL is not set
+# CONFIG_NFTL is not set
+# CONFIG_INFTL is not set
+# CONFIG_RFD_FTL is not set
+# CONFIG_SSFDC is not set
+# CONFIG_MTD_OOPS is not set
+
+#
+# RAM/ROM/Flash chip drivers
+#
+CONFIG_MTD_CFI=y
+# CONFIG_MTD_JEDECPROBE is not set
+CONFIG_MTD_GEN_PROBE=y
+# CONFIG_MTD_CFI_ADV_OPTIONS is not set
+CONFIG_MTD_MAP_BANK_WIDTH_1=y
+CONFIG_MTD_MAP_BANK_WIDTH_2=y
+CONFIG_MTD_MAP_BANK_WIDTH_4=y
+# CONFIG_MTD_MAP_BANK_WIDTH_8 is not set
+# CONFIG_MTD_MAP_BANK_WIDTH_16 is not set
+# CONFIG_MTD_MAP_BANK_WIDTH_32 is not set
+CONFIG_MTD_CFI_I1=y
+CONFIG_MTD_CFI_I2=y
+# CONFIG_MTD_CFI_I4 is not set
+# CONFIG_MTD_CFI_I8 is not set
+# CONFIG_MTD_CFI_INTELEXT is not set
+CONFIG_MTD_CFI_AMDSTD=y
+# CONFIG_MTD_CFI_STAA is not set
+CONFIG_MTD_CFI_UTIL=y
+# CONFIG_MTD_RAM is not set
+# CONFIG_MTD_ROM is not set
+# CONFIG_MTD_ABSENT is not set
+
+#
+# Mapping drivers for chip access
+#
+# CONFIG_MTD_COMPLEX_MAPPINGS is not set
+# CONFIG_MTD_PHYSMAP is not set
+CONFIG_MTD_PHYSMAP_OF=y
+# CONFIG_MTD_INTEL_VR_NOR is not set
+# CONFIG_MTD_PLATRAM is not set
+
+#
+# Self-contained MTD device drivers
+#
+# CONFIG_MTD_PMC551 is not set
+# CONFIG_MTD_SLRAM is not set
+# CONFIG_MTD_PHRAM is not set
+# CONFIG_MTD_MTDRAM is not set
+# CONFIG_MTD_BLOCK2MTD is not set
+
+#
+# Disk-On-Chip Device Drivers
+#
+# CONFIG_MTD_DOC2000 is not set
+# CONFIG_MTD_DOC2001 is not set
+# CONFIG_MTD_DOC2001PLUS is not set
+# CONFIG_MTD_NAND is not set
+# CONFIG_MTD_ONENAND is not set
+
+#
+# LPDDR flash memory drivers
+#
+# CONFIG_MTD_LPDDR is not set
+
+#
+# UBI - Unsorted block images
+#
+# CONFIG_MTD_UBI is not set
 CONFIG_OF_DEVICE=y
+CONFIG_OF_I2C=y
 # CONFIG_PARPORT is not set
 CONFIG_BLK_DEV=y
 # CONFIG_BLK_DEV_FD is not set
@@ -412,7 +527,11 @@ CONFIG_HAVE_IDE=y
 #
 
 #
-# Enable only one of the two stacks, unless you know what you are doing
+# You can enable one or both FireWire driver stacks.
+#
+
+#
+# See the help texts for more information.
 #
 # CONFIG_FIREWIRE is not set
 # CONFIG_IEEE1394 is not set
@@ -433,6 +552,8 @@ CONFIG_NET_ETHERNET=y
 # CONFIG_SUNGEM is not set
 # CONFIG_CASSINI is not set
 # CONFIG_NET_VENDOR_3COM is not set
+# CONFIG_ETHOC is not set
+# CONFIG_DNET is not set
 # CONFIG_NET_TULIP is not set
 # CONFIG_HP100 is not set
 CONFIG_IBM_NEW_EMAC=y
@@ -451,6 +572,7 @@ CONFIG_IBM_NEW_EMAC_EMAC4=y
 # CONFIG_IBM_NEW_EMAC_MAL_COMMON_ERR is not set
 # CONFIG_NET_PCI is not set
 # CONFIG_B44 is not set
+# CONFIG_KS8842 is not set
 # CONFIG_ATL2 is not set
 # CONFIG_NETDEV_1000 is not set
 # CONFIG_NETDEV_10000 is not set
@@ -461,7 +583,6 @@ CONFIG_IBM_NEW_EMAC_EMAC4=y
 #
 # CONFIG_WLAN_PRE80211 is not set
 # CONFIG_WLAN_80211 is not set
-# CONFIG_IWLWIFI_LEDS is not set
 
 #
 # Enable WiMAX (Networking options) to see the WiMAX drivers
@@ -533,13 +654,143 @@ CONFIG_LEGACY_PTY_COUNT=256
 # CONFIG_RAW_DRIVER is not set
 # CONFIG_TCG_TPM is not set
 CONFIG_DEVPORT=y
-# CONFIG_I2C is not set
+CONFIG_I2C=y
+CONFIG_I2C_BOARDINFO=y
+CONFIG_I2C_CHARDEV=y
+CONFIG_I2C_HELPER_AUTO=y
+
+#
+# I2C Hardware Bus support
+#
+
+#
+# PC SMBus host controller drivers
+#
+# 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_ISCH is not set
+# CONFIG_I2C_PIIX4 is not set
+# CONFIG_I2C_NFORCE2 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
+
+#
+# I2C system bus drivers (mostly embedded / system-on-chip)
+#
+CONFIG_I2C_IBM_IIC=y
+# CONFIG_I2C_MPC is not set
+# CONFIG_I2C_OCORES is not set
+# CONFIG_I2C_SIMTEC is not set
+
+#
+# External I2C/SMBus adapter drivers
+#
+# CONFIG_I2C_PARPORT_LIGHT is not set
+# CONFIG_I2C_TAOS_EVM is not set
+
+#
+# Graphics adapter I2C/DDC channel drivers
+#
+# CONFIG_I2C_VOODOO3 is not set
+
+#
+# Other I2C/SMBus bus drivers
+#
+# CONFIG_I2C_PCA_PLATFORM is not set
+# CONFIG_I2C_STUB is not set
+
+#
+# Miscellaneous I2C Chip support
+#
+# CONFIG_DS1682 is not set
+# CONFIG_SENSORS_PCF8574 is not set
+# CONFIG_PCF8575 is not set
+# CONFIG_SENSORS_PCA9539 is not set
+# CONFIG_SENSORS_TSL2550 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
 # CONFIG_SPI is not set
+
+#
+# PPS support
+#
+# CONFIG_PPS is not set
 CONFIG_ARCH_WANT_OPTIONAL_GPIOLIB=y
 # CONFIG_GPIOLIB is not set
 # CONFIG_W1 is not set
 # CONFIG_POWER_SUPPLY is not set
-# CONFIG_HWMON is not set
+CONFIG_HWMON=y
+# CONFIG_HWMON_VID is not set
+CONFIG_SENSORS_AD7414=y
+# CONFIG_SENSORS_AD7418 is not set
+# CONFIG_SENSORS_ADM1021 is not set
+# CONFIG_SENSORS_ADM1025 is not set
+# CONFIG_SENSORS_ADM1026 is not set
+# CONFIG_SENSORS_ADM1029 is not set
+# CONFIG_SENSORS_ADM1031 is not set
+# CONFIG_SENSORS_ADM9240 is not set
+# CONFIG_SENSORS_ADT7462 is not set
+# CONFIG_SENSORS_ADT7470 is not set
+# CONFIG_SENSORS_ADT7473 is not set
+# CONFIG_SENSORS_ADT7475 is not set
+# CONFIG_SENSORS_ATXP1 is not set
+# CONFIG_SENSORS_DS1621 is not set
+# CONFIG_SENSORS_I5K_AMB is not set
+# CONFIG_SENSORS_F71805F is not set
+# CONFIG_SENSORS_F71882FG is not set
+# CONFIG_SENSORS_F75375S is not set
+# CONFIG_SENSORS_G760A 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
+# CONFIG_SENSORS_LM77 is not set
+# CONFIG_SENSORS_LM78 is not set
+# CONFIG_SENSORS_LM80 is not set
+# CONFIG_SENSORS_LM83 is not set
+# 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_LM93 is not set
+# CONFIG_SENSORS_LTC4215 is not set
+# CONFIG_SENSORS_LTC4245 is not set
+# CONFIG_SENSORS_LM95241 is not set
+# CONFIG_SENSORS_MAX1619 is not set
+# CONFIG_SENSORS_MAX6650 is not set
+# CONFIG_SENSORS_PC87360 is not set
+# CONFIG_SENSORS_PC87427 is not set
+# CONFIG_SENSORS_PCF8591 is not set
+# CONFIG_SENSORS_SIS5595 is not set
+# CONFIG_SENSORS_DME1737 is not set
+# CONFIG_SENSORS_SMSC47M1 is not set
+# CONFIG_SENSORS_SMSC47M192 is not set
+# CONFIG_SENSORS_SMSC47B397 is not set
+# CONFIG_SENSORS_ADS7828 is not set
+# CONFIG_SENSORS_THMC50 is not set
+# CONFIG_SENSORS_TMP401 is not set
+# CONFIG_SENSORS_VIA686A is not set
+# CONFIG_SENSORS_VT1211 is not set
+# CONFIG_SENSORS_VT8231 is not set
+# CONFIG_SENSORS_W83781D is not set
+# CONFIG_SENSORS_W83791D is not set
+# CONFIG_SENSORS_W83792D is not set
+# CONFIG_SENSORS_W83793 is not set
+# CONFIG_SENSORS_W83L785TS is not set
+# CONFIG_SENSORS_W83L786NG is not set
+# CONFIG_SENSORS_W83627HF is not set
+# CONFIG_SENSORS_W83627EHF is not set
+# CONFIG_HWMON_DEBUG_CHIP is not set
 # CONFIG_THERMAL is not set
 # CONFIG_THERMAL_HWMON is not set
 # CONFIG_WATCHDOG is not set
@@ -556,24 +807,15 @@ CONFIG_SSB_POSSIBLE=y
 # CONFIG_MFD_CORE is not set
 # CONFIG_MFD_SM501 is not set
 # CONFIG_HTC_PASIC3 is not set
+# CONFIG_TWL4030_CORE is not set
 # CONFIG_MFD_TMIO is not set
+# CONFIG_PMIC_DA903X is not set
+# CONFIG_MFD_WM8400 is not set
+# CONFIG_MFD_WM8350_I2C is not set
+# CONFIG_MFD_PCF50633 is not set
+# CONFIG_AB3100_CORE is not set
 # CONFIG_REGULATOR is not set
-
-#
-# Multimedia devices
-#
-
-#
-# Multimedia core support
-#
-# CONFIG_VIDEO_DEV is not set
-# CONFIG_DVB_CORE is not set
-# CONFIG_VIDEO_MEDIA is not set
-
-#
-# Multimedia drivers
-#
-CONFIG_DAB=y
+# CONFIG_MEDIA_SUPPORT is not set
 
 #
 # Graphics support
@@ -600,7 +842,12 @@ CONFIG_VIDEO_OUTPUT_CONTROL=m
 # CONFIG_EDAC is not set
 # CONFIG_RTC_CLASS is not set
 # CONFIG_DMADEVICES is not set
+# CONFIG_AUXDISPLAY is not set
 # CONFIG_UIO is not set
+
+#
+# TI VLYNQ
+#
 # CONFIG_STAGING is not set
 
 #
@@ -614,11 +861,12 @@ CONFIG_EXT2_FS=y
 # CONFIG_REISERFS_FS is not set
 # CONFIG_JFS_FS is not set
 # CONFIG_FS_POSIX_ACL is not set
-CONFIG_FILE_LOCKING=y
 # CONFIG_XFS_FS is not set
 # CONFIG_GFS2_FS is not set
 # CONFIG_OCFS2_FS is not set
 # CONFIG_BTRFS_FS is not set
+CONFIG_FILE_LOCKING=y
+CONFIG_FSNOTIFY=y
 CONFIG_DNOTIFY=y
 CONFIG_INOTIFY=y
 CONFIG_INOTIFY_USER=y
@@ -627,6 +875,11 @@ CONFIG_INOTIFY_USER=y
 # CONFIG_AUTOFS4_FS is not set
 # CONFIG_FUSE_FS is not set
 
+#
+# Caches
+#
+# CONFIG_FSCACHE is not set
+
 #
 # CD-ROM/DVD Filesystems
 #
@@ -660,6 +913,17 @@ CONFIG_MISC_FILESYSTEMS=y
 # CONFIG_BEFS_FS is not set
 # CONFIG_BFS_FS is not set
 # CONFIG_EFS_FS is not set
+CONFIG_JFFS2_FS=y
+CONFIG_JFFS2_FS_DEBUG=0
+CONFIG_JFFS2_FS_WRITEBUFFER=y
+# CONFIG_JFFS2_FS_WBUF_VERIFY is not set
+# CONFIG_JFFS2_SUMMARY is not set
+# CONFIG_JFFS2_FS_XATTR is not set
+# CONFIG_JFFS2_COMPRESSION_OPTIONS is not set
+CONFIG_JFFS2_ZLIB=y
+# CONFIG_JFFS2_LZO is not set
+CONFIG_JFFS2_RTIME=y
+# CONFIG_JFFS2_RUBIN is not set
 CONFIG_CRAMFS=y
 # CONFIG_SQUASHFS is not set
 # CONFIG_VXFS_FS is not set
@@ -670,6 +934,7 @@ CONFIG_CRAMFS=y
 # CONFIG_ROMFS_FS is not set
 # CONFIG_SYSV_FS is not set
 # CONFIG_UFS_FS is not set
+# CONFIG_NILFS2_FS is not set
 CONFIG_NETWORK_FILESYSTEMS=y
 CONFIG_NFS_FS=y
 CONFIG_NFS_V3=y
@@ -681,7 +946,6 @@ CONFIG_LOCKD=y
 CONFIG_LOCKD_V4=y
 CONFIG_NFS_COMMON=y
 CONFIG_SUNRPC=y
-# CONFIG_SUNRPC_REGISTER_V4 is not set
 # CONFIG_RPCSEC_GSS_KRB5 is not set
 # CONFIG_RPCSEC_GSS_SPKM3 is not set
 # CONFIG_SMB_FS is not set
@@ -697,6 +961,7 @@ CONFIG_SUNRPC=y
 CONFIG_MSDOS_PARTITION=y
 # CONFIG_NLS is not set
 # CONFIG_DLM is not set
+# CONFIG_BINARY_PRINTF is not set
 
 #
 # Library routines
@@ -711,11 +976,14 @@ CONFIG_CRC32=y
 # CONFIG_CRC7 is not set
 # CONFIG_LIBCRC32C is not set
 CONFIG_ZLIB_INFLATE=y
-CONFIG_PLIST=y
+CONFIG_ZLIB_DEFLATE=y
+CONFIG_DECOMPRESS_GZIP=y
 CONFIG_HAS_IOMEM=y
 CONFIG_HAS_IOPORT=y
 CONFIG_HAS_DMA=y
 CONFIG_HAVE_LMB=y
+CONFIG_NLATTR=y
+CONFIG_GENERIC_ATOMIC64=y
 
 #
 # Kernel hacking
@@ -733,6 +1001,9 @@ CONFIG_DEBUG_KERNEL=y
 CONFIG_DETECT_SOFTLOCKUP=y
 # CONFIG_BOOTPARAM_SOFTLOCKUP_PANIC is not set
 CONFIG_BOOTPARAM_SOFTLOCKUP_PANIC_VALUE=0
+CONFIG_DETECT_HUNG_TASK=y
+# CONFIG_BOOTPARAM_HUNG_TASK_PANIC is not set
+CONFIG_BOOTPARAM_HUNG_TASK_PANIC_VALUE=0
 CONFIG_SCHED_DEBUG=y
 # CONFIG_SCHEDSTATS is not set
 # CONFIG_TIMER_STATS is not set
@@ -743,6 +1014,9 @@ CONFIG_SCHED_DEBUG=y
 # CONFIG_RT_MUTEX_TESTER is not set
 # CONFIG_DEBUG_SPINLOCK is not set
 # CONFIG_DEBUG_MUTEXES is not set
+# CONFIG_DEBUG_LOCK_ALLOC is not set
+# CONFIG_PROVE_LOCKING is not set
+# CONFIG_LOCK_STAT is not set
 # CONFIG_DEBUG_SPINLOCK_SLEEP is not set
 # CONFIG_DEBUG_LOCKING_API_SELFTESTS is not set
 # CONFIG_DEBUG_KOBJECT is not set
@@ -754,7 +1028,6 @@ CONFIG_SCHED_DEBUG=y
 # CONFIG_DEBUG_LIST is not set
 # CONFIG_DEBUG_SG is not set
 # CONFIG_DEBUG_NOTIFIERS is not set
-# CONFIG_BOOT_PRINTK_DELAY is not set
 # CONFIG_RCU_TORTURE_TEST is not set
 # CONFIG_RCU_CPU_STALL_DETECTOR is not set
 # CONFIG_BACKTRACE_SELF_TEST is not set
@@ -762,27 +1035,36 @@ CONFIG_SCHED_DEBUG=y
 # CONFIG_FAULT_INJECTION is not set
 # CONFIG_LATENCYTOP is not set
 CONFIG_SYSCTL_SYSCALL_CHECK=y
+# CONFIG_DEBUG_PAGEALLOC is not set
 CONFIG_HAVE_FUNCTION_TRACER=y
+CONFIG_HAVE_FUNCTION_GRAPH_TRACER=y
 CONFIG_HAVE_DYNAMIC_FTRACE=y
 CONFIG_HAVE_FTRACE_MCOUNT_RECORD=y
-
-#
-# Tracers
-#
+CONFIG_TRACING_SUPPORT=y
+CONFIG_FTRACE=y
 # CONFIG_FUNCTION_TRACER is not set
+# CONFIG_IRQSOFF_TRACER is not set
 # CONFIG_SCHED_TRACER is not set
-# CONFIG_CONTEXT_SWITCH_TRACER is not set
+# CONFIG_ENABLE_DEFAULT_TRACERS is not set
 # CONFIG_BOOT_TRACER is not set
-# CONFIG_TRACE_BRANCH_PROFILING is not set
+CONFIG_BRANCH_PROFILE_NONE=y
+# CONFIG_PROFILE_ANNOTATED_BRANCHES is not set
+# CONFIG_PROFILE_ALL_BRANCHES is not set
 # CONFIG_STACK_TRACER is not set
-# CONFIG_DYNAMIC_PRINTK_DEBUG is not set
+# CONFIG_KMEMTRACE is not set
+# CONFIG_WORKQUEUE_TRACER is not set
+# CONFIG_BLK_DEV_IO_TRACE is not set
+# CONFIG_DYNAMIC_DEBUG is not set
 # CONFIG_SAMPLES is not set
 CONFIG_HAVE_ARCH_KGDB=y
 # CONFIG_KGDB is not set
+# CONFIG_KMEMCHECK is not set
+# CONFIG_PPC_DISABLE_WERROR is not set
+CONFIG_PPC_WERROR=y
 CONFIG_PRINT_STACK_DEPTH=64
 # CONFIG_DEBUG_STACKOVERFLOW is not set
 # CONFIG_DEBUG_STACK_USAGE is not set
-# CONFIG_DEBUG_PAGEALLOC is not set
+# CONFIG_PPC_EMULATED_STATS is not set
 # CONFIG_CODE_PATCHING_SELFTEST is not set
 # CONFIG_FTR_FIXUP_SELFTEST is not set
 # CONFIG_MSI_BITMAP_SELFTEST is not set
index 5e85412eb9fae28f401d3b717244187c7d860da4..b312b166be66eb19f5d295f08cc23d82a39c48b2 100644 (file)
@@ -1,14 +1,14 @@
 #
 # Automatically generated make config: don't edit
-# Linux kernel version: 2.6.29-rc3
-# Mon Feb  2 13:13:04 2009
+# Linux kernel version: 2.6.31-rc4
+# Wed Jul 29 17:27:20 2009
 #
 # CONFIG_PPC64 is not set
 
 #
 # Processor support
 #
-# CONFIG_6xx is not set
+# CONFIG_PPC_BOOK3S_32 is not set
 # CONFIG_PPC_85xx is not set
 # CONFIG_PPC_8xx is not set
 # CONFIG_40x is not set
@@ -31,15 +31,16 @@ CONFIG_GENERIC_TIME=y
 CONFIG_GENERIC_TIME_VSYSCALL=y
 CONFIG_GENERIC_CLOCKEVENTS=y
 CONFIG_GENERIC_HARDIRQS=y
+CONFIG_GENERIC_HARDIRQS_NO__DO_IRQ=y
 # CONFIG_HAVE_SETUP_PER_CPU_AREA is not set
 CONFIG_IRQ_PER_CPU=y
 CONFIG_STACKTRACE_SUPPORT=y
 CONFIG_HAVE_LATENCYTOP_SUPPORT=y
+CONFIG_TRACE_IRQFLAGS_SUPPORT=y
 CONFIG_LOCKDEP_SUPPORT=y
 CONFIG_RWSEM_XCHGADD_ALGORITHM=y
 CONFIG_ARCH_HAS_ILOG2_U32=y
 CONFIG_GENERIC_HWEIGHT=y
-CONFIG_GENERIC_CALIBRATE_DELAY=y
 CONFIG_GENERIC_FIND_NEXT_BIT=y
 # CONFIG_ARCH_NO_VIRT_TO_BUS is not set
 CONFIG_PPC=y
@@ -53,11 +54,14 @@ CONFIG_PPC_UDBG_16550=y
 # CONFIG_GENERIC_TBSYNC is not set
 CONFIG_AUDIT_ARCH=y
 CONFIG_GENERIC_BUG=y
+CONFIG_DTC=y
 # CONFIG_DEFAULT_UIMAGE is not set
 CONFIG_PPC_DCR_NATIVE=y
 # CONFIG_PPC_DCR_MMIO is not set
 CONFIG_PPC_DCR=y
+CONFIG_ARCH_SUPPORTS_DEBUG_PAGEALLOC=y
 CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
+CONFIG_CONSTRUCTORS=y
 
 #
 # General setup
@@ -71,6 +75,7 @@ CONFIG_SWAP=y
 CONFIG_SYSVIPC=y
 CONFIG_SYSVIPC_SYSCTL=y
 CONFIG_POSIX_MQUEUE=y
+CONFIG_POSIX_MQUEUE_SYSCTL=y
 # CONFIG_BSD_PROCESS_ACCT is not set
 # CONFIG_TASKSTATS is not set
 # CONFIG_AUDIT is not set
@@ -93,8 +98,12 @@ CONFIG_SYSFS_DEPRECATED_V2=y
 # CONFIG_NAMESPACES is not set
 CONFIG_BLK_DEV_INITRD=y
 CONFIG_INITRAMFS_SOURCE=""
+CONFIG_RD_GZIP=y
+# CONFIG_RD_BZIP2 is not set
+# CONFIG_RD_LZMA is not set
 # CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
 CONFIG_SYSCTL=y
+CONFIG_ANON_INODES=y
 CONFIG_EMBEDDED=y
 CONFIG_SYSCTL_SYSCALL=y
 CONFIG_KALLSYMS=y
@@ -104,23 +113,30 @@ CONFIG_HOTPLUG=y
 CONFIG_PRINTK=y
 CONFIG_BUG=y
 CONFIG_ELF_CORE=y
-CONFIG_COMPAT_BRK=y
 CONFIG_BASE_FULL=y
 CONFIG_FUTEX=y
-CONFIG_ANON_INODES=y
 CONFIG_EPOLL=y
 CONFIG_SIGNALFD=y
 CONFIG_TIMERFD=y
 CONFIG_EVENTFD=y
 CONFIG_SHMEM=y
 CONFIG_AIO=y
+CONFIG_HAVE_PERF_COUNTERS=y
+
+#
+# Performance Counters
+#
+# CONFIG_PERF_COUNTERS is not set
 CONFIG_VM_EVENT_COUNTERS=y
 CONFIG_PCI_QUIRKS=y
 CONFIG_SLUB_DEBUG=y
+# CONFIG_STRIP_ASM_SYMS is not set
+CONFIG_COMPAT_BRK=y
 # CONFIG_SLAB is not set
 CONFIG_SLUB=y
 # CONFIG_SLOB is not set
 # CONFIG_PROFILING is not set
+# CONFIG_MARKERS is not set
 CONFIG_HAVE_OPROFILE=y
 # CONFIG_KPROBES is not set
 CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS=y
@@ -128,6 +144,12 @@ CONFIG_HAVE_IOREMAP_PROT=y
 CONFIG_HAVE_KPROBES=y
 CONFIG_HAVE_KRETPROBES=y
 CONFIG_HAVE_ARCH_TRACEHOOK=y
+
+#
+# GCOV-based kernel profiling
+#
+# CONFIG_GCOV_KERNEL is not set
+# CONFIG_SLOW_WORK is not set
 # CONFIG_HAVE_GENERIC_DMA_COHERENT is not set
 CONFIG_SLABINFO=y
 CONFIG_RT_MUTEXES=y
@@ -139,8 +161,7 @@ CONFIG_MODULE_UNLOAD=y
 # CONFIG_MODVERSIONS is not set
 # CONFIG_MODULE_SRCVERSION_ALL is not set
 CONFIG_BLOCK=y
-CONFIG_LBD=y
-# CONFIG_BLK_DEV_IO_TRACE is not set
+CONFIG_LBDAF=y
 # CONFIG_BLK_DEV_BSG is not set
 # CONFIG_BLK_DEV_INTEGRITY is not set
 
@@ -176,6 +197,7 @@ CONFIG_PPC4xx_PCI_EXPRESS=y
 # CONFIG_ARCHES is not set
 CONFIG_CANYONLANDS=y
 # CONFIG_GLACIER is not set
+# CONFIG_REDWOOD is not set
 # CONFIG_YOSEMITE is not set
 # CONFIG_XILINX_VIRTEX440_GENERIC_BOARD is not set
 CONFIG_PPC44x_SIMPLE=y
@@ -218,6 +240,7 @@ CONFIG_BINFMT_ELF=y
 # CONFIG_BINFMT_MISC is not set
 # CONFIG_MATH_EMULATION is not set
 # CONFIG_IOMMU_HELPER is not set
+# CONFIG_SWIOTLB is not set
 CONFIG_PPC_NEED_DMA_SYNC_OPS=y
 CONFIG_ARCH_ENABLE_MEMORY_HOTPLUG=y
 CONFIG_ARCH_HAS_WALK_MEMORY=y
@@ -237,10 +260,14 @@ CONFIG_PHYS_ADDR_T_64BIT=y
 CONFIG_ZONE_DMA_FLAG=1
 CONFIG_BOUNCE=y
 CONFIG_VIRT_TO_BUS=y
-CONFIG_UNEVICTABLE_LRU=y
+CONFIG_HAVE_MLOCK=y
+CONFIG_HAVE_MLOCKED_PAGE_BIT=y
+CONFIG_DEFAULT_MMAP_MIN_ADDR=4096
+CONFIG_STDBINUTILS=y
 CONFIG_PPC_4K_PAGES=y
 # CONFIG_PPC_16K_PAGES is not set
 # CONFIG_PPC_64K_PAGES is not set
+# CONFIG_PPC_256K_PAGES is not set
 CONFIG_FORCE_MAX_ZONEORDER=11
 CONFIG_PROC_DEVICETREE=y
 CONFIG_CMDLINE_BOOL=y
@@ -265,6 +292,7 @@ CONFIG_ARCH_SUPPORTS_MSI=y
 # CONFIG_PCI_LEGACY is not set
 # CONFIG_PCI_DEBUG is not set
 # CONFIG_PCI_STUB is not set
+# CONFIG_PCI_IOV is not set
 # CONFIG_PCCARD is not set
 # CONFIG_HOTPLUG_PCI is not set
 # CONFIG_HAS_RAPIDIO is not set
@@ -282,14 +310,12 @@ CONFIG_PAGE_OFFSET=0xc0000000
 CONFIG_KERNEL_START=0xc0000000
 CONFIG_PHYSICAL_START=0x00000000
 CONFIG_TASK_SIZE=0xc0000000
-CONFIG_CONSISTENT_START=0xff100000
 CONFIG_CONSISTENT_SIZE=0x00200000
 CONFIG_NET=y
 
 #
 # Networking options
 #
-CONFIG_COMPAT_NET_DEV_OPS=y
 CONFIG_PACKET=y
 # CONFIG_PACKET_MMAP is not set
 CONFIG_UNIX=y
@@ -339,6 +365,8 @@ CONFIG_DEFAULT_TCP_CONG="cubic"
 # CONFIG_LAPB is not set
 # CONFIG_ECONET is not set
 # CONFIG_WAN_ROUTER is not set
+# CONFIG_PHONET is not set
+# CONFIG_IEEE802154 is not set
 # CONFIG_NET_SCHED is not set
 # CONFIG_DCB is not set
 
@@ -351,7 +379,6 @@ CONFIG_DEFAULT_TCP_CONG="cubic"
 # CONFIG_IRDA is not set
 # CONFIG_BT is not set
 # CONFIG_AF_RXRPC is not set
-# CONFIG_PHONET is not set
 # CONFIG_WIRELESS is not set
 # CONFIG_WIMAX is not set
 # CONFIG_RFKILL is not set
@@ -375,7 +402,101 @@ CONFIG_EXTRA_FIRMWARE=""
 # CONFIG_SYS_HYPERVISOR is not set
 CONFIG_CONNECTOR=y
 CONFIG_PROC_EVENTS=y
-# CONFIG_MTD is not set
+CONFIG_MTD=y
+# CONFIG_MTD_DEBUG is not set
+# CONFIG_MTD_CONCAT is not set
+CONFIG_MTD_PARTITIONS=y
+# CONFIG_MTD_TESTS is not set
+# CONFIG_MTD_REDBOOT_PARTS is not set
+CONFIG_MTD_CMDLINE_PARTS=y
+CONFIG_MTD_OF_PARTS=y
+# CONFIG_MTD_AR7_PARTS is not set
+
+#
+# User Modules And Translation Layers
+#
+CONFIG_MTD_CHAR=y
+CONFIG_MTD_BLKDEVS=y
+CONFIG_MTD_BLOCK=y
+# CONFIG_FTL is not set
+# CONFIG_NFTL is not set
+# CONFIG_INFTL is not set
+# CONFIG_RFD_FTL is not set
+# CONFIG_SSFDC is not set
+# CONFIG_MTD_OOPS is not set
+
+#
+# RAM/ROM/Flash chip drivers
+#
+CONFIG_MTD_CFI=y
+# CONFIG_MTD_JEDECPROBE is not set
+CONFIG_MTD_GEN_PROBE=y
+# CONFIG_MTD_CFI_ADV_OPTIONS is not set
+CONFIG_MTD_MAP_BANK_WIDTH_1=y
+CONFIG_MTD_MAP_BANK_WIDTH_2=y
+CONFIG_MTD_MAP_BANK_WIDTH_4=y
+# CONFIG_MTD_MAP_BANK_WIDTH_8 is not set
+# CONFIG_MTD_MAP_BANK_WIDTH_16 is not set
+# CONFIG_MTD_MAP_BANK_WIDTH_32 is not set
+CONFIG_MTD_CFI_I1=y
+CONFIG_MTD_CFI_I2=y
+# CONFIG_MTD_CFI_I4 is not set
+# CONFIG_MTD_CFI_I8 is not set
+# CONFIG_MTD_CFI_INTELEXT is not set
+CONFIG_MTD_CFI_AMDSTD=y
+# CONFIG_MTD_CFI_STAA is not set
+CONFIG_MTD_CFI_UTIL=y
+# CONFIG_MTD_RAM is not set
+# CONFIG_MTD_ROM is not set
+# CONFIG_MTD_ABSENT is not set
+
+#
+# Mapping drivers for chip access
+#
+# CONFIG_MTD_COMPLEX_MAPPINGS is not set
+# CONFIG_MTD_PHYSMAP is not set
+CONFIG_MTD_PHYSMAP_OF=y
+# CONFIG_MTD_INTEL_VR_NOR is not set
+# CONFIG_MTD_PLATRAM is not set
+
+#
+# Self-contained MTD device drivers
+#
+# CONFIG_MTD_PMC551 is not set
+# CONFIG_MTD_SLRAM is not set
+# CONFIG_MTD_PHRAM is not set
+# CONFIG_MTD_MTDRAM is not set
+# CONFIG_MTD_BLOCK2MTD is not set
+
+#
+# Disk-On-Chip Device Drivers
+#
+# CONFIG_MTD_DOC2000 is not set
+# CONFIG_MTD_DOC2001 is not set
+# CONFIG_MTD_DOC2001PLUS is not set
+CONFIG_MTD_NAND=y
+# CONFIG_MTD_NAND_VERIFY_WRITE is not set
+CONFIG_MTD_NAND_ECC_SMC=y
+# CONFIG_MTD_NAND_MUSEUM_IDS is not set
+CONFIG_MTD_NAND_IDS=y
+CONFIG_MTD_NAND_NDFC=y
+# CONFIG_MTD_NAND_DISKONCHIP is not set
+# CONFIG_MTD_NAND_CAFE is not set
+# CONFIG_MTD_NAND_NANDSIM is not set
+# CONFIG_MTD_NAND_PLATFORM is not set
+# CONFIG_MTD_ALAUDA is not set
+# CONFIG_MTD_NAND_FSL_ELBC is not set
+# CONFIG_MTD_ONENAND is not set
+
+#
+# LPDDR flash memory drivers
+#
+# CONFIG_MTD_LPDDR is not set
+
+#
+# UBI - Unsorted block images
+#
+# CONFIG_MTD_UBI is not set
 CONFIG_OF_DEVICE=y
 CONFIG_OF_I2C=y
 # CONFIG_PARPORT is not set
@@ -418,7 +539,11 @@ CONFIG_HAVE_IDE=y
 #
 
 #
-# Enable only one of the two stacks, unless you know what you are doing
+# You can enable one or both FireWire driver stacks.
+#
+
+#
+# See the help texts for more information.
 #
 # CONFIG_FIREWIRE is not set
 # CONFIG_IEEE1394 is not set
@@ -439,6 +564,8 @@ CONFIG_NET_ETHERNET=y
 # CONFIG_SUNGEM is not set
 # CONFIG_CASSINI is not set
 # CONFIG_NET_VENDOR_3COM is not set
+# CONFIG_ETHOC is not set
+# CONFIG_DNET is not set
 # CONFIG_NET_TULIP is not set
 # CONFIG_HP100 is not set
 CONFIG_IBM_NEW_EMAC=y
@@ -457,6 +584,7 @@ CONFIG_IBM_NEW_EMAC_EMAC4=y
 # CONFIG_IBM_NEW_EMAC_MAL_COMMON_ERR is not set
 # CONFIG_NET_PCI is not set
 # CONFIG_B44 is not set
+# CONFIG_KS8842 is not set
 # CONFIG_ATL2 is not set
 # CONFIG_NETDEV_1000 is not set
 # CONFIG_NETDEV_10000 is not set
@@ -467,7 +595,6 @@ CONFIG_IBM_NEW_EMAC_EMAC4=y
 #
 # CONFIG_WLAN_PRE80211 is not set
 # CONFIG_WLAN_80211 is not set
-# CONFIG_IWLWIFI_LEDS is not set
 
 #
 # Enable WiMAX (Networking options) to see the WiMAX drivers
@@ -542,7 +669,6 @@ CONFIG_LEGACY_PTY_COUNT=256
 # CONFIG_IPMI_HANDLER is not set
 # CONFIG_HW_RANDOM is not set
 # CONFIG_NVRAM is not set
-# CONFIG_GEN_RTC is not set
 # CONFIG_R3964 is not set
 # CONFIG_APPLICOM is not set
 # CONFIG_RAW_DRIVER is not set
@@ -608,14 +734,17 @@ CONFIG_I2C_IBM_IIC=y
 # CONFIG_SENSORS_PCF8574 is not set
 # CONFIG_PCF8575 is not set
 # CONFIG_SENSORS_PCA9539 is not set
-# CONFIG_SENSORS_PCF8591 is not set
-# CONFIG_SENSORS_MAX6875 is not set
 # CONFIG_SENSORS_TSL2550 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
 # CONFIG_SPI is not set
+
+#
+# PPS support
+#
+# CONFIG_PPS is not set
 CONFIG_ARCH_WANT_OPTIONAL_GPIOLIB=y
 # CONFIG_GPIOLIB is not set
 # CONFIG_W1 is not set
@@ -640,6 +769,7 @@ CONFIG_SENSORS_AD7414=y
 # CONFIG_SENSORS_F71805F is not set
 # CONFIG_SENSORS_F71882FG is not set
 # CONFIG_SENSORS_F75375S is not set
+# CONFIG_SENSORS_G760A is not set
 # CONFIG_SENSORS_GL518SM is not set
 # CONFIG_SENSORS_GL520SM is not set
 # CONFIG_SENSORS_IT87 is not set
@@ -654,11 +784,14 @@ CONFIG_SENSORS_AD7414=y
 # CONFIG_SENSORS_LM90 is not set
 # CONFIG_SENSORS_LM92 is not set
 # CONFIG_SENSORS_LM93 is not set
+# CONFIG_SENSORS_LTC4215 is not set
 # CONFIG_SENSORS_LTC4245 is not set
+# CONFIG_SENSORS_LM95241 is not set
 # CONFIG_SENSORS_MAX1619 is not set
 # CONFIG_SENSORS_MAX6650 is not set
 # CONFIG_SENSORS_PC87360 is not set
 # CONFIG_SENSORS_PC87427 is not set
+# CONFIG_SENSORS_PCF8591 is not set
 # CONFIG_SENSORS_SIS5595 is not set
 # CONFIG_SENSORS_DME1737 is not set
 # CONFIG_SENSORS_SMSC47M1 is not set
@@ -666,6 +799,7 @@ CONFIG_SENSORS_AD7414=y
 # CONFIG_SENSORS_SMSC47B397 is not set
 # CONFIG_SENSORS_ADS7828 is not set
 # CONFIG_SENSORS_THMC50 is not set
+# CONFIG_SENSORS_TMP401 is not set
 # CONFIG_SENSORS_VIA686A is not set
 # CONFIG_SENSORS_VT1211 is not set
 # CONFIG_SENSORS_VT8231 is not set
@@ -700,24 +834,9 @@ CONFIG_SSB_POSSIBLE=y
 # CONFIG_MFD_WM8400 is not set
 # CONFIG_MFD_WM8350_I2C is not set
 # CONFIG_MFD_PCF50633 is not set
+# CONFIG_AB3100_CORE is not set
 # CONFIG_REGULATOR is not set
-
-#
-# Multimedia devices
-#
-
-#
-# Multimedia core support
-#
-# CONFIG_VIDEO_DEV is not set
-# CONFIG_DVB_CORE is not set
-# CONFIG_VIDEO_MEDIA is not set
-
-#
-# Multimedia drivers
-#
-# CONFIG_DAB is not set
-# CONFIG_USB_DABUSB is not set
+# CONFIG_MEDIA_SUPPORT is not set
 
 #
 # Graphics support
@@ -759,6 +878,7 @@ CONFIG_USB_MON=y
 # USB Host Controller Drivers
 #
 # CONFIG_USB_C67X00_HCD is not set
+# CONFIG_USB_XHCI_HCD is not set
 CONFIG_USB_EHCI_HCD=m
 # CONFIG_USB_EHCI_ROOT_HUB_TT is not set
 # CONFIG_USB_EHCI_TT_NEWSCHED is not set
@@ -767,9 +887,9 @@ CONFIG_USB_EHCI_HCD_PPC_OF=y
 # CONFIG_USB_ISP116X_HCD is not set
 # CONFIG_USB_ISP1760_HCD is not set
 CONFIG_USB_OHCI_HCD=y
-CONFIG_USB_OHCI_HCD_PPC_OF=y
 CONFIG_USB_OHCI_HCD_PPC_OF_BE=y
 CONFIG_USB_OHCI_HCD_PPC_OF_LE=y
+CONFIG_USB_OHCI_HCD_PPC_OF=y
 CONFIG_USB_OHCI_HCD_PCI=y
 CONFIG_USB_OHCI_BIG_ENDIAN_DESC=y
 CONFIG_USB_OHCI_BIG_ENDIAN_MMIO=y
@@ -789,11 +909,11 @@ CONFIG_USB_OHCI_LITTLE_ENDIAN=y
 # CONFIG_USB_TMC is not set
 
 #
-# NOTE: USB_STORAGE depends on SCSI but BLK_DEV_SD may also be needed;
+# NOTE: USB_STORAGE depends on SCSI but BLK_DEV_SD may
 #
 
 #
-# see USB_STORAGE Help for more information
+# also be needed; see USB_STORAGE Help for more info
 #
 CONFIG_USB_LIBUSUAL=y
 
@@ -821,7 +941,6 @@ CONFIG_USB_LIBUSUAL=y
 # CONFIG_USB_LED is not set
 # CONFIG_USB_CYPRESS_CY7C63 is not set
 # CONFIG_USB_CYTHERM is not set
-# CONFIG_USB_PHIDGET is not set
 # CONFIG_USB_IDMOUSE is not set
 # CONFIG_USB_FTDI_ELAN is not set
 # CONFIG_USB_APPLEDISPLAY is not set
@@ -837,6 +956,7 @@ CONFIG_USB_LIBUSUAL=y
 #
 # OTG and related infrastructure
 #
+# CONFIG_NOP_USB_XCEIV is not set
 # CONFIG_UWB is not set
 # CONFIG_MMC is not set
 # CONFIG_MEMSTICK is not set
@@ -844,9 +964,70 @@ CONFIG_USB_LIBUSUAL=y
 # CONFIG_ACCESSIBILITY is not set
 # CONFIG_INFINIBAND is not set
 # CONFIG_EDAC is not set
-# CONFIG_RTC_CLASS is not set
+CONFIG_RTC_LIB=y
+CONFIG_RTC_CLASS=y
+CONFIG_RTC_HCTOSYS=y
+CONFIG_RTC_HCTOSYS_DEVICE="rtc0"
+# CONFIG_RTC_DEBUG is not set
+
+#
+# RTC interfaces
+#
+CONFIG_RTC_INTF_SYSFS=y
+CONFIG_RTC_INTF_PROC=y
+CONFIG_RTC_INTF_DEV=y
+# CONFIG_RTC_INTF_DEV_UIE_EMUL is not set
+# CONFIG_RTC_DRV_TEST is not set
+
+#
+# I2C RTC drivers
+#
+# CONFIG_RTC_DRV_DS1307 is not set
+# CONFIG_RTC_DRV_DS1374 is not set
+# CONFIG_RTC_DRV_DS1672 is not set
+# CONFIG_RTC_DRV_MAX6900 is not set
+# CONFIG_RTC_DRV_RS5C372 is not set
+# CONFIG_RTC_DRV_ISL1208 is not set
+# CONFIG_RTC_DRV_X1205 is not set
+# CONFIG_RTC_DRV_PCF8563 is not set
+# CONFIG_RTC_DRV_PCF8583 is not set
+CONFIG_RTC_DRV_M41T80=y
+# CONFIG_RTC_DRV_M41T80_WDT is not set
+# CONFIG_RTC_DRV_S35390A is not set
+# CONFIG_RTC_DRV_FM3130 is not set
+# CONFIG_RTC_DRV_RX8581 is not set
+# CONFIG_RTC_DRV_RX8025 is not set
+
+#
+# SPI RTC drivers
+#
+
+#
+# Platform RTC drivers
+#
+# CONFIG_RTC_DRV_CMOS is not set
+# CONFIG_RTC_DRV_DS1286 is not set
+# CONFIG_RTC_DRV_DS1511 is not set
+# CONFIG_RTC_DRV_DS1553 is not set
+# CONFIG_RTC_DRV_DS1742 is not set
+# CONFIG_RTC_DRV_STK17TA8 is not set
+# CONFIG_RTC_DRV_M48T86 is not set
+# CONFIG_RTC_DRV_M48T35 is not set
+# CONFIG_RTC_DRV_M48T59 is not set
+# CONFIG_RTC_DRV_BQ4802 is not set
+# CONFIG_RTC_DRV_V3020 is not set
+
+#
+# on-CPU RTC drivers
+#
+# CONFIG_RTC_DRV_GENERIC is not set
 # CONFIG_DMADEVICES is not set
+# CONFIG_AUXDISPLAY is not set
 # CONFIG_UIO is not set
+
+#
+# TI VLYNQ
+#
 # CONFIG_STAGING is not set
 
 #
@@ -860,11 +1041,12 @@ CONFIG_EXT2_FS=y
 # CONFIG_REISERFS_FS is not set
 # CONFIG_JFS_FS is not set
 # CONFIG_FS_POSIX_ACL is not set
-CONFIG_FILE_LOCKING=y
 # CONFIG_XFS_FS is not set
 # CONFIG_GFS2_FS is not set
 # CONFIG_OCFS2_FS is not set
 # CONFIG_BTRFS_FS is not set
+CONFIG_FILE_LOCKING=y
+CONFIG_FSNOTIFY=y
 CONFIG_DNOTIFY=y
 CONFIG_INOTIFY=y
 CONFIG_INOTIFY_USER=y
@@ -873,6 +1055,11 @@ CONFIG_INOTIFY_USER=y
 # CONFIG_AUTOFS4_FS is not set
 # CONFIG_FUSE_FS is not set
 
+#
+# Caches
+#
+# CONFIG_FSCACHE is not set
+
 #
 # CD-ROM/DVD Filesystems
 #
@@ -906,6 +1093,7 @@ CONFIG_MISC_FILESYSTEMS=y
 # CONFIG_BEFS_FS is not set
 # CONFIG_BFS_FS is not set
 # CONFIG_EFS_FS is not set
+# CONFIG_JFFS2_FS is not set
 CONFIG_CRAMFS=y
 # CONFIG_SQUASHFS is not set
 # CONFIG_VXFS_FS is not set
@@ -916,6 +1104,7 @@ CONFIG_CRAMFS=y
 # CONFIG_ROMFS_FS is not set
 # CONFIG_SYSV_FS is not set
 # CONFIG_UFS_FS is not set
+# CONFIG_NILFS2_FS is not set
 CONFIG_NETWORK_FILESYSTEMS=y
 CONFIG_NFS_FS=y
 CONFIG_NFS_V3=y
@@ -927,7 +1116,6 @@ CONFIG_LOCKD=y
 CONFIG_LOCKD_V4=y
 CONFIG_NFS_COMMON=y
 CONFIG_SUNRPC=y
-# CONFIG_SUNRPC_REGISTER_V4 is not set
 # CONFIG_RPCSEC_GSS_KRB5 is not set
 # CONFIG_RPCSEC_GSS_SPKM3 is not set
 # CONFIG_SMB_FS is not set
@@ -941,8 +1129,48 @@ CONFIG_SUNRPC=y
 #
 # CONFIG_PARTITION_ADVANCED is not set
 CONFIG_MSDOS_PARTITION=y
-# CONFIG_NLS is not set
+CONFIG_NLS=y
+CONFIG_NLS_DEFAULT="iso8859-1"
+# CONFIG_NLS_CODEPAGE_437 is not set
+# CONFIG_NLS_CODEPAGE_737 is not set
+# CONFIG_NLS_CODEPAGE_775 is not set
+# CONFIG_NLS_CODEPAGE_850 is not set
+# CONFIG_NLS_CODEPAGE_852 is not set
+# CONFIG_NLS_CODEPAGE_855 is not set
+# CONFIG_NLS_CODEPAGE_857 is not set
+# CONFIG_NLS_CODEPAGE_860 is not set
+# CONFIG_NLS_CODEPAGE_861 is not set
+# CONFIG_NLS_CODEPAGE_862 is not set
+# CONFIG_NLS_CODEPAGE_863 is not set
+# CONFIG_NLS_CODEPAGE_864 is not set
+# CONFIG_NLS_CODEPAGE_865 is not set
+# CONFIG_NLS_CODEPAGE_866 is not set
+# CONFIG_NLS_CODEPAGE_869 is not set
+# CONFIG_NLS_CODEPAGE_936 is not set
+# CONFIG_NLS_CODEPAGE_950 is not set
+# CONFIG_NLS_CODEPAGE_932 is not set
+# CONFIG_NLS_CODEPAGE_949 is not set
+# CONFIG_NLS_CODEPAGE_874 is not set
+# CONFIG_NLS_ISO8859_8 is not set
+# CONFIG_NLS_CODEPAGE_1250 is not set
+# CONFIG_NLS_CODEPAGE_1251 is not set
+# CONFIG_NLS_ASCII is not set
+# CONFIG_NLS_ISO8859_1 is not set
+# CONFIG_NLS_ISO8859_2 is not set
+# CONFIG_NLS_ISO8859_3 is not set
+# CONFIG_NLS_ISO8859_4 is not set
+# CONFIG_NLS_ISO8859_5 is not set
+# CONFIG_NLS_ISO8859_6 is not set
+# CONFIG_NLS_ISO8859_7 is not set
+# CONFIG_NLS_ISO8859_9 is not set
+# CONFIG_NLS_ISO8859_13 is not set
+# CONFIG_NLS_ISO8859_14 is not set
+# CONFIG_NLS_ISO8859_15 is not set
+# CONFIG_NLS_KOI8_R is not set
+# CONFIG_NLS_KOI8_U is not set
+# CONFIG_NLS_UTF8 is not set
 # CONFIG_DLM is not set
+# CONFIG_BINARY_PRINTF is not set
 
 #
 # Library routines
@@ -957,11 +1185,13 @@ CONFIG_CRC32=y
 # CONFIG_CRC7 is not set
 # CONFIG_LIBCRC32C is not set
 CONFIG_ZLIB_INFLATE=y
-CONFIG_PLIST=y
+CONFIG_DECOMPRESS_GZIP=y
 CONFIG_HAS_IOMEM=y
 CONFIG_HAS_IOPORT=y
 CONFIG_HAS_DMA=y
 CONFIG_HAVE_LMB=y
+CONFIG_NLATTR=y
+CONFIG_GENERIC_ATOMIC64=y
 
 #
 # Kernel hacking
@@ -979,6 +1209,9 @@ CONFIG_DEBUG_KERNEL=y
 CONFIG_DETECT_SOFTLOCKUP=y
 # CONFIG_BOOTPARAM_SOFTLOCKUP_PANIC is not set
 CONFIG_BOOTPARAM_SOFTLOCKUP_PANIC_VALUE=0
+CONFIG_DETECT_HUNG_TASK=y
+# CONFIG_BOOTPARAM_HUNG_TASK_PANIC is not set
+CONFIG_BOOTPARAM_HUNG_TASK_PANIC_VALUE=0
 CONFIG_SCHED_DEBUG=y
 # CONFIG_SCHEDSTATS is not set
 # CONFIG_TIMER_STATS is not set
@@ -989,6 +1222,9 @@ CONFIG_SCHED_DEBUG=y
 # CONFIG_RT_MUTEX_TESTER is not set
 # CONFIG_DEBUG_SPINLOCK is not set
 # CONFIG_DEBUG_MUTEXES is not set
+# CONFIG_DEBUG_LOCK_ALLOC is not set
+# CONFIG_PROVE_LOCKING is not set
+# CONFIG_LOCK_STAT is not set
 # CONFIG_DEBUG_SPINLOCK_SLEEP is not set
 # CONFIG_DEBUG_LOCKING_API_SELFTESTS is not set
 # CONFIG_DEBUG_KOBJECT is not set
@@ -1000,7 +1236,6 @@ CONFIG_SCHED_DEBUG=y
 # CONFIG_DEBUG_LIST is not set
 # CONFIG_DEBUG_SG is not set
 # CONFIG_DEBUG_NOTIFIERS is not set
-# CONFIG_BOOT_PRINTK_DELAY is not set
 # CONFIG_RCU_TORTURE_TEST is not set
 # CONFIG_RCU_CPU_STALL_DETECTOR is not set
 # CONFIG_BACKTRACE_SELF_TEST is not set
@@ -1008,27 +1243,36 @@ CONFIG_SCHED_DEBUG=y
 # CONFIG_FAULT_INJECTION is not set
 # CONFIG_LATENCYTOP is not set
 CONFIG_SYSCTL_SYSCALL_CHECK=y
+# CONFIG_DEBUG_PAGEALLOC is not set
 CONFIG_HAVE_FUNCTION_TRACER=y
+CONFIG_HAVE_FUNCTION_GRAPH_TRACER=y
 CONFIG_HAVE_DYNAMIC_FTRACE=y
 CONFIG_HAVE_FTRACE_MCOUNT_RECORD=y
-
-#
-# Tracers
-#
+CONFIG_TRACING_SUPPORT=y
+CONFIG_FTRACE=y
 # CONFIG_FUNCTION_TRACER is not set
+# CONFIG_IRQSOFF_TRACER is not set
 # CONFIG_SCHED_TRACER is not set
-# CONFIG_CONTEXT_SWITCH_TRACER is not set
+# CONFIG_ENABLE_DEFAULT_TRACERS is not set
 # CONFIG_BOOT_TRACER is not set
-# CONFIG_TRACE_BRANCH_PROFILING is not set
+CONFIG_BRANCH_PROFILE_NONE=y
+# CONFIG_PROFILE_ANNOTATED_BRANCHES is not set
+# CONFIG_PROFILE_ALL_BRANCHES is not set
 # CONFIG_STACK_TRACER is not set
-# CONFIG_DYNAMIC_PRINTK_DEBUG is not set
+# CONFIG_KMEMTRACE is not set
+# CONFIG_WORKQUEUE_TRACER is not set
+# CONFIG_BLK_DEV_IO_TRACE is not set
+# CONFIG_DYNAMIC_DEBUG is not set
 # CONFIG_SAMPLES is not set
 CONFIG_HAVE_ARCH_KGDB=y
 # CONFIG_KGDB is not set
+# CONFIG_KMEMCHECK is not set
+# CONFIG_PPC_DISABLE_WERROR is not set
+CONFIG_PPC_WERROR=y
 CONFIG_PRINT_STACK_DEPTH=64
 # CONFIG_DEBUG_STACKOVERFLOW is not set
 # CONFIG_DEBUG_STACK_USAGE is not set
-# CONFIG_DEBUG_PAGEALLOC is not set
+# CONFIG_PPC_EMULATED_STATS is not set
 # CONFIG_CODE_PATCHING_SELFTEST is not set
 # CONFIG_FTR_FIXUP_SELFTEST is not set
 # CONFIG_MSI_BITMAP_SELFTEST is not set
diff --git a/arch/powerpc/configs/44x/eiger_defconfig b/arch/powerpc/configs/44x/eiger_defconfig
new file mode 100644 (file)
index 0000000..007f3bd
--- /dev/null
@@ -0,0 +1,1252 @@
+#
+# Automatically generated make config: don't edit
+# Linux kernel version: 2.6.31-rc6
+# Wed Aug 19 13:06:50 2009
+#
+# CONFIG_PPC64 is not set
+
+#
+# Processor support
+#
+# CONFIG_PPC_BOOK3S_32 is not set
+# CONFIG_PPC_85xx is not set
+# CONFIG_PPC_8xx is not set
+# CONFIG_40x is not set
+CONFIG_44x=y
+# CONFIG_E200 is not set
+CONFIG_PPC_FPU=y
+CONFIG_4xx=y
+CONFIG_BOOKE=y
+CONFIG_PTE_64BIT=y
+CONFIG_PHYS_64BIT=y
+CONFIG_PPC_MMU_NOHASH=y
+CONFIG_PPC_MMU_NOHASH_32=y
+# CONFIG_PPC_MM_SLICES is not set
+CONFIG_NOT_COHERENT_CACHE=y
+CONFIG_PPC32=y
+CONFIG_WORD_SIZE=32
+CONFIG_ARCH_PHYS_ADDR_T_64BIT=y
+CONFIG_MMU=y
+CONFIG_GENERIC_CMOS_UPDATE=y
+CONFIG_GENERIC_TIME=y
+CONFIG_GENERIC_TIME_VSYSCALL=y
+CONFIG_GENERIC_CLOCKEVENTS=y
+CONFIG_GENERIC_HARDIRQS=y
+CONFIG_GENERIC_HARDIRQS_NO__DO_IRQ=y
+# CONFIG_HAVE_SETUP_PER_CPU_AREA is not set
+CONFIG_IRQ_PER_CPU=y
+CONFIG_STACKTRACE_SUPPORT=y
+CONFIG_HAVE_LATENCYTOP_SUPPORT=y
+CONFIG_TRACE_IRQFLAGS_SUPPORT=y
+CONFIG_LOCKDEP_SUPPORT=y
+CONFIG_RWSEM_XCHGADD_ALGORITHM=y
+CONFIG_ARCH_HAS_ILOG2_U32=y
+CONFIG_GENERIC_HWEIGHT=y
+CONFIG_GENERIC_FIND_NEXT_BIT=y
+# CONFIG_ARCH_NO_VIRT_TO_BUS is not set
+CONFIG_PPC=y
+CONFIG_EARLY_PRINTK=y
+CONFIG_GENERIC_NVRAM=y
+CONFIG_SCHED_OMIT_FRAME_POINTER=y
+CONFIG_ARCH_MAY_HAVE_PC_FDC=y
+CONFIG_PPC_OF=y
+CONFIG_OF=y
+CONFIG_PPC_UDBG_16550=y
+# CONFIG_GENERIC_TBSYNC is not set
+CONFIG_AUDIT_ARCH=y
+CONFIG_GENERIC_BUG=y
+CONFIG_DTC=y
+# CONFIG_DEFAULT_UIMAGE is not set
+CONFIG_PPC_DCR_NATIVE=y
+# CONFIG_PPC_DCR_MMIO is not set
+CONFIG_PPC_DCR=y
+CONFIG_ARCH_SUPPORTS_DEBUG_PAGEALLOC=y
+CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
+CONFIG_CONSTRUCTORS=y
+
+#
+# General setup
+#
+CONFIG_EXPERIMENTAL=y
+CONFIG_BROKEN_ON_SMP=y
+CONFIG_INIT_ENV_ARG_LIMIT=32
+CONFIG_LOCALVERSION=""
+CONFIG_LOCALVERSION_AUTO=y
+CONFIG_SWAP=y
+CONFIG_SYSVIPC=y
+CONFIG_SYSVIPC_SYSCTL=y
+CONFIG_POSIX_MQUEUE=y
+CONFIG_POSIX_MQUEUE_SYSCTL=y
+# CONFIG_BSD_PROCESS_ACCT is not set
+# CONFIG_TASKSTATS is not set
+# CONFIG_AUDIT is not set
+
+#
+# RCU Subsystem
+#
+CONFIG_CLASSIC_RCU=y
+# CONFIG_TREE_RCU is not set
+# CONFIG_PREEMPT_RCU is not set
+# CONFIG_TREE_RCU_TRACE is not set
+# CONFIG_PREEMPT_RCU_TRACE is not set
+# CONFIG_IKCONFIG is not set
+CONFIG_LOG_BUF_SHIFT=14
+# CONFIG_GROUP_SCHED is not set
+# CONFIG_CGROUPS is not set
+CONFIG_SYSFS_DEPRECATED=y
+CONFIG_SYSFS_DEPRECATED_V2=y
+# CONFIG_RELAY is not set
+# CONFIG_NAMESPACES is not set
+CONFIG_BLK_DEV_INITRD=y
+CONFIG_INITRAMFS_SOURCE=""
+CONFIG_RD_GZIP=y
+# CONFIG_RD_BZIP2 is not set
+# CONFIG_RD_LZMA is not set
+# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
+CONFIG_SYSCTL=y
+CONFIG_ANON_INODES=y
+CONFIG_EMBEDDED=y
+CONFIG_SYSCTL_SYSCALL=y
+CONFIG_KALLSYMS=y
+# CONFIG_KALLSYMS_ALL is not set
+# CONFIG_KALLSYMS_EXTRA_PASS is not set
+CONFIG_HOTPLUG=y
+CONFIG_PRINTK=y
+CONFIG_BUG=y
+CONFIG_ELF_CORE=y
+CONFIG_BASE_FULL=y
+CONFIG_FUTEX=y
+CONFIG_EPOLL=y
+CONFIG_SIGNALFD=y
+CONFIG_TIMERFD=y
+CONFIG_EVENTFD=y
+CONFIG_SHMEM=y
+CONFIG_AIO=y
+CONFIG_HAVE_PERF_COUNTERS=y
+
+#
+# Performance Counters
+#
+# CONFIG_PERF_COUNTERS is not set
+CONFIG_VM_EVENT_COUNTERS=y
+CONFIG_PCI_QUIRKS=y
+CONFIG_SLUB_DEBUG=y
+# CONFIG_STRIP_ASM_SYMS is not set
+CONFIG_COMPAT_BRK=y
+# CONFIG_SLAB is not set
+CONFIG_SLUB=y
+# CONFIG_SLOB is not set
+# CONFIG_PROFILING is not set
+# CONFIG_MARKERS is not set
+CONFIG_HAVE_OPROFILE=y
+# CONFIG_KPROBES is not set
+CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS=y
+CONFIG_HAVE_IOREMAP_PROT=y
+CONFIG_HAVE_KPROBES=y
+CONFIG_HAVE_KRETPROBES=y
+CONFIG_HAVE_ARCH_TRACEHOOK=y
+
+#
+# GCOV-based kernel profiling
+#
+# CONFIG_GCOV_KERNEL is not set
+# CONFIG_SLOW_WORK is not set
+# CONFIG_HAVE_GENERIC_DMA_COHERENT is not set
+CONFIG_SLABINFO=y
+CONFIG_RT_MUTEXES=y
+CONFIG_BASE_SMALL=0
+CONFIG_MODULES=y
+# CONFIG_MODULE_FORCE_LOAD is not set
+CONFIG_MODULE_UNLOAD=y
+# CONFIG_MODULE_FORCE_UNLOAD is not set
+# CONFIG_MODVERSIONS is not set
+# CONFIG_MODULE_SRCVERSION_ALL is not set
+CONFIG_BLOCK=y
+CONFIG_LBDAF=y
+# CONFIG_BLK_DEV_BSG is not set
+# CONFIG_BLK_DEV_INTEGRITY is not set
+
+#
+# IO Schedulers
+#
+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_FREEZER is not set
+CONFIG_PPC4xx_PCI_EXPRESS=y
+
+#
+# Platform support
+#
+# CONFIG_PPC_CELL is not set
+# CONFIG_PPC_CELL_NATIVE is not set
+# CONFIG_PQ2ADS is not set
+# CONFIG_BAMBOO is not set
+# CONFIG_EBONY is not set
+# CONFIG_SAM440EP is not set
+# CONFIG_SEQUOIA is not set
+# CONFIG_TAISHAN is not set
+# CONFIG_KATMAI is not set
+# CONFIG_RAINIER is not set
+# CONFIG_WARP is not set
+# CONFIG_ARCHES is not set
+# CONFIG_CANYONLANDS is not set
+# CONFIG_GLACIER is not set
+# CONFIG_REDWOOD is not set
+CONFIG_EIGER=y
+# CONFIG_YOSEMITE is not set
+# CONFIG_XILINX_VIRTEX440_GENERIC_BOARD is not set
+CONFIG_PPC44x_SIMPLE=y
+# CONFIG_PPC4xx_GPIO is not set
+CONFIG_460SX=y
+# CONFIG_IPIC is not set
+# CONFIG_MPIC is not set
+# CONFIG_MPIC_WEIRD is not set
+# CONFIG_PPC_I8259 is not set
+# CONFIG_PPC_RTAS is not set
+# CONFIG_MMIO_NVRAM is not set
+# CONFIG_PPC_MPC106 is not set
+# CONFIG_PPC_970_NAP is not set
+# CONFIG_PPC_INDIRECT_IO is not set
+# CONFIG_GENERIC_IOMAP is not set
+# CONFIG_CPU_FREQ is not set
+# CONFIG_FSL_ULI1575 is not set
+# CONFIG_SIMPLE_GPIO is not set
+
+#
+# Kernel options
+#
+# CONFIG_HIGHMEM is not set
+CONFIG_TICK_ONESHOT=y
+CONFIG_NO_HZ=y
+CONFIG_HIGH_RES_TIMERS=y
+CONFIG_GENERIC_CLOCKEVENTS_BUILD=y
+# CONFIG_HZ_100 is not set
+CONFIG_HZ_250=y
+# CONFIG_HZ_300 is not set
+# CONFIG_HZ_1000 is not set
+CONFIG_HZ=250
+CONFIG_SCHED_HRTICK=y
+CONFIG_PREEMPT_NONE=y
+# CONFIG_PREEMPT_VOLUNTARY is not set
+# CONFIG_PREEMPT is not set
+CONFIG_BINFMT_ELF=y
+# CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS is not set
+# CONFIG_HAVE_AOUT is not set
+# CONFIG_BINFMT_MISC is not set
+# CONFIG_MATH_EMULATION is not set
+# CONFIG_IOMMU_HELPER is not set
+# CONFIG_SWIOTLB is not set
+CONFIG_PPC_NEED_DMA_SYNC_OPS=y
+CONFIG_ARCH_ENABLE_MEMORY_HOTPLUG=y
+CONFIG_ARCH_HAS_WALK_MEMORY=y
+CONFIG_ARCH_ENABLE_MEMORY_HOTREMOVE=y
+CONFIG_ARCH_FLATMEM_ENABLE=y
+CONFIG_ARCH_POPULATES_NODE_MAP=y
+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_PAGEFLAGS_EXTENDED=y
+CONFIG_SPLIT_PTLOCK_CPUS=4
+CONFIG_MIGRATION=y
+CONFIG_PHYS_ADDR_T_64BIT=y
+CONFIG_ZONE_DMA_FLAG=1
+CONFIG_BOUNCE=y
+CONFIG_VIRT_TO_BUS=y
+CONFIG_HAVE_MLOCK=y
+CONFIG_HAVE_MLOCKED_PAGE_BIT=y
+CONFIG_DEFAULT_MMAP_MIN_ADDR=4096
+CONFIG_STDBINUTILS=y
+CONFIG_PPC_4K_PAGES=y
+# CONFIG_PPC_16K_PAGES is not set
+# CONFIG_PPC_64K_PAGES is not set
+# CONFIG_PPC_256K_PAGES is not set
+CONFIG_FORCE_MAX_ZONEORDER=11
+CONFIG_PROC_DEVICETREE=y
+CONFIG_CMDLINE_BOOL=y
+CONFIG_CMDLINE=""
+CONFIG_EXTRA_TARGETS=""
+CONFIG_SECCOMP=y
+CONFIG_ISA_DMA_API=y
+
+#
+# Bus options
+#
+CONFIG_ZONE_DMA=y
+CONFIG_PPC_INDIRECT_PCI=y
+CONFIG_4xx_SOC=y
+CONFIG_PPC_PCI_CHOICE=y
+CONFIG_PCI=y
+CONFIG_PCI_DOMAINS=y
+CONFIG_PCI_SYSCALL=y
+CONFIG_PCIEPORTBUS=y
+CONFIG_PCIEAER=y
+# CONFIG_PCIE_ECRC is not set
+# CONFIG_PCIEAER_INJECT is not set
+# CONFIG_PCIEASPM is not set
+CONFIG_ARCH_SUPPORTS_MSI=y
+# CONFIG_PCI_MSI is not set
+CONFIG_PCI_LEGACY=y
+# CONFIG_PCI_DEBUG is not set
+# CONFIG_PCI_STUB is not set
+# CONFIG_PCI_IOV is not set
+# CONFIG_PCCARD is not set
+# CONFIG_HOTPLUG_PCI is not set
+# CONFIG_HAS_RAPIDIO is not set
+
+#
+# Advanced setup
+#
+# CONFIG_ADVANCED_OPTIONS is not set
+
+#
+# Default settings for advanced configuration options are used
+#
+CONFIG_LOWMEM_SIZE=0x30000000
+CONFIG_PAGE_OFFSET=0xc0000000
+CONFIG_KERNEL_START=0xc0000000
+CONFIG_PHYSICAL_START=0x00000000
+CONFIG_TASK_SIZE=0xc0000000
+CONFIG_CONSISTENT_SIZE=0x00200000
+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 is not set
+# 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_ARPD is not set
+# CONFIG_SYN_COOKIES is not set
+# CONFIG_INET_AH is not set
+# CONFIG_INET_ESP is not set
+# CONFIG_INET_IPCOMP is not set
+# CONFIG_INET_XFRM_TUNNEL is not set
+# CONFIG_INET_TUNNEL is not set
+# CONFIG_INET_XFRM_MODE_TRANSPORT is not set
+# CONFIG_INET_XFRM_MODE_TUNNEL is not set
+# CONFIG_INET_XFRM_MODE_BEET is not set
+# CONFIG_INET_LRO is not set
+CONFIG_INET_DIAG=y
+CONFIG_INET_TCP_DIAG=y
+# CONFIG_TCP_CONG_ADVANCED is not set
+CONFIG_TCP_CONG_CUBIC=y
+CONFIG_DEFAULT_TCP_CONG="cubic"
+# CONFIG_TCP_MD5SIG is not set
+# CONFIG_IPV6 is not set
+# CONFIG_NETWORK_SECMARK is not set
+# CONFIG_NETFILTER is not set
+# CONFIG_IP_DCCP is not set
+# CONFIG_IP_SCTP is not set
+# CONFIG_TIPC is not set
+# CONFIG_ATM is not set
+# CONFIG_BRIDGE is not set
+# CONFIG_NET_DSA 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_ECONET is not set
+# CONFIG_WAN_ROUTER is not set
+# CONFIG_PHONET is not set
+# CONFIG_IEEE802154 is not set
+# CONFIG_NET_SCHED is not set
+# CONFIG_DCB is not set
+
+#
+# Network testing
+#
+# CONFIG_NET_PKTGEN is not set
+# CONFIG_HAMRADIO is not set
+# CONFIG_CAN is not set
+# CONFIG_IRDA is not set
+# CONFIG_BT is not set
+# CONFIG_AF_RXRPC is not set
+CONFIG_WIRELESS=y
+# CONFIG_CFG80211 is not set
+CONFIG_WIRELESS_OLD_REGULATORY=y
+# CONFIG_WIRELESS_EXT is not set
+# CONFIG_LIB80211 is not set
+
+#
+# CFG80211 needs to be enabled for MAC80211
+#
+CONFIG_MAC80211_DEFAULT_PS_VALUE=0
+# CONFIG_WIMAX is not set
+# CONFIG_RFKILL is not set
+# CONFIG_NET_9P is not set
+
+#
+# Device Drivers
+#
+
+#
+# Generic Driver Options
+#
+CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
+CONFIG_STANDALONE=y
+CONFIG_PREVENT_FIRMWARE_BUILD=y
+CONFIG_FW_LOADER=y
+CONFIG_FIRMWARE_IN_KERNEL=y
+CONFIG_EXTRA_FIRMWARE=""
+# CONFIG_DEBUG_DRIVER is not set
+# CONFIG_DEBUG_DEVRES is not set
+# CONFIG_SYS_HYPERVISOR is not set
+CONFIG_CONNECTOR=y
+CONFIG_PROC_EVENTS=y
+CONFIG_MTD=y
+# CONFIG_MTD_DEBUG is not set
+CONFIG_MTD_CONCAT=y
+CONFIG_MTD_PARTITIONS=y
+# CONFIG_MTD_TESTS is not set
+# CONFIG_MTD_REDBOOT_PARTS is not set
+CONFIG_MTD_CMDLINE_PARTS=y
+CONFIG_MTD_OF_PARTS=y
+# CONFIG_MTD_AR7_PARTS is not set
+
+#
+# User Modules And Translation Layers
+#
+CONFIG_MTD_CHAR=y
+CONFIG_MTD_BLKDEVS=y
+CONFIG_MTD_BLOCK=y
+# CONFIG_FTL is not set
+# CONFIG_NFTL is not set
+# CONFIG_INFTL is not set
+# CONFIG_RFD_FTL is not set
+# CONFIG_SSFDC is not set
+# CONFIG_MTD_OOPS is not set
+
+#
+# RAM/ROM/Flash chip drivers
+#
+CONFIG_MTD_CFI=y
+# CONFIG_MTD_JEDECPROBE is not set
+CONFIG_MTD_GEN_PROBE=y
+# CONFIG_MTD_CFI_ADV_OPTIONS is not set
+CONFIG_MTD_MAP_BANK_WIDTH_1=y
+CONFIG_MTD_MAP_BANK_WIDTH_2=y
+CONFIG_MTD_MAP_BANK_WIDTH_4=y
+# CONFIG_MTD_MAP_BANK_WIDTH_8 is not set
+# CONFIG_MTD_MAP_BANK_WIDTH_16 is not set
+# CONFIG_MTD_MAP_BANK_WIDTH_32 is not set
+CONFIG_MTD_CFI_I1=y
+CONFIG_MTD_CFI_I2=y
+# CONFIG_MTD_CFI_I4 is not set
+# CONFIG_MTD_CFI_I8 is not set
+# CONFIG_MTD_CFI_INTELEXT is not set
+CONFIG_MTD_CFI_AMDSTD=y
+# CONFIG_MTD_CFI_STAA is not set
+CONFIG_MTD_CFI_UTIL=y
+# CONFIG_MTD_RAM is not set
+# CONFIG_MTD_ROM is not set
+# CONFIG_MTD_ABSENT is not set
+
+#
+# Mapping drivers for chip access
+#
+# CONFIG_MTD_COMPLEX_MAPPINGS is not set
+# CONFIG_MTD_PHYSMAP is not set
+CONFIG_MTD_PHYSMAP_OF=y
+# CONFIG_MTD_INTEL_VR_NOR is not set
+# CONFIG_MTD_PLATRAM is not set
+
+#
+# Self-contained MTD device drivers
+#
+# CONFIG_MTD_PMC551 is not set
+# CONFIG_MTD_SLRAM is not set
+# CONFIG_MTD_PHRAM is not set
+# CONFIG_MTD_MTDRAM is not set
+# CONFIG_MTD_BLOCK2MTD is not set
+
+#
+# Disk-On-Chip Device Drivers
+#
+# CONFIG_MTD_DOC2000 is not set
+# CONFIG_MTD_DOC2001 is not set
+# CONFIG_MTD_DOC2001PLUS is not set
+CONFIG_MTD_NAND=y
+# CONFIG_MTD_NAND_VERIFY_WRITE is not set
+CONFIG_MTD_NAND_ECC_SMC=y
+# CONFIG_MTD_NAND_MUSEUM_IDS is not set
+CONFIG_MTD_NAND_IDS=y
+CONFIG_MTD_NAND_NDFC=y
+# CONFIG_MTD_NAND_DISKONCHIP is not set
+# CONFIG_MTD_NAND_CAFE is not set
+# CONFIG_MTD_NAND_NANDSIM is not set
+# CONFIG_MTD_NAND_PLATFORM is not set
+# CONFIG_MTD_NAND_FSL_ELBC is not set
+# CONFIG_MTD_ONENAND is not set
+
+#
+# LPDDR flash memory drivers
+#
+# CONFIG_MTD_LPDDR is not set
+
+#
+# UBI - Unsorted block images
+#
+# CONFIG_MTD_UBI is not set
+CONFIG_OF_DEVICE=y
+CONFIG_OF_I2C=y
+# CONFIG_PARPORT is not set
+CONFIG_BLK_DEV=y
+# 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 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=35000
+# CONFIG_BLK_DEV_XIP is not set
+# CONFIG_CDROM_PKTCDVD is not set
+# CONFIG_ATA_OVER_ETH is not set
+# CONFIG_XILINX_SYSACE is not set
+# CONFIG_BLK_DEV_HD is not set
+# CONFIG_MISC_DEVICES is not set
+CONFIG_HAVE_IDE=y
+# CONFIG_IDE is not set
+
+#
+# SCSI device support
+#
+# CONFIG_RAID_ATTRS is not set
+CONFIG_SCSI=y
+CONFIG_SCSI_DMA=y
+# CONFIG_SCSI_TGT is not set
+# CONFIG_SCSI_NETLINK is not set
+CONFIG_SCSI_PROC_FS=y
+
+#
+# SCSI support type (disk, tape, CD-ROM)
+#
+CONFIG_BLK_DEV_SD=y
+# CONFIG_CHR_DEV_ST is not set
+# CONFIG_CHR_DEV_OSST is not set
+# CONFIG_BLK_DEV_SR is not set
+CONFIG_CHR_DEV_SG=y
+# CONFIG_CHR_DEV_SCH is not set
+# CONFIG_SCSI_MULTI_LUN is not set
+# CONFIG_SCSI_CONSTANTS is not set
+# CONFIG_SCSI_LOGGING is not set
+# CONFIG_SCSI_SCAN_ASYNC is not set
+CONFIG_SCSI_WAIT_SCAN=m
+
+#
+# SCSI Transports
+#
+# CONFIG_SCSI_SPI_ATTRS is not set
+# CONFIG_SCSI_FC_ATTRS is not set
+# CONFIG_SCSI_ISCSI_ATTRS is not set
+CONFIG_SCSI_SAS_ATTRS=y
+# CONFIG_SCSI_SAS_LIBSAS is not set
+# CONFIG_SCSI_SRP_ATTRS is not set
+CONFIG_SCSI_LOWLEVEL=y
+# CONFIG_ISCSI_TCP is not set
+# CONFIG_SCSI_BNX2_ISCSI 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
+# CONFIG_SCSI_AACRAID is not set
+# CONFIG_SCSI_AIC7XXX is not set
+# CONFIG_SCSI_AIC7XXX_OLD is not set
+# CONFIG_SCSI_AIC79XX is not set
+# CONFIG_SCSI_AIC94XX is not set
+# CONFIG_SCSI_MVSAS is not set
+# CONFIG_SCSI_DPT_I2O is not set
+# CONFIG_SCSI_ADVANSYS is not set
+# CONFIG_SCSI_ARCMSR is not set
+# CONFIG_MEGARAID_NEWGEN is not set
+# CONFIG_MEGARAID_LEGACY is not set
+# CONFIG_MEGARAID_SAS is not set
+# CONFIG_SCSI_MPT2SAS is not set
+# CONFIG_SCSI_HPTIOP is not set
+# CONFIG_SCSI_BUSLOGIC is not set
+# CONFIG_LIBFC is not set
+# CONFIG_LIBFCOE is not set
+# CONFIG_FCOE is not set
+# CONFIG_SCSI_DMX3191D is not set
+# CONFIG_SCSI_EATA is not set
+# CONFIG_SCSI_FUTURE_DOMAIN is not set
+# CONFIG_SCSI_GDTH is not set
+# CONFIG_SCSI_IPS is not set
+# CONFIG_SCSI_INITIO is not set
+# CONFIG_SCSI_INIA100 is not set
+# CONFIG_SCSI_STEX is not set
+# CONFIG_SCSI_SYM53C8XX_2 is not set
+# CONFIG_SCSI_QLOGIC_1280 is not set
+# CONFIG_SCSI_QLA_FC is not set
+# CONFIG_SCSI_QLA_ISCSI is not set
+# CONFIG_SCSI_LPFC is not set
+# CONFIG_SCSI_DC395x is not set
+# CONFIG_SCSI_DC390T is not set
+# CONFIG_SCSI_NSP32 is not set
+# CONFIG_SCSI_DEBUG is not set
+# CONFIG_SCSI_SRP is not set
+# CONFIG_SCSI_DH is not set
+# CONFIG_SCSI_OSD_INITIATOR is not set
+# CONFIG_ATA is not set
+# CONFIG_MD is not set
+CONFIG_FUSION=y
+# CONFIG_FUSION_SPI is not set
+# CONFIG_FUSION_FC is not set
+CONFIG_FUSION_SAS=y
+CONFIG_FUSION_MAX_SGE=128
+# CONFIG_FUSION_CTL is not set
+# CONFIG_FUSION_LOGGING is not set
+
+#
+# IEEE 1394 (FireWire) support
+#
+
+#
+# You can enable one or both FireWire driver stacks.
+#
+
+#
+# See the help texts for more information.
+#
+# CONFIG_FIREWIRE is not set
+# CONFIG_IEEE1394 is not set
+CONFIG_I2O=y
+CONFIG_I2O_LCT_NOTIFY_ON_CHANGES=y
+CONFIG_I2O_EXT_ADAPTEC=y
+# CONFIG_I2O_CONFIG is not set
+# CONFIG_I2O_BUS is not set
+# CONFIG_I2O_BLOCK is not set
+# CONFIG_I2O_SCSI is not set
+# CONFIG_I2O_PROC is not set
+# CONFIG_MACINTOSH_DRIVERS is not set
+CONFIG_NETDEVICES=y
+# CONFIG_DUMMY is not set
+# CONFIG_BONDING is not set
+# CONFIG_MACVLAN is not set
+# CONFIG_EQUALIZER is not set
+# CONFIG_TUN is not set
+# CONFIG_VETH is not set
+# CONFIG_ARCNET is not set
+# CONFIG_PHYLIB is not set
+CONFIG_NET_ETHERNET=y
+# CONFIG_MII is not set
+# CONFIG_HAPPYMEAL is not set
+# CONFIG_SUNGEM is not set
+# CONFIG_CASSINI is not set
+# CONFIG_NET_VENDOR_3COM is not set
+# CONFIG_ETHOC is not set
+# CONFIG_DNET is not set
+# CONFIG_NET_TULIP is not set
+# CONFIG_HP100 is not set
+CONFIG_IBM_NEW_EMAC=y
+CONFIG_IBM_NEW_EMAC_RXB=256
+CONFIG_IBM_NEW_EMAC_TXB=256
+CONFIG_IBM_NEW_EMAC_POLL_WEIGHT=32
+CONFIG_IBM_NEW_EMAC_RX_COPY_THRESHOLD=256
+CONFIG_IBM_NEW_EMAC_RX_SKB_HEADROOM=0
+# CONFIG_IBM_NEW_EMAC_DEBUG is not set
+CONFIG_IBM_NEW_EMAC_ZMII=y
+CONFIG_IBM_NEW_EMAC_RGMII=y
+CONFIG_IBM_NEW_EMAC_TAH=y
+CONFIG_IBM_NEW_EMAC_EMAC4=y
+# CONFIG_IBM_NEW_EMAC_NO_FLOW_CTRL is not set
+# CONFIG_IBM_NEW_EMAC_MAL_CLR_ICINTSTAT is not set
+# CONFIG_IBM_NEW_EMAC_MAL_COMMON_ERR is not set
+# CONFIG_NET_PCI is not set
+# CONFIG_B44 is not set
+# CONFIG_KS8842 is not set
+# CONFIG_ATL2 is not set
+CONFIG_NETDEV_1000=y
+# CONFIG_ACENIC is not set
+# CONFIG_DL2K is not set
+# CONFIG_E1000 is not set
+CONFIG_E1000E=y
+# CONFIG_IP1000 is not set
+# CONFIG_IGB is not set
+# CONFIG_IGBVF 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_SKY2 is not set
+# CONFIG_VIA_VELOCITY is not set
+# CONFIG_TIGON3 is not set
+# CONFIG_BNX2 is not set
+# CONFIG_CNIC is not set
+# CONFIG_MV643XX_ETH is not set
+# CONFIG_XILINX_LL_TEMAC is not set
+# CONFIG_QLA3XXX is not set
+# CONFIG_ATL1 is not set
+# CONFIG_ATL1E is not set
+# CONFIG_ATL1C is not set
+# CONFIG_JME is not set
+# CONFIG_NETDEV_10000 is not set
+# CONFIG_TR is not set
+
+#
+# Wireless LAN
+#
+# CONFIG_WLAN_PRE80211 is not set
+# CONFIG_WLAN_80211 is not set
+
+#
+# Enable WiMAX (Networking options) to see the WiMAX drivers
+#
+# 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_NET_FC is not set
+# CONFIG_NETCONSOLE is not set
+# CONFIG_NETPOLL is not set
+# CONFIG_NET_POLL_CONTROLLER is not set
+# CONFIG_ISDN is not set
+# CONFIG_PHONE is not set
+
+#
+# Input device support
+#
+# CONFIG_INPUT is not set
+
+#
+# Hardware I/O ports
+#
+# CONFIG_SERIO is not set
+# CONFIG_GAMEPORT is not set
+
+#
+# Character devices
+#
+# CONFIG_VT is not set
+CONFIG_DEVKMEM=y
+# CONFIG_SERIAL_NONSTANDARD is not set
+# CONFIG_NOZOMI is not set
+
+#
+# Serial drivers
+#
+CONFIG_SERIAL_8250=y
+CONFIG_SERIAL_8250_CONSOLE=y
+# CONFIG_SERIAL_8250_PCI is not set
+CONFIG_SERIAL_8250_NR_UARTS=2
+CONFIG_SERIAL_8250_RUNTIME_UARTS=2
+CONFIG_SERIAL_8250_EXTENDED=y
+# CONFIG_SERIAL_8250_MANY_PORTS is not set
+CONFIG_SERIAL_8250_SHARE_IRQ=y
+# CONFIG_SERIAL_8250_DETECT_IRQ is not set
+# CONFIG_SERIAL_8250_RSA is not set
+
+#
+# Non-8250 serial port support
+#
+# CONFIG_SERIAL_UARTLITE is not set
+CONFIG_SERIAL_CORE=y
+CONFIG_SERIAL_CORE_CONSOLE=y
+# CONFIG_SERIAL_JSM is not set
+CONFIG_SERIAL_OF_PLATFORM=y
+# CONFIG_SERIAL_OF_PLATFORM_NWPSERIAL is not set
+CONFIG_UNIX98_PTYS=y
+# CONFIG_DEVPTS_MULTIPLE_INSTANCES is not set
+CONFIG_LEGACY_PTYS=y
+CONFIG_LEGACY_PTY_COUNT=256
+# CONFIG_HVC_UDBG is not set
+# CONFIG_IPMI_HANDLER is not set
+# CONFIG_HW_RANDOM is not set
+# CONFIG_NVRAM is not set
+# CONFIG_GEN_RTC is not set
+# CONFIG_R3964 is not set
+# CONFIG_APPLICOM is not set
+# CONFIG_RAW_DRIVER is not set
+# CONFIG_TCG_TPM is not set
+CONFIG_DEVPORT=y
+CONFIG_I2C=y
+CONFIG_I2C_BOARDINFO=y
+CONFIG_I2C_CHARDEV=y
+CONFIG_I2C_HELPER_AUTO=y
+
+#
+# I2C Hardware Bus support
+#
+
+#
+# PC SMBus host controller drivers
+#
+# 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_ISCH is not set
+# CONFIG_I2C_PIIX4 is not set
+# CONFIG_I2C_NFORCE2 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
+
+#
+# I2C system bus drivers (mostly embedded / system-on-chip)
+#
+CONFIG_I2C_IBM_IIC=y
+# CONFIG_I2C_MPC is not set
+# CONFIG_I2C_OCORES is not set
+# CONFIG_I2C_SIMTEC is not set
+
+#
+# External I2C/SMBus adapter drivers
+#
+# CONFIG_I2C_PARPORT_LIGHT is not set
+# CONFIG_I2C_TAOS_EVM is not set
+
+#
+# Graphics adapter I2C/DDC channel drivers
+#
+# CONFIG_I2C_VOODOO3 is not set
+
+#
+# Other I2C/SMBus bus drivers
+#
+# CONFIG_I2C_PCA_PLATFORM is not set
+# CONFIG_I2C_STUB is not set
+
+#
+# Miscellaneous I2C Chip support
+#
+# CONFIG_DS1682 is not set
+# CONFIG_SENSORS_PCF8574 is not set
+# CONFIG_PCF8575 is not set
+# CONFIG_SENSORS_PCA9539 is not set
+# CONFIG_SENSORS_TSL2550 is not set
+CONFIG_I2C_DEBUG_CORE=y
+CONFIG_I2C_DEBUG_ALGO=y
+CONFIG_I2C_DEBUG_BUS=y
+CONFIG_I2C_DEBUG_CHIP=y
+# CONFIG_SPI is not set
+
+#
+# PPS support
+#
+# CONFIG_PPS is not set
+CONFIG_ARCH_WANT_OPTIONAL_GPIOLIB=y
+# CONFIG_GPIOLIB is not set
+# CONFIG_W1 is not set
+# CONFIG_POWER_SUPPLY is not set
+# CONFIG_HWMON is not set
+# CONFIG_THERMAL is not set
+# CONFIG_THERMAL_HWMON is not set
+# CONFIG_WATCHDOG is not set
+CONFIG_SSB_POSSIBLE=y
+
+#
+# Sonics Silicon Backplane
+#
+# CONFIG_SSB is not set
+
+#
+# Multifunction device drivers
+#
+# CONFIG_MFD_CORE is not set
+# CONFIG_MFD_SM501 is not set
+# CONFIG_HTC_PASIC3 is not set
+# CONFIG_TWL4030_CORE is not set
+# CONFIG_MFD_TMIO is not set
+# CONFIG_PMIC_DA903X is not set
+# CONFIG_MFD_WM8400 is not set
+# CONFIG_MFD_WM8350_I2C is not set
+# CONFIG_MFD_PCF50633 is not set
+# CONFIG_AB3100_CORE is not set
+# CONFIG_REGULATOR is not set
+# CONFIG_MEDIA_SUPPORT is not set
+
+#
+# Graphics support
+#
+# CONFIG_AGP is not set
+# CONFIG_DRM is not set
+# CONFIG_VGASTATE is not set
+CONFIG_VIDEO_OUTPUT_CONTROL=m
+# CONFIG_FB is not set
+# CONFIG_BACKLIGHT_LCD_SUPPORT is not set
+
+#
+# Display device support
+#
+# CONFIG_DISPLAY_SUPPORT is not set
+# CONFIG_SOUND is not set
+# CONFIG_USB_SUPPORT is not set
+# CONFIG_UWB is not set
+# CONFIG_MMC is not set
+# CONFIG_MEMSTICK is not set
+# CONFIG_NEW_LEDS is not set
+# CONFIG_ACCESSIBILITY is not set
+# CONFIG_INFINIBAND is not set
+# CONFIG_EDAC is not set
+# CONFIG_RTC_CLASS is not set
+CONFIG_DMADEVICES=y
+
+#
+# DMA Devices
+#
+# CONFIG_AUXDISPLAY is not set
+# CONFIG_UIO is not set
+
+#
+# TI VLYNQ
+#
+# CONFIG_STAGING is not set
+
+#
+# File systems
+#
+CONFIG_EXT2_FS=y
+# CONFIG_EXT2_FS_XATTR is not set
+# CONFIG_EXT2_FS_XIP is not set
+# CONFIG_EXT3_FS is not set
+# CONFIG_EXT4_FS is not set
+# CONFIG_REISERFS_FS is not set
+# CONFIG_JFS_FS is not set
+# CONFIG_FS_POSIX_ACL is not set
+# CONFIG_XFS_FS is not set
+# CONFIG_GFS2_FS is not set
+# CONFIG_OCFS2_FS is not set
+# CONFIG_BTRFS_FS is not set
+CONFIG_FILE_LOCKING=y
+CONFIG_FSNOTIFY=y
+CONFIG_DNOTIFY=y
+CONFIG_INOTIFY=y
+CONFIG_INOTIFY_USER=y
+# CONFIG_QUOTA is not set
+# CONFIG_AUTOFS_FS is not set
+# CONFIG_AUTOFS4_FS is not set
+# CONFIG_FUSE_FS is not set
+
+#
+# Caches
+#
+# CONFIG_FSCACHE is not set
+
+#
+# CD-ROM/DVD Filesystems
+#
+# CONFIG_ISO9660_FS is not set
+# CONFIG_UDF_FS is not set
+
+#
+# DOS/FAT/NT Filesystems
+#
+# CONFIG_MSDOS_FS is not set
+# CONFIG_VFAT_FS is not set
+# CONFIG_NTFS_FS is not set
+
+#
+# Pseudo filesystems
+#
+CONFIG_PROC_FS=y
+CONFIG_PROC_KCORE=y
+CONFIG_PROC_SYSCTL=y
+CONFIG_PROC_PAGE_MONITOR=y
+CONFIG_SYSFS=y
+CONFIG_TMPFS=y
+# CONFIG_TMPFS_POSIX_ACL is not set
+# CONFIG_HUGETLB_PAGE is not set
+# CONFIG_CONFIGFS_FS is not set
+CONFIG_MISC_FILESYSTEMS=y
+# CONFIG_ADFS_FS is not set
+# CONFIG_AFFS_FS is not set
+# CONFIG_HFS_FS is not set
+# CONFIG_HFSPLUS_FS is not set
+# CONFIG_BEFS_FS is not set
+# CONFIG_BFS_FS is not set
+# CONFIG_EFS_FS is not set
+# CONFIG_JFFS2_FS is not set
+CONFIG_CRAMFS=y
+# CONFIG_SQUASHFS is not set
+# CONFIG_VXFS_FS is not set
+# CONFIG_MINIX_FS is not set
+# CONFIG_OMFS_FS is not set
+# CONFIG_HPFS_FS is not set
+# CONFIG_QNX4FS_FS is not set
+# CONFIG_ROMFS_FS is not set
+# CONFIG_SYSV_FS is not set
+# CONFIG_UFS_FS is not set
+# CONFIG_NILFS2_FS is not set
+CONFIG_NETWORK_FILESYSTEMS=y
+CONFIG_NFS_FS=y
+CONFIG_NFS_V3=y
+# CONFIG_NFS_V3_ACL is not set
+# CONFIG_NFS_V4 is not set
+CONFIG_ROOT_NFS=y
+# CONFIG_NFSD is not set
+CONFIG_LOCKD=y
+CONFIG_LOCKD_V4=y
+CONFIG_NFS_COMMON=y
+CONFIG_SUNRPC=y
+# CONFIG_RPCSEC_GSS_KRB5 is not set
+# CONFIG_RPCSEC_GSS_SPKM3 is not set
+# CONFIG_SMB_FS is not set
+# CONFIG_CIFS is not set
+# CONFIG_NCP_FS is not set
+# CONFIG_CODA_FS is not set
+# CONFIG_AFS_FS is not set
+
+#
+# Partition Types
+#
+# CONFIG_PARTITION_ADVANCED is not set
+CONFIG_MSDOS_PARTITION=y
+# CONFIG_NLS is not set
+# CONFIG_DLM is not set
+# CONFIG_BINARY_PRINTF is not set
+
+#
+# Library routines
+#
+CONFIG_BITREVERSE=y
+CONFIG_GENERIC_FIND_LAST_BIT=y
+# CONFIG_CRC_CCITT is not set
+# CONFIG_CRC16 is not set
+# CONFIG_CRC_T10DIF is not set
+# CONFIG_CRC_ITU_T is not set
+CONFIG_CRC32=y
+# CONFIG_CRC7 is not set
+# CONFIG_LIBCRC32C is not set
+CONFIG_ZLIB_INFLATE=y
+CONFIG_DECOMPRESS_GZIP=y
+CONFIG_HAS_IOMEM=y
+CONFIG_HAS_IOPORT=y
+CONFIG_HAS_DMA=y
+CONFIG_HAVE_LMB=y
+CONFIG_NLATTR=y
+CONFIG_GENERIC_ATOMIC64=y
+
+#
+# Kernel hacking
+#
+# CONFIG_PRINTK_TIME is not set
+CONFIG_ENABLE_WARN_DEPRECATED=y
+CONFIG_ENABLE_MUST_CHECK=y
+CONFIG_FRAME_WARN=1024
+CONFIG_MAGIC_SYSRQ=y
+# CONFIG_UNUSED_SYMBOLS is not set
+CONFIG_DEBUG_FS=y
+# CONFIG_HEADERS_CHECK is not set
+CONFIG_DEBUG_KERNEL=y
+# CONFIG_DEBUG_SHIRQ is not set
+CONFIG_DETECT_SOFTLOCKUP=y
+# CONFIG_BOOTPARAM_SOFTLOCKUP_PANIC is not set
+CONFIG_BOOTPARAM_SOFTLOCKUP_PANIC_VALUE=0
+CONFIG_DETECT_HUNG_TASK=y
+# CONFIG_BOOTPARAM_HUNG_TASK_PANIC is not set
+CONFIG_BOOTPARAM_HUNG_TASK_PANIC_VALUE=0
+CONFIG_SCHED_DEBUG=y
+# CONFIG_SCHEDSTATS is not set
+# CONFIG_TIMER_STATS is not set
+# CONFIG_DEBUG_OBJECTS is not set
+# CONFIG_SLUB_DEBUG_ON is not set
+# CONFIG_SLUB_STATS is not set
+# CONFIG_DEBUG_KMEMLEAK is not set
+# CONFIG_DEBUG_RT_MUTEXES is not set
+# CONFIG_RT_MUTEX_TESTER is not set
+# CONFIG_DEBUG_SPINLOCK is not set
+# CONFIG_DEBUG_MUTEXES is not set
+# CONFIG_DEBUG_LOCK_ALLOC is not set
+# CONFIG_PROVE_LOCKING is not set
+# CONFIG_LOCK_STAT is not set
+# CONFIG_DEBUG_SPINLOCK_SLEEP is not set
+# CONFIG_DEBUG_LOCKING_API_SELFTESTS is not set
+# CONFIG_DEBUG_KOBJECT is not set
+# CONFIG_DEBUG_BUGVERBOSE is not set
+# CONFIG_DEBUG_INFO is not set
+# CONFIG_DEBUG_VM is not set
+# CONFIG_DEBUG_WRITECOUNT is not set
+# CONFIG_DEBUG_MEMORY_INIT is not set
+# CONFIG_DEBUG_LIST is not set
+# CONFIG_DEBUG_SG is not set
+# CONFIG_DEBUG_NOTIFIERS is not set
+# CONFIG_RCU_TORTURE_TEST is not set
+# CONFIG_RCU_CPU_STALL_DETECTOR is not set
+# CONFIG_BACKTRACE_SELF_TEST is not set
+# CONFIG_DEBUG_BLOCK_EXT_DEVT is not set
+# CONFIG_FAULT_INJECTION is not set
+# CONFIG_LATENCYTOP is not set
+CONFIG_SYSCTL_SYSCALL_CHECK=y
+# CONFIG_DEBUG_PAGEALLOC is not set
+CONFIG_HAVE_FUNCTION_TRACER=y
+CONFIG_HAVE_FUNCTION_GRAPH_TRACER=y
+CONFIG_HAVE_DYNAMIC_FTRACE=y
+CONFIG_HAVE_FTRACE_MCOUNT_RECORD=y
+CONFIG_TRACING_SUPPORT=y
+CONFIG_FTRACE=y
+# CONFIG_FUNCTION_TRACER is not set
+# CONFIG_IRQSOFF_TRACER is not set
+# CONFIG_SCHED_TRACER is not set
+# CONFIG_ENABLE_DEFAULT_TRACERS is not set
+# CONFIG_BOOT_TRACER is not set
+CONFIG_BRANCH_PROFILE_NONE=y
+# CONFIG_PROFILE_ANNOTATED_BRANCHES is not set
+# CONFIG_PROFILE_ALL_BRANCHES is not set
+# CONFIG_STACK_TRACER is not set
+# CONFIG_KMEMTRACE is not set
+# CONFIG_WORKQUEUE_TRACER is not set
+# CONFIG_BLK_DEV_IO_TRACE is not set
+# CONFIG_DYNAMIC_DEBUG is not set
+# CONFIG_SAMPLES is not set
+CONFIG_HAVE_ARCH_KGDB=y
+# CONFIG_KGDB is not set
+# CONFIG_KMEMCHECK is not set
+# CONFIG_PPC_DISABLE_WERROR is not set
+CONFIG_PPC_WERROR=y
+CONFIG_PRINT_STACK_DEPTH=64
+# CONFIG_DEBUG_STACKOVERFLOW is not set
+# CONFIG_DEBUG_STACK_USAGE is not set
+# CONFIG_PPC_EMULATED_STATS is not set
+# CONFIG_CODE_PATCHING_SELFTEST is not set
+# CONFIG_FTR_FIXUP_SELFTEST is not set
+# CONFIG_MSI_BITMAP_SELFTEST is not set
+# CONFIG_XMON is not set
+# CONFIG_IRQSTACKS is not set
+# CONFIG_VIRQ_DEBUG is not set
+# CONFIG_BDI_SWITCH is not set
+# CONFIG_PPC_EARLY_DEBUG is not set
+
+#
+# Security options
+#
+# CONFIG_KEYS is not set
+# CONFIG_SECURITY is not set
+# CONFIG_SECURITYFS is not set
+# CONFIG_SECURITY_FILE_CAPABILITIES is not set
+CONFIG_CRYPTO=y
+
+#
+# Crypto core or helper
+#
+# CONFIG_CRYPTO_FIPS is not set
+CONFIG_CRYPTO_ALGAPI=y
+CONFIG_CRYPTO_ALGAPI2=y
+CONFIG_CRYPTO_AEAD=y
+CONFIG_CRYPTO_AEAD2=y
+CONFIG_CRYPTO_BLKCIPHER=y
+CONFIG_CRYPTO_BLKCIPHER2=y
+CONFIG_CRYPTO_HASH=y
+CONFIG_CRYPTO_HASH2=y
+CONFIG_CRYPTO_RNG=y
+CONFIG_CRYPTO_RNG2=y
+CONFIG_CRYPTO_PCOMP=y
+CONFIG_CRYPTO_MANAGER=y
+CONFIG_CRYPTO_MANAGER2=y
+CONFIG_CRYPTO_GF128MUL=y
+# CONFIG_CRYPTO_NULL is not set
+CONFIG_CRYPTO_WORKQUEUE=y
+CONFIG_CRYPTO_CRYPTD=y
+CONFIG_CRYPTO_AUTHENC=y
+# CONFIG_CRYPTO_TEST is not set
+
+#
+# Authenticated Encryption with Associated Data
+#
+CONFIG_CRYPTO_CCM=y
+CONFIG_CRYPTO_GCM=y
+CONFIG_CRYPTO_SEQIV=y
+
+#
+# Block modes
+#
+CONFIG_CRYPTO_CBC=y
+CONFIG_CRYPTO_CTR=y
+CONFIG_CRYPTO_CTS=y
+CONFIG_CRYPTO_ECB=y
+CONFIG_CRYPTO_LRW=y
+CONFIG_CRYPTO_PCBC=y
+CONFIG_CRYPTO_XTS=y
+
+#
+# Hash modes
+#
+CONFIG_CRYPTO_HMAC=y
+CONFIG_CRYPTO_XCBC=y
+
+#
+# Digest
+#
+# CONFIG_CRYPTO_CRC32C is not set
+CONFIG_CRYPTO_MD4=y
+CONFIG_CRYPTO_MD5=y
+# CONFIG_CRYPTO_MICHAEL_MIC is not set
+# CONFIG_CRYPTO_RMD128 is not set
+# CONFIG_CRYPTO_RMD160 is not set
+# CONFIG_CRYPTO_RMD256 is not set
+# CONFIG_CRYPTO_RMD320 is not set
+CONFIG_CRYPTO_SHA1=y
+CONFIG_CRYPTO_SHA256=y
+CONFIG_CRYPTO_SHA512=y
+# CONFIG_CRYPTO_TGR192 is not set
+# CONFIG_CRYPTO_WP512 is not set
+
+#
+# Ciphers
+#
+CONFIG_CRYPTO_AES=y
+# CONFIG_CRYPTO_ANUBIS is not set
+CONFIG_CRYPTO_ARC4=y
+CONFIG_CRYPTO_BLOWFISH=y
+# CONFIG_CRYPTO_CAMELLIA is not set
+# CONFIG_CRYPTO_CAST5 is not set
+# CONFIG_CRYPTO_CAST6 is not set
+CONFIG_CRYPTO_DES=y
+# CONFIG_CRYPTO_FCRYPT is not set
+# CONFIG_CRYPTO_KHAZAD is not set
+# CONFIG_CRYPTO_SALSA20 is not set
+# CONFIG_CRYPTO_SEED is not set
+# CONFIG_CRYPTO_SERPENT is not set
+# CONFIG_CRYPTO_TEA is not set
+# CONFIG_CRYPTO_TWOFISH is not set
+
+#
+# Compression
+#
+# CONFIG_CRYPTO_DEFLATE is not set
+# CONFIG_CRYPTO_ZLIB is not set
+# CONFIG_CRYPTO_LZO is not set
+
+#
+# Random Number Generation
+#
+# CONFIG_CRYPTO_ANSI_CPRNG is not set
+CONFIG_CRYPTO_HW=y
+# CONFIG_CRYPTO_DEV_HIFN_795X is not set
+# CONFIG_CRYPTO_DEV_PPC4XX is not set
+# CONFIG_PPC_CLOCK is not set
+# CONFIG_VIRTUALIZATION is not set
index a592b5efdc4d9a58036a277c360a671bfe7a4c6a..3a68f861b1bd9e711148077337105a7c7c54af7e 100644 (file)
@@ -1,7 +1,7 @@
 #
 # Automatically generated make config: don't edit
-# Linux kernel version: 2.6.31-rc4
-# Wed Jul 29 23:32:13 2009
+# Linux kernel version: 2.6.31-rc5
+# Tue Aug 11 19:57:51 2009
 #
 # CONFIG_PPC64 is not set
 
@@ -420,7 +420,90 @@ CONFIG_PREVENT_FIRMWARE_BUILD=y
 # CONFIG_FW_LOADER is not set
 # CONFIG_SYS_HYPERVISOR is not set
 # CONFIG_CONNECTOR is not set
-# CONFIG_MTD is not set
+CONFIG_MTD=y
+# CONFIG_MTD_DEBUG is not set
+CONFIG_MTD_CONCAT=y
+CONFIG_MTD_PARTITIONS=y
+# CONFIG_MTD_TESTS is not set
+# CONFIG_MTD_REDBOOT_PARTS is not set
+CONFIG_MTD_CMDLINE_PARTS=y
+CONFIG_MTD_OF_PARTS=y
+# CONFIG_MTD_AR7_PARTS is not set
+
+#
+# User Modules And Translation Layers
+#
+CONFIG_MTD_CHAR=y
+CONFIG_MTD_BLKDEVS=y
+CONFIG_MTD_BLOCK=y
+# CONFIG_FTL is not set
+# CONFIG_NFTL is not set
+# CONFIG_INFTL is not set
+# CONFIG_RFD_FTL is not set
+# CONFIG_SSFDC is not set
+# CONFIG_MTD_OOPS is not set
+
+#
+# RAM/ROM/Flash chip drivers
+#
+CONFIG_MTD_CFI=y
+# CONFIG_MTD_JEDECPROBE is not set
+CONFIG_MTD_GEN_PROBE=y
+# CONFIG_MTD_CFI_ADV_OPTIONS is not set
+CONFIG_MTD_MAP_BANK_WIDTH_1=y
+CONFIG_MTD_MAP_BANK_WIDTH_2=y
+CONFIG_MTD_MAP_BANK_WIDTH_4=y
+# CONFIG_MTD_MAP_BANK_WIDTH_8 is not set
+# CONFIG_MTD_MAP_BANK_WIDTH_16 is not set
+# CONFIG_MTD_MAP_BANK_WIDTH_32 is not set
+CONFIG_MTD_CFI_I1=y
+CONFIG_MTD_CFI_I2=y
+# CONFIG_MTD_CFI_I4 is not set
+# CONFIG_MTD_CFI_I8 is not set
+CONFIG_MTD_CFI_INTELEXT=y
+# CONFIG_MTD_CFI_AMDSTD is not set
+# CONFIG_MTD_CFI_STAA is not set
+CONFIG_MTD_CFI_UTIL=y
+# CONFIG_MTD_RAM is not set
+# CONFIG_MTD_ROM is not set
+# CONFIG_MTD_ABSENT is not set
+
+#
+# Mapping drivers for chip access
+#
+# CONFIG_MTD_COMPLEX_MAPPINGS is not set
+# CONFIG_MTD_PHYSMAP is not set
+CONFIG_MTD_PHYSMAP_OF=y
+# CONFIG_MTD_INTEL_VR_NOR is not set
+# CONFIG_MTD_PLATRAM is not set
+
+#
+# Self-contained MTD device drivers
+#
+# CONFIG_MTD_PMC551 is not set
+# CONFIG_MTD_SLRAM is not set
+# CONFIG_MTD_PHRAM is not set
+# CONFIG_MTD_MTDRAM is not set
+# CONFIG_MTD_BLOCK2MTD is not set
+
+#
+# Disk-On-Chip Device Drivers
+#
+# CONFIG_MTD_DOC2000 is not set
+# CONFIG_MTD_DOC2001 is not set
+# CONFIG_MTD_DOC2001PLUS is not set
+# CONFIG_MTD_NAND is not set
+# CONFIG_MTD_ONENAND is not set
+
+#
+# LPDDR flash memory drivers
+#
+# CONFIG_MTD_LPDDR is not set
+
+#
+# UBI - Unsorted block images
+#
+# CONFIG_MTD_UBI is not set
 CONFIG_OF_DEVICE=y
 CONFIG_OF_I2C=y
 CONFIG_OF_MDIO=y
@@ -436,6 +519,7 @@ 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_UB is not set
 CONFIG_BLK_DEV_RAM=y
 CONFIG_BLK_DEV_RAM_COUNT=16
 CONFIG_BLK_DEV_RAM_SIZE=32768
@@ -468,9 +552,38 @@ CONFIG_HAVE_IDE=y
 # SCSI device support
 #
 # CONFIG_RAID_ATTRS is not set
-# CONFIG_SCSI is not set
-# CONFIG_SCSI_DMA is not set
+CONFIG_SCSI=y
+CONFIG_SCSI_DMA=y
+# CONFIG_SCSI_TGT is not set
 # CONFIG_SCSI_NETLINK is not set
+# CONFIG_SCSI_PROC_FS is not set
+
+#
+# SCSI support type (disk, tape, CD-ROM)
+#
+CONFIG_BLK_DEV_SD=y
+# CONFIG_CHR_DEV_ST is not set
+# CONFIG_CHR_DEV_OSST is not set
+# CONFIG_BLK_DEV_SR is not set
+# CONFIG_CHR_DEV_SG is not set
+# CONFIG_CHR_DEV_SCH is not set
+# CONFIG_SCSI_MULTI_LUN is not set
+# CONFIG_SCSI_CONSTANTS is not set
+# CONFIG_SCSI_LOGGING is not set
+# CONFIG_SCSI_SCAN_ASYNC is not set
+CONFIG_SCSI_WAIT_SCAN=m
+
+#
+# SCSI Transports
+#
+# CONFIG_SCSI_SPI_ATTRS is not set
+# CONFIG_SCSI_FC_ATTRS is not set
+# CONFIG_SCSI_ISCSI_ATTRS is not set
+# CONFIG_SCSI_SAS_LIBSAS is not set
+# CONFIG_SCSI_SRP_ATTRS is not set
+# CONFIG_SCSI_LOWLEVEL is not set
+# CONFIG_SCSI_DH is not set
+# CONFIG_SCSI_OSD_INITIATOR is not set
 # CONFIG_ATA is not set
 # CONFIG_MD is not set
 # CONFIG_FUSION is not set
@@ -578,11 +691,21 @@ CONFIG_GIANFAR=y
 #
 # Enable WiMAX (Networking options) to see the WiMAX drivers
 #
+
+#
+# USB Network Adapters
+#
+# CONFIG_USB_CATC is not set
+# CONFIG_USB_KAWETH is not set
+# CONFIG_USB_PEGASUS is not set
+# CONFIG_USB_RTL8150 is not set
+# CONFIG_USB_USBNET is not set
 # 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_NET_FC is not set
 # CONFIG_NETCONSOLE is not set
 # CONFIG_NETPOLL is not set
 # CONFIG_NET_POLL_CONTROLLER is not set
@@ -633,9 +756,9 @@ CONFIG_DEVKMEM=y
 #
 CONFIG_SERIAL_8250=y
 CONFIG_SERIAL_8250_CONSOLE=y
-CONFIG_SERIAL_8250_PCI=y
-CONFIG_SERIAL_8250_NR_UARTS=4
-CONFIG_SERIAL_8250_RUNTIME_UARTS=4
+# CONFIG_SERIAL_8250_PCI is not set
+CONFIG_SERIAL_8250_NR_UARTS=2
+CONFIG_SERIAL_8250_RUNTIME_UARTS=2
 # CONFIG_SERIAL_8250_EXTENDED is not set
 
 #
@@ -700,6 +823,7 @@ CONFIG_I2C_MPC=y
 #
 # CONFIG_I2C_PARPORT_LIGHT is not set
 # CONFIG_I2C_TAOS_EVM is not set
+# CONFIG_I2C_TINY_USB is not set
 
 #
 # Graphics adapter I2C/DDC channel drivers
@@ -814,6 +938,11 @@ CONFIG_WATCHDOG=y
 #
 # CONFIG_PCIPCWATCHDOG is not set
 # CONFIG_WDTPCI is not set
+
+#
+# USB-based Watchdog Cards
+#
+# CONFIG_USBPCWATCHDOG is not set
 CONFIG_SSB_POSSIBLE=y
 
 #
@@ -856,12 +985,134 @@ CONFIG_HID_SUPPORT=y
 CONFIG_HID=y
 # CONFIG_HID_DEBUG is not set
 # CONFIG_HIDRAW is not set
+
+#
+# USB Input Devices
+#
+# CONFIG_USB_HID is not set
 # CONFIG_HID_PID is not set
 
+#
+# USB HID Boot Protocol drivers
+#
+# CONFIG_USB_KBD is not set
+# CONFIG_USB_MOUSE is not set
+
 #
 # Special HID drivers
 #
-# CONFIG_USB_SUPPORT is not set
+CONFIG_USB_SUPPORT=y
+CONFIG_USB_ARCH_HAS_HCD=y
+CONFIG_USB_ARCH_HAS_OHCI=y
+CONFIG_USB_ARCH_HAS_EHCI=y
+CONFIG_USB=y
+# CONFIG_USB_DEBUG is not set
+# CONFIG_USB_ANNOUNCE_NEW_DEVICES is not set
+
+#
+# Miscellaneous USB options
+#
+CONFIG_USB_DEVICEFS=y
+CONFIG_USB_DEVICE_CLASS=y
+# CONFIG_USB_DYNAMIC_MINORS is not set
+# CONFIG_USB_OTG is not set
+# CONFIG_USB_OTG_WHITELIST is not set
+# CONFIG_USB_OTG_BLACKLIST_HUB is not set
+CONFIG_USB_MON=y
+# CONFIG_USB_WUSB is not set
+# CONFIG_USB_WUSB_CBAF is not set
+
+#
+# USB Host Controller Drivers
+#
+# CONFIG_USB_C67X00_HCD is not set
+# CONFIG_USB_XHCI_HCD is not set
+CONFIG_USB_EHCI_HCD=y
+CONFIG_USB_EHCI_ROOT_HUB_TT=y
+# CONFIG_USB_EHCI_TT_NEWSCHED is not set
+CONFIG_USB_EHCI_FSL=y
+CONFIG_USB_EHCI_HCD_PPC_OF=y
+# CONFIG_USB_OXU210HP_HCD is not set
+# CONFIG_USB_ISP116X_HCD is not set
+# CONFIG_USB_ISP1760_HCD is not set
+# CONFIG_USB_OHCI_HCD is not set
+# CONFIG_USB_UHCI_HCD is not set
+# CONFIG_USB_SL811_HCD is not set
+# CONFIG_USB_R8A66597_HCD is not set
+# CONFIG_USB_WHCI_HCD is not set
+# CONFIG_USB_HWA_HCD is not set
+
+#
+# USB Device Class drivers
+#
+# CONFIG_USB_ACM is not set
+# CONFIG_USB_PRINTER is not set
+# CONFIG_USB_WDM is not set
+# CONFIG_USB_TMC is not set
+
+#
+# NOTE: USB_STORAGE depends on SCSI but BLK_DEV_SD may
+#
+
+#
+# also be needed; see USB_STORAGE Help for more info
+#
+CONFIG_USB_STORAGE=y
+# CONFIG_USB_STORAGE_DEBUG is not set
+# CONFIG_USB_STORAGE_DATAFAB is not set
+# CONFIG_USB_STORAGE_FREECOM is not set
+# CONFIG_USB_STORAGE_ISD200 is not set
+# CONFIG_USB_STORAGE_USBAT is not set
+# CONFIG_USB_STORAGE_SDDR09 is not set
+# CONFIG_USB_STORAGE_SDDR55 is not set
+# CONFIG_USB_STORAGE_JUMPSHOT is not set
+# CONFIG_USB_STORAGE_ALAUDA is not set
+# CONFIG_USB_STORAGE_ONETOUCH is not set
+# CONFIG_USB_STORAGE_KARMA is not set
+# CONFIG_USB_STORAGE_CYPRESS_ATACB is not set
+# CONFIG_USB_LIBUSUAL is not set
+
+#
+# USB Imaging devices
+#
+# CONFIG_USB_MDC800 is not set
+# CONFIG_USB_MICROTEK is not set
+
+#
+# USB port drivers
+#
+# CONFIG_USB_SERIAL is not set
+
+#
+# USB Miscellaneous drivers
+#
+# CONFIG_USB_EMI62 is not set
+# CONFIG_USB_EMI26 is not set
+# CONFIG_USB_ADUTUX is not set
+# CONFIG_USB_SEVSEG is not set
+# CONFIG_USB_RIO500 is not set
+# CONFIG_USB_LEGOTOWER is not set
+# CONFIG_USB_LCD is not set
+# CONFIG_USB_BERRY_CHARGE is not set
+# CONFIG_USB_LED is not set
+# CONFIG_USB_CYPRESS_CY7C63 is not set
+# CONFIG_USB_CYTHERM is not set
+# CONFIG_USB_IDMOUSE is not set
+# CONFIG_USB_FTDI_ELAN is not set
+# CONFIG_USB_APPLEDISPLAY is not set
+# CONFIG_USB_SISUSBVGA is not set
+# CONFIG_USB_LD is not set
+# CONFIG_USB_TRANCEVIBRATOR is not set
+# CONFIG_USB_IOWARRIOR is not set
+# CONFIG_USB_TEST is not set
+# CONFIG_USB_ISIGHTFW is not set
+# CONFIG_USB_VST is not set
+# CONFIG_USB_GADGET is not set
+
+#
+# OTG and related infrastructure
+#
+# CONFIG_NOP_USB_XCEIV is not set
 # CONFIG_UWB is not set
 # CONFIG_MMC is not set
 # CONFIG_MEMSTICK is not set
@@ -882,9 +1133,14 @@ CONFIG_HID=y
 #
 # File systems
 #
-# CONFIG_EXT2_FS is not set
-# CONFIG_EXT3_FS is not set
+CONFIG_EXT2_FS=y
+# CONFIG_EXT2_FS_XATTR is not set
+# CONFIG_EXT2_FS_XIP is not set
+CONFIG_EXT3_FS=y
+# CONFIG_EXT3_DEFAULTS_TO_ORDERED is not set
+# CONFIG_EXT3_FS_XATTR is not set
 # CONFIG_EXT4_FS is not set
+CONFIG_JBD=y
 # CONFIG_REISERFS_FS is not set
 # CONFIG_JFS_FS is not set
 # CONFIG_FS_POSIX_ACL is not set
@@ -940,6 +1196,7 @@ CONFIG_MISC_FILESYSTEMS=y
 # CONFIG_BEFS_FS is not set
 # CONFIG_BFS_FS is not set
 # CONFIG_EFS_FS is not set
+# CONFIG_JFFS2_FS is not set
 # CONFIG_CRAMFS is not set
 # CONFIG_SQUASHFS is not set
 # CONFIG_VXFS_FS is not set
@@ -977,7 +1234,46 @@ CONFIG_RPCSEC_GSS_KRB5=y
 #
 # CONFIG_PARTITION_ADVANCED is not set
 CONFIG_MSDOS_PARTITION=y
-# CONFIG_NLS is not set
+CONFIG_NLS=y
+CONFIG_NLS_DEFAULT="iso8859-1"
+# CONFIG_NLS_CODEPAGE_437 is not set
+# CONFIG_NLS_CODEPAGE_737 is not set
+# CONFIG_NLS_CODEPAGE_775 is not set
+# CONFIG_NLS_CODEPAGE_850 is not set
+# CONFIG_NLS_CODEPAGE_852 is not set
+# CONFIG_NLS_CODEPAGE_855 is not set
+# CONFIG_NLS_CODEPAGE_857 is not set
+# CONFIG_NLS_CODEPAGE_860 is not set
+# CONFIG_NLS_CODEPAGE_861 is not set
+# CONFIG_NLS_CODEPAGE_862 is not set
+# CONFIG_NLS_CODEPAGE_863 is not set
+# CONFIG_NLS_CODEPAGE_864 is not set
+# CONFIG_NLS_CODEPAGE_865 is not set
+# CONFIG_NLS_CODEPAGE_866 is not set
+# CONFIG_NLS_CODEPAGE_869 is not set
+# CONFIG_NLS_CODEPAGE_936 is not set
+# CONFIG_NLS_CODEPAGE_950 is not set
+# CONFIG_NLS_CODEPAGE_932 is not set
+# CONFIG_NLS_CODEPAGE_949 is not set
+# CONFIG_NLS_CODEPAGE_874 is not set
+# CONFIG_NLS_ISO8859_8 is not set
+# CONFIG_NLS_CODEPAGE_1250 is not set
+# CONFIG_NLS_CODEPAGE_1251 is not set
+# CONFIG_NLS_ASCII is not set
+# CONFIG_NLS_ISO8859_1 is not set
+# CONFIG_NLS_ISO8859_2 is not set
+# CONFIG_NLS_ISO8859_3 is not set
+# CONFIG_NLS_ISO8859_4 is not set
+# CONFIG_NLS_ISO8859_5 is not set
+# CONFIG_NLS_ISO8859_6 is not set
+# CONFIG_NLS_ISO8859_7 is not set
+# CONFIG_NLS_ISO8859_9 is not set
+# CONFIG_NLS_ISO8859_13 is not set
+# CONFIG_NLS_ISO8859_14 is not set
+# CONFIG_NLS_ISO8859_15 is not set
+# CONFIG_NLS_KOI8_R is not set
+# CONFIG_NLS_KOI8_U is not set
+# CONFIG_NLS_UTF8 is not set
 # CONFIG_DLM is not set
 # CONFIG_BINARY_PRINTF is not set
 
index e9491c1c3f31f9d6e69838e4dbed36fa488e45d6..30b68bfacebff68ef777f8b849291bd127d80573 100644 (file)
@@ -1,7 +1,7 @@
 #
 # Automatically generated make config: don't edit
-# Linux kernel version: 2.6.31-rc4
-# Wed Jul 29 23:31:51 2009
+# Linux kernel version: 2.6.31-rc5
+# Fri Aug  7 08:19:15 2009
 #
 # CONFIG_PPC64 is not set
 
@@ -158,6 +158,7 @@ CONFIG_BASE_SMALL=0
 # CONFIG_MODULES is not set
 CONFIG_BLOCK=y
 CONFIG_LBDAF=y
+CONFIG_BLK_DEV_BSG=y
 # CONFIG_BLK_DEV_INTEGRITY is not set
 
 #
@@ -506,6 +507,7 @@ CONFIG_MTD_PHYSMAP_OF=y
 # CONFIG_MTD_UBI is not set
 CONFIG_OF_DEVICE=y
 CONFIG_OF_GPIO=y
+CONFIG_OF_I2C=y
 CONFIG_OF_MDIO=y
 # CONFIG_PARPORT is not set
 CONFIG_BLK_DEV=y
@@ -582,7 +584,8 @@ CONFIG_PHYLIB=y
 # CONFIG_STE10XP is not set
 # CONFIG_LSI_ET1011C_PHY is not set
 CONFIG_FIXED_PHY=y
-# CONFIG_MDIO_BITBANG is not set
+CONFIG_MDIO_BITBANG=y
+# CONFIG_MDIO_GPIO is not set
 CONFIG_NET_ETHERNET=y
 CONFIG_MII=y
 # CONFIG_MACE is not set
@@ -608,8 +611,8 @@ CONFIG_MII=y
 # CONFIG_ATL2 is not set
 CONFIG_FS_ENET=y
 CONFIG_FS_ENET_HAS_SCC=y
-# CONFIG_FS_ENET_HAS_FCC is not set
-# CONFIG_FS_ENET_MDIO_FCC is not set
+CONFIG_FS_ENET_HAS_FCC=y
+CONFIG_FS_ENET_MDIO_FCC=y
 # CONFIG_NETDEV_1000 is not set
 # CONFIG_NETDEV_10000 is not set
 # CONFIG_TR is not set
@@ -680,7 +683,68 @@ CONFIG_HW_RANDOM=y
 # CONFIG_APPLICOM is not set
 # CONFIG_RAW_DRIVER is not set
 CONFIG_DEVPORT=y
-# CONFIG_I2C is not set
+CONFIG_I2C=y
+CONFIG_I2C_BOARDINFO=y
+CONFIG_I2C_CHARDEV=y
+CONFIG_I2C_HELPER_AUTO=y
+
+#
+# I2C Hardware Bus support
+#
+
+#
+# PC SMBus host controller drivers
+#
+# CONFIG_I2C_ALI1535 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_ISCH is not set
+# CONFIG_I2C_PIIX4 is not set
+# CONFIG_I2C_NFORCE2 is not set
+# CONFIG_I2C_SIS5595 is not set
+# CONFIG_I2C_SIS630 is not set
+# CONFIG_I2C_SIS96X is not set
+# CONFIG_I2C_VIAPRO is not set
+
+#
+# Mac SMBus host controller drivers
+#
+# CONFIG_I2C_POWERMAC is not set
+
+#
+# I2C system bus drivers (mostly embedded / system-on-chip)
+#
+CONFIG_I2C_CPM=y
+# CONFIG_I2C_DESIGNWARE is not set
+# CONFIG_I2C_GPIO is not set
+# CONFIG_I2C_MPC is not set
+# CONFIG_I2C_SIMTEC is not set
+
+#
+# External I2C/SMBus adapter drivers
+#
+# CONFIG_I2C_PARPORT_LIGHT is not set
+
+#
+# Graphics adapter I2C/DDC channel drivers
+#
+# CONFIG_I2C_VOODOO3 is not set
+
+#
+# Other I2C/SMBus bus drivers
+#
+# CONFIG_I2C_PCA_PLATFORM is not set
+
+#
+# Miscellaneous I2C Chip support
+#
+# CONFIG_PCF8575 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
 # CONFIG_SPI is not set
 
 #
@@ -699,6 +763,9 @@ CONFIG_GPIOLIB=y
 #
 # I2C GPIO expanders:
 #
+# CONFIG_GPIO_MAX732X is not set
+# CONFIG_GPIO_PCA953X is not set
+# CONFIG_GPIO_PCF857X is not set
 
 #
 # PCI GPIO expanders:
@@ -727,7 +794,14 @@ CONFIG_SSB_POSSIBLE=y
 # CONFIG_MFD_CORE is not set
 # CONFIG_MFD_SM501 is not set
 # CONFIG_HTC_PASIC3 is not set
+# CONFIG_TPS65010 is not set
+# CONFIG_TWL4030_CORE is not set
 # CONFIG_MFD_TMIO is not set
+# CONFIG_PMIC_DA903X is not set
+# CONFIG_MFD_WM8400 is not set
+# CONFIG_MFD_WM8350_I2C is not set
+# CONFIG_MFD_PCF50633 is not set
+# CONFIG_AB3100_CORE is not set
 # CONFIG_REGULATOR is not set
 # CONFIG_MEDIA_SUPPORT is not set
 
index ada595898af117f2653875d04bef69dd74b0eec5..ee6acc6557f816007b3144737abaae8109577b93 100644 (file)
@@ -203,6 +203,7 @@ CONFIG_MPC85xx_CDS=y
 CONFIG_MPC85xx_MDS=y
 CONFIG_MPC8536_DS=y
 CONFIG_MPC85xx_DS=y
+CONFIG_MPC85xx_RDB=y
 CONFIG_SOCRATES=y
 CONFIG_KSI8560=y
 # CONFIG_XES_MPC85xx is not set
index 86455c4c31eea851f84b73ddbdc126581ff49c92..416e12c2d5052234173675894d81f48c18e78179 100644 (file)
@@ -8,10 +8,6 @@
 #define unmap_page_from_agp(page)
 #define flush_agp_cache() mb()
 
-/* Convert a physical address to an address suitable for the GART. */
-#define phys_to_gart(x) (x)
-#define gart_to_phys(x) (x)
-
 /* GATT allocation. Returns/accepts GATT kernel virtual address. */
 #define alloc_gatt_pages(order)                \
        ((char *)__get_free_pages(GFP_KERNEL, (order)))
index 897eade3afbeb0109159de4e1eb855f42ddab4e0..56f2f2ea56319fc13897e5a94647ae54f6fc5cd3 100644 (file)
 #define BITOP_WORD(nr)         ((nr) / BITS_PER_LONG)
 #define BITOP_LE_SWIZZLE       ((BITS_PER_LONG-1) & ~0x7)
 
+/* Macro for generating the ***_bits() functions */
+#define DEFINE_BITOP(fn, op, prefix, postfix)  \
+static __inline__ void fn(unsigned long mask,  \
+               volatile unsigned long *_p)     \
+{                                              \
+       unsigned long old;                      \
+       unsigned long *p = (unsigned long *)_p; \
+       __asm__ __volatile__ (                  \
+       prefix                                  \
+"1:"   PPC_LLARX "%0,0,%3\n"                   \
+       stringify_in_c(op) "%0,%0,%2\n"         \
+       PPC405_ERR77(0,%3)                      \
+       PPC_STLCX "%0,0,%3\n"                   \
+       "bne- 1b\n"                             \
+       postfix                                 \
+       : "=&r" (old), "+m" (*p)                \
+       : "r" (mask), "r" (p)                   \
+       : "cc", "memory");                      \
+}
+
+DEFINE_BITOP(set_bits, or, "", "")
+DEFINE_BITOP(clear_bits, andc, "", "")
+DEFINE_BITOP(clear_bits_unlock, andc, LWSYNC_ON_SMP, "")
+DEFINE_BITOP(change_bits, xor, "", "")
+
 static __inline__ void set_bit(int nr, volatile unsigned long *addr)
 {
-       unsigned long old;
-       unsigned long mask = BITOP_MASK(nr);
-       unsigned long *p = ((unsigned long *)addr) + BITOP_WORD(nr);
-
-       __asm__ __volatile__(
-"1:"   PPC_LLARX "%0,0,%3      # set_bit\n"
-       "or     %0,%0,%2\n"
-       PPC405_ERR77(0,%3)
-       PPC_STLCX "%0,0,%3\n"
-       "bne-   1b"
-       : "=&r" (old), "+m" (*p)
-       : "r" (mask), "r" (p)
-       : "cc" );
+       set_bits(BITOP_MASK(nr), addr + BITOP_WORD(nr));
 }
 
 static __inline__ void clear_bit(int nr, volatile unsigned long *addr)
 {
-       unsigned long old;
-       unsigned long mask = BITOP_MASK(nr);
-       unsigned long *p = ((unsigned long *)addr) + BITOP_WORD(nr);
-
-       __asm__ __volatile__(
-"1:"   PPC_LLARX "%0,0,%3      # clear_bit\n"
-       "andc   %0,%0,%2\n"
-       PPC405_ERR77(0,%3)
-       PPC_STLCX "%0,0,%3\n"
-       "bne-   1b"
-       : "=&r" (old), "+m" (*p)
-       : "r" (mask), "r" (p)
-       : "cc" );
+       clear_bits(BITOP_MASK(nr), addr + BITOP_WORD(nr));
 }
 
 static __inline__ void clear_bit_unlock(int nr, volatile unsigned long *addr)
 {
-       unsigned long old;
-       unsigned long mask = BITOP_MASK(nr);
-       unsigned long *p = ((unsigned long *)addr) + BITOP_WORD(nr);
-
-       __asm__ __volatile__(
-       LWSYNC_ON_SMP
-"1:"   PPC_LLARX "%0,0,%3      # clear_bit_unlock\n"
-       "andc   %0,%0,%2\n"
-       PPC405_ERR77(0,%3)
-       PPC_STLCX "%0,0,%3\n"
-       "bne-   1b"
-       : "=&r" (old), "+m" (*p)
-       : "r" (mask), "r" (p)
-       : "cc", "memory");
+       clear_bits_unlock(BITOP_MASK(nr), addr + BITOP_WORD(nr));
 }
 
 static __inline__ void change_bit(int nr, volatile unsigned long *addr)
 {
-       unsigned long old;
-       unsigned long mask = BITOP_MASK(nr);
-       unsigned long *p = ((unsigned long *)addr) + BITOP_WORD(nr);
-
-       __asm__ __volatile__(
-"1:"   PPC_LLARX "%0,0,%3      # change_bit\n"
-       "xor    %0,%0,%2\n"
-       PPC405_ERR77(0,%3)
-       PPC_STLCX "%0,0,%3\n"
-       "bne-   1b"
-       : "=&r" (old), "+m" (*p)
-       : "r" (mask), "r" (p)
-       : "cc" );
+       change_bits(BITOP_MASK(nr), addr + BITOP_WORD(nr));
+}
+
+/* Like DEFINE_BITOP(), with changes to the arguments to 'op' and the output
+ * operands. */
+#define DEFINE_TESTOP(fn, op, prefix, postfix) \
+static __inline__ unsigned long fn(            \
+               unsigned long mask,             \
+               volatile unsigned long *_p)     \
+{                                              \
+       unsigned long old, t;                   \
+       unsigned long *p = (unsigned long *)_p; \
+       __asm__ __volatile__ (                  \
+       prefix                                  \
+"1:"   PPC_LLARX "%0,0,%3\n"                   \
+       stringify_in_c(op) "%1,%0,%2\n"         \
+       PPC405_ERR77(0,%3)                      \
+       PPC_STLCX "%1,0,%3\n"                   \
+       "bne- 1b\n"                             \
+       postfix                                 \
+       : "=&r" (old), "=&r" (t)                \
+       : "r" (mask), "r" (p)                   \
+       : "cc", "memory");                      \
+       return (old & mask);                    \
 }
 
+DEFINE_TESTOP(test_and_set_bits, or, LWSYNC_ON_SMP, ISYNC_ON_SMP)
+DEFINE_TESTOP(test_and_set_bits_lock, or, "", ISYNC_ON_SMP)
+DEFINE_TESTOP(test_and_clear_bits, andc, LWSYNC_ON_SMP, ISYNC_ON_SMP)
+DEFINE_TESTOP(test_and_change_bits, xor, LWSYNC_ON_SMP, ISYNC_ON_SMP)
+
 static __inline__ int test_and_set_bit(unsigned long nr,
                                       volatile unsigned long *addr)
 {
-       unsigned long old, t;
-       unsigned long mask = BITOP_MASK(nr);
-       unsigned long *p = ((unsigned long *)addr) + BITOP_WORD(nr);
-
-       __asm__ __volatile__(
-       LWSYNC_ON_SMP
-"1:"   PPC_LLARX "%0,0,%3              # test_and_set_bit\n"
-       "or     %1,%0,%2 \n"
-       PPC405_ERR77(0,%3)
-       PPC_STLCX "%1,0,%3 \n"
-       "bne-   1b"
-       ISYNC_ON_SMP
-       : "=&r" (old), "=&r" (t)
-       : "r" (mask), "r" (p)
-       : "cc", "memory");
-
-       return (old & mask) != 0;
+       return test_and_set_bits(BITOP_MASK(nr), addr + BITOP_WORD(nr)) != 0;
 }
 
 static __inline__ int test_and_set_bit_lock(unsigned long nr,
                                       volatile unsigned long *addr)
 {
-       unsigned long old, t;
-       unsigned long mask = BITOP_MASK(nr);
-       unsigned long *p = ((unsigned long *)addr) + BITOP_WORD(nr);
-
-       __asm__ __volatile__(
-"1:"   PPC_LLARX "%0,0,%3              # test_and_set_bit_lock\n"
-       "or     %1,%0,%2 \n"
-       PPC405_ERR77(0,%3)
-       PPC_STLCX "%1,0,%3 \n"
-       "bne-   1b"
-       ISYNC_ON_SMP
-       : "=&r" (old), "=&r" (t)
-       : "r" (mask), "r" (p)
-       : "cc", "memory");
-
-       return (old & mask) != 0;
+       return test_and_set_bits_lock(BITOP_MASK(nr),
+                               addr + BITOP_WORD(nr)) != 0;
 }
 
 static __inline__ int test_and_clear_bit(unsigned long nr,
                                         volatile unsigned long *addr)
 {
-       unsigned long old, t;
-       unsigned long mask = BITOP_MASK(nr);
-       unsigned long *p = ((unsigned long *)addr) + BITOP_WORD(nr);
-
-       __asm__ __volatile__(
-       LWSYNC_ON_SMP
-"1:"   PPC_LLARX "%0,0,%3              # test_and_clear_bit\n"
-       "andc   %1,%0,%2 \n"
-       PPC405_ERR77(0,%3)
-       PPC_STLCX "%1,0,%3 \n"
-       "bne-   1b"
-       ISYNC_ON_SMP
-       : "=&r" (old), "=&r" (t)
-       : "r" (mask), "r" (p)
-       : "cc", "memory");
-
-       return (old & mask) != 0;
+       return test_and_clear_bits(BITOP_MASK(nr), addr + BITOP_WORD(nr)) != 0;
 }
 
 static __inline__ int test_and_change_bit(unsigned long nr,
                                          volatile unsigned long *addr)
 {
-       unsigned long old, t;
-       unsigned long mask = BITOP_MASK(nr);
-       unsigned long *p = ((unsigned long *)addr) + BITOP_WORD(nr);
-
-       __asm__ __volatile__(
-       LWSYNC_ON_SMP
-"1:"   PPC_LLARX "%0,0,%3              # test_and_change_bit\n"
-       "xor    %1,%0,%2 \n"
-       PPC405_ERR77(0,%3)
-       PPC_STLCX "%1,0,%3 \n"
-       "bne-   1b"
-       ISYNC_ON_SMP
-       : "=&r" (old), "=&r" (t)
-       : "r" (mask), "r" (p)
-       : "cc", "memory");
-
-       return (old & mask) != 0;
-}
-
-static __inline__ void set_bits(unsigned long mask, unsigned long *addr)
-{
-        unsigned long old;
-
-       __asm__ __volatile__(
-"1:"   PPC_LLARX "%0,0,%3         # set_bits\n"
-       "or     %0,%0,%2\n"
-       PPC_STLCX "%0,0,%3\n"
-       "bne-   1b"
-       : "=&r" (old), "+m" (*addr)
-       : "r" (mask), "r" (addr)
-       : "cc");
+       return test_and_change_bits(BITOP_MASK(nr), addr + BITOP_WORD(nr)) != 0;
 }
 
 #include <asm-generic/bitops/non-atomic.h>
index fd6fd00434efc04e0e0bffdaeb98d4c9e1aac8dd..fdf64fd259508c94e8e4ab39635d7a4ef27aaa56 100644 (file)
@@ -303,6 +303,17 @@ struct cbe_mic_tm_regs {
 extern struct cbe_mic_tm_regs __iomem *cbe_get_mic_tm_regs(struct device_node *np);
 extern struct cbe_mic_tm_regs __iomem *cbe_get_cpu_mic_tm_regs(int cpu);
 
+
+/* Cell page table entries */
+#define CBE_IOPTE_PP_W         0x8000000000000000ul /* protection: write */
+#define CBE_IOPTE_PP_R         0x4000000000000000ul /* protection: read */
+#define CBE_IOPTE_M            0x2000000000000000ul /* coherency required */
+#define CBE_IOPTE_SO_R         0x1000000000000000ul /* ordering: writes */
+#define CBE_IOPTE_SO_RW                0x1800000000000000ul /* ordering: r & w */
+#define CBE_IOPTE_RPN_Mask     0x07fffffffffff000ul /* RPN */
+#define CBE_IOPTE_H            0x0000000000000800ul /* cache hint */
+#define CBE_IOPTE_IOID_Mask    0x00000000000007fful /* ioid */
+
 /* some utility functions to deal with SMT */
 extern u32 cbe_get_hw_thread_id(int cpu);
 extern u32 cbe_cpu_to_node(int cpu);
index fb11b0c459b832912cabee81141517a38d136ba6..a8e18447c62b967d381a09fb5a7f0857753dbd19 100644 (file)
@@ -5,6 +5,15 @@
 
 /*
  * Mapping of threads to cores
+ *
+ * Note: This implementation is limited to a power of 2 number of
+ * threads per core and the same number for each core in the system
+ * (though it would work if some processors had less threads as long
+ * as the CPU numbers are still allocated, just not brought offline).
+ *
+ * However, the API allows for a different implementation in the future
+ * if needed, as long as you only use the functions and not the variables
+ * directly.
  */
 
 #ifdef CONFIG_SMP
@@ -67,5 +76,12 @@ static inline int cpu_first_thread_in_core(int cpu)
        return cpu & ~(threads_per_core - 1);
 }
 
+static inline int cpu_last_thread_in_core(int cpu)
+{
+       return cpu | (threads_per_core - 1);
+}
+
+
+
 #endif /* _ASM_POWERPC_CPUTHREADS_H */
 
index e3e06e0f7fc0b14d78b0205bc74a865768554305..9dade15d1ab48c8475bc912752b57cc047a90226 100644 (file)
@@ -6,7 +6,7 @@
 #ifndef _ASM_POWERPC_DEVICE_H
 #define _ASM_POWERPC_DEVICE_H
 
-struct dma_mapping_ops;
+struct dma_map_ops;
 struct device_node;
 
 struct dev_archdata {
@@ -14,8 +14,11 @@ struct dev_archdata {
        struct device_node      *of_node;
 
        /* DMA operations on that device */
-       struct dma_mapping_ops  *dma_ops;
+       struct dma_map_ops      *dma_ops;
        void                    *dma_data;
+#ifdef CONFIG_SWIOTLB
+       dma_addr_t              max_direct_dma_addr;
+#endif
 };
 
 static inline void dev_archdata_set_node(struct dev_archdata *ad,
index 0c34371ec49c8922b21161efbf275d7c198199e4..cb2ca41dd526d077e62e9dea395404948cfc75c3 100644 (file)
@@ -14,6 +14,7 @@
 #include <linux/mm.h>
 #include <linux/scatterlist.h>
 #include <linux/dma-attrs.h>
+#include <linux/dma-debug.h>
 #include <asm/io.h>
 #include <asm/swiotlb.h>
 
@@ -63,59 +64,15 @@ static inline unsigned long device_to_mask(struct device *dev)
        return 0xfffffffful;
 }
 
-/*
- * DMA operations are abstracted for G5 vs. i/pSeries, PCI vs. VIO
- */
-struct dma_mapping_ops {
-       void *          (*alloc_coherent)(struct device *dev, size_t size,
-                               dma_addr_t *dma_handle, gfp_t flag);
-       void            (*free_coherent)(struct device *dev, size_t size,
-                               void *vaddr, dma_addr_t dma_handle);
-       int             (*map_sg)(struct device *dev, struct scatterlist *sg,
-                               int nents, enum dma_data_direction direction,
-                               struct dma_attrs *attrs);
-       void            (*unmap_sg)(struct device *dev, struct scatterlist *sg,
-                               int nents, enum dma_data_direction direction,
-                               struct dma_attrs *attrs);
-       int             (*dma_supported)(struct device *dev, u64 mask);
-       int             (*set_dma_mask)(struct device *dev, u64 dma_mask);
-       dma_addr_t      (*map_page)(struct device *dev, struct page *page,
-                               unsigned long offset, size_t size,
-                               enum dma_data_direction direction,
-                               struct dma_attrs *attrs);
-       void            (*unmap_page)(struct device *dev,
-                               dma_addr_t dma_address, size_t size,
-                               enum dma_data_direction direction,
-                               struct dma_attrs *attrs);
-       int             (*addr_needs_map)(struct device *dev, dma_addr_t addr,
-                               size_t size);
-#ifdef CONFIG_PPC_NEED_DMA_SYNC_OPS
-       void            (*sync_single_range_for_cpu)(struct device *hwdev,
-                               dma_addr_t dma_handle, unsigned long offset,
-                               size_t size,
-                               enum dma_data_direction direction);
-       void            (*sync_single_range_for_device)(struct device *hwdev,
-                               dma_addr_t dma_handle, unsigned long offset,
-                               size_t size,
-                               enum dma_data_direction direction);
-       void            (*sync_sg_for_cpu)(struct device *hwdev,
-                               struct scatterlist *sg, int nelems,
-                               enum dma_data_direction direction);
-       void            (*sync_sg_for_device)(struct device *hwdev,
-                               struct scatterlist *sg, int nelems,
-                               enum dma_data_direction direction);
-#endif
-};
-
 /*
  * Available generic sets of operations
  */
 #ifdef CONFIG_PPC64
-extern struct dma_mapping_ops dma_iommu_ops;
+extern struct dma_map_ops dma_iommu_ops;
 #endif
-extern struct dma_mapping_ops dma_direct_ops;
+extern struct dma_map_ops dma_direct_ops;
 
-static inline struct dma_mapping_ops *get_dma_ops(struct device *dev)
+static inline struct dma_map_ops *get_dma_ops(struct device *dev)
 {
        /* We don't handle the NULL dev case for ISA for now. We could
         * do it via an out of line call but it is not needed for now. The
@@ -128,14 +85,19 @@ static inline struct dma_mapping_ops *get_dma_ops(struct device *dev)
        return dev->archdata.dma_ops;
 }
 
-static inline void set_dma_ops(struct device *dev, struct dma_mapping_ops *ops)
+static inline void set_dma_ops(struct device *dev, struct dma_map_ops *ops)
 {
        dev->archdata.dma_ops = ops;
 }
 
+/* this will be removed soon */
+#define flush_write_buffers()
+
+#include <asm-generic/dma-mapping-common.h>
+
 static inline int dma_supported(struct device *dev, u64 mask)
 {
-       struct dma_mapping_ops *dma_ops = get_dma_ops(dev);
+       struct dma_map_ops *dma_ops = get_dma_ops(dev);
 
        if (unlikely(dma_ops == NULL))
                return 0;
@@ -149,7 +111,7 @@ static inline int dma_supported(struct device *dev, u64 mask)
 
 static inline int dma_set_mask(struct device *dev, u64 dma_mask)
 {
-       struct dma_mapping_ops *dma_ops = get_dma_ops(dev);
+       struct dma_map_ops *dma_ops = get_dma_ops(dev);
 
        if (unlikely(dma_ops == NULL))
                return -EIO;
@@ -161,262 +123,40 @@ static inline int dma_set_mask(struct device *dev, u64 dma_mask)
        return 0;
 }
 
-/*
- * map_/unmap_single actually call through to map/unmap_page now that all the
- * dma_mapping_ops have been converted over. We just have to get the page and
- * offset to pass through to map_page
- */
-static inline dma_addr_t dma_map_single_attrs(struct device *dev,
-                                             void *cpu_addr,
-                                             size_t size,
-                                             enum dma_data_direction direction,
-                                             struct dma_attrs *attrs)
-{
-       struct dma_mapping_ops *dma_ops = get_dma_ops(dev);
-
-       BUG_ON(!dma_ops);
-
-       return dma_ops->map_page(dev, virt_to_page(cpu_addr),
-                                (unsigned long)cpu_addr % PAGE_SIZE, size,
-                                direction, attrs);
-}
-
-static inline void dma_unmap_single_attrs(struct device *dev,
-                                         dma_addr_t dma_addr,
-                                         size_t size,
-                                         enum dma_data_direction direction,
-                                         struct dma_attrs *attrs)
-{
-       struct dma_mapping_ops *dma_ops = get_dma_ops(dev);
-
-       BUG_ON(!dma_ops);
-
-       dma_ops->unmap_page(dev, dma_addr, size, direction, attrs);
-}
-
-static inline dma_addr_t dma_map_page_attrs(struct device *dev,
-                                           struct page *page,
-                                           unsigned long offset, size_t size,
-                                           enum dma_data_direction direction,
-                                           struct dma_attrs *attrs)
-{
-       struct dma_mapping_ops *dma_ops = get_dma_ops(dev);
-
-       BUG_ON(!dma_ops);
-
-       return dma_ops->map_page(dev, page, offset, size, direction, attrs);
-}
-
-static inline void dma_unmap_page_attrs(struct device *dev,
-                                       dma_addr_t dma_address,
-                                       size_t size,
-                                       enum dma_data_direction direction,
-                                       struct dma_attrs *attrs)
-{
-       struct dma_mapping_ops *dma_ops = get_dma_ops(dev);
-
-       BUG_ON(!dma_ops);
-
-       dma_ops->unmap_page(dev, dma_address, size, direction, attrs);
-}
-
-static inline int dma_map_sg_attrs(struct device *dev, struct scatterlist *sg,
-                                  int nents, enum dma_data_direction direction,
-                                  struct dma_attrs *attrs)
-{
-       struct dma_mapping_ops *dma_ops = get_dma_ops(dev);
-
-       BUG_ON(!dma_ops);
-       return dma_ops->map_sg(dev, sg, nents, direction, attrs);
-}
-
-static inline void dma_unmap_sg_attrs(struct device *dev,
-                                     struct scatterlist *sg,
-                                     int nhwentries,
-                                     enum dma_data_direction direction,
-                                     struct dma_attrs *attrs)
-{
-       struct dma_mapping_ops *dma_ops = get_dma_ops(dev);
-
-       BUG_ON(!dma_ops);
-       dma_ops->unmap_sg(dev, sg, nhwentries, direction, attrs);
-}
-
 static inline void *dma_alloc_coherent(struct device *dev, size_t size,
                                       dma_addr_t *dma_handle, gfp_t flag)
 {
-       struct dma_mapping_ops *dma_ops = get_dma_ops(dev);
-
-       BUG_ON(!dma_ops);
-       return dma_ops->alloc_coherent(dev, size, dma_handle, flag);
-}
-
-static inline void dma_free_coherent(struct device *dev, size_t size,
-                                    void *cpu_addr, dma_addr_t dma_handle)
-{
-       struct dma_mapping_ops *dma_ops = get_dma_ops(dev);
-
-       BUG_ON(!dma_ops);
-       dma_ops->free_coherent(dev, size, cpu_addr, dma_handle);
-}
-
-static inline dma_addr_t dma_map_single(struct device *dev, void *cpu_addr,
-                                       size_t size,
-                                       enum dma_data_direction direction)
-{
-       return dma_map_single_attrs(dev, cpu_addr, size, direction, NULL);
-}
-
-static inline void dma_unmap_single(struct device *dev, dma_addr_t dma_addr,
-                                   size_t size,
-                                   enum dma_data_direction direction)
-{
-       dma_unmap_single_attrs(dev, dma_addr, size, direction, NULL);
-}
-
-static inline dma_addr_t dma_map_page(struct device *dev, struct page *page,
-                                     unsigned long offset, size_t size,
-                                     enum dma_data_direction direction)
-{
-       return dma_map_page_attrs(dev, page, offset, size, direction, NULL);
-}
-
-static inline void dma_unmap_page(struct device *dev, dma_addr_t dma_address,
-                                 size_t size,
-                                 enum dma_data_direction direction)
-{
-       dma_unmap_page_attrs(dev, dma_address, size, direction, NULL);
-}
-
-static inline int dma_map_sg(struct device *dev, struct scatterlist *sg,
-                            int nents, enum dma_data_direction direction)
-{
-       return dma_map_sg_attrs(dev, sg, nents, direction, NULL);
-}
-
-static inline void dma_unmap_sg(struct device *dev, struct scatterlist *sg,
-                               int nhwentries,
-                               enum dma_data_direction direction)
-{
-       dma_unmap_sg_attrs(dev, sg, nhwentries, direction, NULL);
-}
-
-#ifdef CONFIG_PPC_NEED_DMA_SYNC_OPS
-static inline void dma_sync_single_for_cpu(struct device *dev,
-               dma_addr_t dma_handle, size_t size,
-               enum dma_data_direction direction)
-{
-       struct dma_mapping_ops *dma_ops = get_dma_ops(dev);
-
-       BUG_ON(!dma_ops);
-
-       if (dma_ops->sync_single_range_for_cpu)
-               dma_ops->sync_single_range_for_cpu(dev, dma_handle, 0,
-                                          size, direction);
-}
-
-static inline void dma_sync_single_for_device(struct device *dev,
-               dma_addr_t dma_handle, size_t size,
-               enum dma_data_direction direction)
-{
-       struct dma_mapping_ops *dma_ops = get_dma_ops(dev);
-
-       BUG_ON(!dma_ops);
-
-       if (dma_ops->sync_single_range_for_device)
-               dma_ops->sync_single_range_for_device(dev, dma_handle,
-                                             0, size, direction);
-}
-
-static inline void dma_sync_sg_for_cpu(struct device *dev,
-               struct scatterlist *sgl, int nents,
-               enum dma_data_direction direction)
-{
-       struct dma_mapping_ops *dma_ops = get_dma_ops(dev);
+       struct dma_map_ops *dma_ops = get_dma_ops(dev);
+       void *cpu_addr;
 
        BUG_ON(!dma_ops);
 
-       if (dma_ops->sync_sg_for_cpu)
-               dma_ops->sync_sg_for_cpu(dev, sgl, nents, direction);
-}
-
-static inline void dma_sync_sg_for_device(struct device *dev,
-               struct scatterlist *sgl, int nents,
-               enum dma_data_direction direction)
-{
-       struct dma_mapping_ops *dma_ops = get_dma_ops(dev);
-
-       BUG_ON(!dma_ops);
-
-       if (dma_ops->sync_sg_for_device)
-               dma_ops->sync_sg_for_device(dev, sgl, nents, direction);
-}
-
-static inline void dma_sync_single_range_for_cpu(struct device *dev,
-               dma_addr_t dma_handle, unsigned long offset, size_t size,
-               enum dma_data_direction direction)
-{
-       struct dma_mapping_ops *dma_ops = get_dma_ops(dev);
+       cpu_addr = dma_ops->alloc_coherent(dev, size, dma_handle, flag);
 
-       BUG_ON(!dma_ops);
+       debug_dma_alloc_coherent(dev, size, *dma_handle, cpu_addr);
 
-       if (dma_ops->sync_single_range_for_cpu)
-               dma_ops->sync_single_range_for_cpu(dev, dma_handle,
-                                          offset, size, direction);
+       return cpu_addr;
 }
 
-static inline void dma_sync_single_range_for_device(struct device *dev,
-               dma_addr_t dma_handle, unsigned long offset, size_t size,
-               enum dma_data_direction direction)
+static inline void dma_free_coherent(struct device *dev, size_t size,
+                                    void *cpu_addr, dma_addr_t dma_handle)
 {
-       struct dma_mapping_ops *dma_ops = get_dma_ops(dev);
+       struct dma_map_ops *dma_ops = get_dma_ops(dev);
 
        BUG_ON(!dma_ops);
 
-       if (dma_ops->sync_single_range_for_device)
-               dma_ops->sync_single_range_for_device(dev, dma_handle, offset,
-                                             size, direction);
-}
-#else /* CONFIG_PPC_NEED_DMA_SYNC_OPS */
-static inline void dma_sync_single_for_cpu(struct device *dev,
-               dma_addr_t dma_handle, size_t size,
-               enum dma_data_direction direction)
-{
-}
-
-static inline void dma_sync_single_for_device(struct device *dev,
-               dma_addr_t dma_handle, size_t size,
-               enum dma_data_direction direction)
-{
-}
-
-static inline void dma_sync_sg_for_cpu(struct device *dev,
-               struct scatterlist *sgl, int nents,
-               enum dma_data_direction direction)
-{
-}
+       debug_dma_free_coherent(dev, size, cpu_addr, dma_handle);
 
-static inline void dma_sync_sg_for_device(struct device *dev,
-               struct scatterlist *sgl, int nents,
-               enum dma_data_direction direction)
-{
+       dma_ops->free_coherent(dev, size, cpu_addr, dma_handle);
 }
 
-static inline void dma_sync_single_range_for_cpu(struct device *dev,
-               dma_addr_t dma_handle, unsigned long offset, size_t size,
-               enum dma_data_direction direction)
+static inline int dma_mapping_error(struct device *dev, dma_addr_t dma_addr)
 {
-}
+       struct dma_map_ops *dma_ops = get_dma_ops(dev);
 
-static inline void dma_sync_single_range_for_device(struct device *dev,
-               dma_addr_t dma_handle, unsigned long offset, size_t size,
-               enum dma_data_direction direction)
-{
-}
-#endif
+       if (dma_ops->mapping_error)
+               return dma_ops->mapping_error(dev, dma_addr);
 
-static inline int dma_mapping_error(struct device *dev, dma_addr_t dma_addr)
-{
 #ifdef CONFIG_PPC64
        return (dma_addr == DMA_ERROR_CODE);
 #else
@@ -426,10 +166,12 @@ static inline int dma_mapping_error(struct device *dev, dma_addr_t dma_addr)
 
 static inline bool dma_capable(struct device *dev, dma_addr_t addr, size_t size)
 {
-       struct dma_mapping_ops *ops = get_dma_ops(dev);
+#ifdef CONFIG_SWIOTLB
+       struct dev_archdata *sd = &dev->archdata;
 
-       if (ops->addr_needs_map && ops->addr_needs_map(dev, addr, size))
+       if (sd->max_direct_dma_addr && addr + size > sd->max_direct_dma_addr)
                return 0;
+#endif
 
        if (!dev->dma_mask)
                return 0;
diff --git a/arch/powerpc/include/asm/exception-64e.h b/arch/powerpc/include/asm/exception-64e.h
new file mode 100644 (file)
index 0000000..6d53f31
--- /dev/null
@@ -0,0 +1,205 @@
+/*
+ *  Definitions for use by exception code on Book3-E
+ *
+ *  Copyright (C) 2008 Ben. Herrenschmidt (benh@kernel.crashing.org), IBM Corp.
+ *
+ *  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.
+ */
+#ifndef _ASM_POWERPC_EXCEPTION_64E_H
+#define _ASM_POWERPC_EXCEPTION_64E_H
+
+/*
+ * SPRGs usage an other considerations...
+ *
+ * Since TLB miss and other standard exceptions can be interrupted by
+ * critical exceptions which can themselves be interrupted by machine
+ * checks, and since the two later can themselves cause a TLB miss when
+ * hitting the linear mapping for the kernel stacks, we need to be a bit
+ * creative on how we use SPRGs.
+ *
+ * The base idea is that we have one SRPG reserved for critical and one
+ * for machine check interrupts. Those are used to save a GPR that can
+ * then be used to get the PACA, and store as much context as we need
+ * to save in there. That includes saving the SPRGs used by the TLB miss
+ * handler for linear mapping misses and the associated SRR0/1 due to
+ * the above re-entrancy issue.
+ *
+ * So here's the current usage pattern. It's done regardless of which
+ * SPRGs are user-readable though, thus we might have to change some of
+ * this later. In order to do that more easily, we use special constants
+ * for naming them
+ *
+ * WARNING: Some of these SPRGs are user readable. We need to do something
+ * about it as some point by making sure they can't be used to leak kernel
+ * critical data
+ */
+
+
+/* We are out of SPRGs so we save some things in the PACA. The normal
+ * exception frame is smaller than the CRIT or MC one though
+ */
+#define EX_R1          (0 * 8)
+#define EX_CR          (1 * 8)
+#define EX_R10         (2 * 8)
+#define EX_R11         (3 * 8)
+#define EX_R14         (4 * 8)
+#define EX_R15         (5 * 8)
+
+/* The TLB miss exception uses different slots */
+
+#define EX_TLB_R10     ( 0 * 8)
+#define EX_TLB_R11     ( 1 * 8)
+#define EX_TLB_R12     ( 2 * 8)
+#define EX_TLB_R13     ( 3 * 8)
+#define EX_TLB_R14     ( 4 * 8)
+#define EX_TLB_R15     ( 5 * 8)
+#define EX_TLB_R16     ( 6 * 8)
+#define EX_TLB_CR      ( 7 * 8)
+#define EX_TLB_DEAR    ( 8 * 8) /* Level 0 and 2 only */
+#define EX_TLB_ESR     ( 9 * 8) /* Level 0 and 2 only */
+#define EX_TLB_SRR0    (10 * 8)
+#define EX_TLB_SRR1    (11 * 8)
+#define EX_TLB_MMUCR0  (12 * 8) /* Level 0 */
+#define EX_TLB_MAS1    (12 * 8) /* Level 0 */
+#define EX_TLB_MAS2    (13 * 8) /* Level 0 */
+#ifdef CONFIG_BOOK3E_MMU_TLB_STATS
+#define EX_TLB_R8      (14 * 8)
+#define EX_TLB_R9      (15 * 8)
+#define EX_TLB_LR      (16 * 8)
+#define EX_TLB_SIZE    (17 * 8)
+#else
+#define EX_TLB_SIZE    (14 * 8)
+#endif
+
+#define        START_EXCEPTION(label)                                          \
+       .globl exc_##label##_book3e;                                    \
+exc_##label##_book3e:
+
+/* TLB miss exception prolog
+ *
+ * This prolog handles re-entrancy (up to 3 levels supported in the PACA
+ * though we currently don't test for overflow). It provides you with a
+ * re-entrancy safe working space of r10...r16 and CR with r12 being used
+ * as the exception area pointer in the PACA for that level of re-entrancy
+ * and r13 containing the PACA pointer.
+ *
+ * SRR0 and SRR1 are saved, but DEAR and ESR are not, since they don't apply
+ * as-is for instruction exceptions. It's up to the actual exception code
+ * to save them as well if required.
+ */
+#define TLB_MISS_PROLOG                                                            \
+       mtspr   SPRN_SPRG_TLB_SCRATCH,r12;                                  \
+       mfspr   r12,SPRN_SPRG_TLB_EXFRAME;                                  \
+       std     r10,EX_TLB_R10(r12);                                        \
+       mfcr    r10;                                                        \
+       std     r11,EX_TLB_R11(r12);                                        \
+       mfspr   r11,SPRN_SPRG_TLB_SCRATCH;                                  \
+       std     r13,EX_TLB_R13(r12);                                        \
+       mfspr   r13,SPRN_SPRG_PACA;                                         \
+       std     r14,EX_TLB_R14(r12);                                        \
+       addi    r14,r12,EX_TLB_SIZE;                                        \
+       std     r15,EX_TLB_R15(r12);                                        \
+       mfspr   r15,SPRN_SRR1;                                              \
+       std     r16,EX_TLB_R16(r12);                                        \
+       mfspr   r16,SPRN_SRR0;                                              \
+       std     r10,EX_TLB_CR(r12);                                         \
+       std     r11,EX_TLB_R12(r12);                                        \
+       mtspr   SPRN_SPRG_TLB_EXFRAME,r14;                                  \
+       std     r15,EX_TLB_SRR1(r12);                                       \
+       std     r16,EX_TLB_SRR0(r12);                                       \
+       TLB_MISS_PROLOG_STATS
+
+/* And these are the matching epilogs that restores things
+ *
+ * There are 3 epilogs:
+ *
+ * - SUCCESS       : Unwinds one level
+ * - ERROR         : restore from level 0 and reset
+ * - ERROR_SPECIAL : restore from current level and reset
+ *
+ * Normal errors use ERROR, that is, they restore the initial fault context
+ * and trigger a fault. However, there is a special case for linear mapping
+ * errors. Those should basically never happen, but if they do happen, we
+ * want the error to point out the context that did that linear mapping
+ * fault, not the initial level 0 (basically, we got a bogus PGF or something
+ * like that). For userland errors on the linear mapping, there is no
+ * difference since those are always level 0 anyway
+ */
+
+#define TLB_MISS_RESTORE(freg)                                             \
+       ld      r14,EX_TLB_CR(r12);                                         \
+       ld      r10,EX_TLB_R10(r12);                                        \
+       ld      r15,EX_TLB_SRR0(r12);                                       \
+       ld      r16,EX_TLB_SRR1(r12);                                       \
+       mtspr   SPRN_SPRG_TLB_EXFRAME,freg;                                 \
+       ld      r11,EX_TLB_R11(r12);                                        \
+       mtcr    r14;                                                        \
+       ld      r13,EX_TLB_R13(r12);                                        \
+       ld      r14,EX_TLB_R14(r12);                                        \
+       mtspr   SPRN_SRR0,r15;                                              \
+       ld      r15,EX_TLB_R15(r12);                                        \
+       mtspr   SPRN_SRR1,r16;                                              \
+       TLB_MISS_RESTORE_STATS                                              \
+       ld      r16,EX_TLB_R16(r12);                                        \
+       ld      r12,EX_TLB_R12(r12);                                        \
+
+#define TLB_MISS_EPILOG_SUCCESS                                                    \
+       TLB_MISS_RESTORE(r12)
+
+#define TLB_MISS_EPILOG_ERROR                                              \
+       addi    r12,r13,PACA_EXTLB;                                         \
+       TLB_MISS_RESTORE(r12)
+
+#define TLB_MISS_EPILOG_ERROR_SPECIAL                                      \
+       addi    r11,r13,PACA_EXTLB;                                         \
+       TLB_MISS_RESTORE(r11)
+
+#ifdef CONFIG_BOOK3E_MMU_TLB_STATS
+#define TLB_MISS_PROLOG_STATS                                              \
+       mflr    r10;                                                        \
+       std     r8,EX_TLB_R8(r12);                                          \
+       std     r9,EX_TLB_R9(r12);                                          \
+       std     r10,EX_TLB_LR(r12);
+#define TLB_MISS_RESTORE_STATS                                             \
+       ld      r16,EX_TLB_LR(r12);                                         \
+       ld      r9,EX_TLB_R9(r12);                                          \
+       ld      r8,EX_TLB_R8(r12);                                          \
+       mtlr    r16;
+#define TLB_MISS_STATS_D(name)                                             \
+       addi    r9,r13,MMSTAT_DSTATS+name;                                  \
+       bl      .tlb_stat_inc;
+#define TLB_MISS_STATS_I(name)                                             \
+       addi    r9,r13,MMSTAT_ISTATS+name;                                  \
+       bl      .tlb_stat_inc;
+#define TLB_MISS_STATS_X(name)                                             \
+       ld      r8,PACA_EXTLB+EX_TLB_ESR(r13);                              \
+       cmpdi   cr2,r8,-1;                                                  \
+       beq     cr2,61f;                                                    \
+       addi    r9,r13,MMSTAT_DSTATS+name;                                  \
+       b       62f;                                                        \
+61:    addi    r9,r13,MMSTAT_ISTATS+name;                                  \
+62:    bl      .tlb_stat_inc;
+#define TLB_MISS_STATS_SAVE_INFO                                           \
+       std     r14,EX_TLB_ESR(r12);    /* save ESR */                      \
+
+
+#else
+#define TLB_MISS_PROLOG_STATS
+#define TLB_MISS_RESTORE_STATS
+#define TLB_MISS_STATS_D(name)
+#define TLB_MISS_STATS_I(name)
+#define TLB_MISS_STATS_X(name)
+#define TLB_MISS_STATS_Y(name)
+#define TLB_MISS_STATS_SAVE_INFO
+#endif
+
+#define SET_IVOR(vector_number, vector_offset) \
+       li      r3,vector_offset@l;             \
+       ori     r3,r3,interrupt_base_book3e@l;  \
+       mtspr   SPRN_IVOR##vector_number,r3;
+
+#endif /* _ASM_POWERPC_EXCEPTION_64E_H */
+
diff --git a/arch/powerpc/include/asm/exception-64s.h b/arch/powerpc/include/asm/exception-64s.h
new file mode 100644 (file)
index 0000000..a98653b
--- /dev/null
@@ -0,0 +1,282 @@
+#ifndef _ASM_POWERPC_EXCEPTION_H
+#define _ASM_POWERPC_EXCEPTION_H
+/*
+ * Extracted from head_64.S
+ *
+ *  PowerPC version
+ *    Copyright (C) 1995-1996 Gary Thomas (gdt@linuxppc.org)
+ *
+ *  Rewritten by Cort Dougan (cort@cs.nmt.edu) for PReP
+ *    Copyright (C) 1996 Cort Dougan <cort@cs.nmt.edu>
+ *  Adapted for Power Macintosh by Paul Mackerras.
+ *  Low-level exception handlers and MMU support
+ *  rewritten by Paul Mackerras.
+ *    Copyright (C) 1996 Paul Mackerras.
+ *
+ *  Adapted for 64bit PowerPC by Dave Engebretsen, Peter Bergner, and
+ *    Mike Corrigan {engebret|bergner|mikejc}@us.ibm.com
+ *
+ *  This file contains the low-level support and setup for the
+ *  PowerPC-64 platform, including trap and interrupt dispatch.
+ *
+ *  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.
+ */
+/*
+ * The following macros define the code that appears as
+ * the prologue to each of the exception handlers.  They
+ * are split into two parts to allow a single kernel binary
+ * to be used for pSeries and iSeries.
+ *
+ * We make as much of the exception code common between native
+ * exception handlers (including pSeries LPAR) and iSeries LPAR
+ * implementations as possible.
+ */
+
+#define EX_R9          0
+#define EX_R10         8
+#define EX_R11         16
+#define EX_R12         24
+#define EX_R13         32
+#define EX_SRR0                40
+#define EX_DAR         48
+#define EX_DSISR       56
+#define EX_CCR         60
+#define EX_R3          64
+#define EX_LR          72
+
+/*
+ * We're short on space and time in the exception prolog, so we can't
+ * use the normal SET_REG_IMMEDIATE macro. Normally we just need the
+ * low halfword of the address, but for Kdump we need the whole low
+ * word.
+ */
+#define LOAD_HANDLER(reg, label)                                       \
+       addi    reg,reg,(label)-_stext; /* virt addr of handler ... */
+
+#define EXCEPTION_PROLOG_1(area)                               \
+       mfspr   r13,SPRN_SPRG_PACA;     /* get paca address into r13 */ \
+       std     r9,area+EX_R9(r13);     /* save r9 - r12 */             \
+       std     r10,area+EX_R10(r13);                                   \
+       std     r11,area+EX_R11(r13);                                   \
+       std     r12,area+EX_R12(r13);                                   \
+       mfspr   r9,SPRN_SPRG_SCRATCH0;                                  \
+       std     r9,area+EX_R13(r13);                                    \
+       mfcr    r9
+
+#define EXCEPTION_PROLOG_PSERIES_1(label)                              \
+       ld      r12,PACAKBASE(r13);     /* get high part of &label */   \
+       ld      r10,PACAKMSR(r13);      /* get MSR value for kernel */  \
+       mfspr   r11,SPRN_SRR0;          /* save SRR0 */                 \
+       LOAD_HANDLER(r12,label)                                         \
+       mtspr   SPRN_SRR0,r12;                                          \
+       mfspr   r12,SPRN_SRR1;          /* and SRR1 */                  \
+       mtspr   SPRN_SRR1,r10;                                          \
+       rfid;                                                           \
+       b       .       /* prevent speculative execution */
+
+#define EXCEPTION_PROLOG_PSERIES(area, label)                          \
+       EXCEPTION_PROLOG_1(area);                                       \
+       EXCEPTION_PROLOG_PSERIES_1(label);
+
+/*
+ * The common exception prolog is used for all except a few exceptions
+ * such as a segment miss on a kernel address.  We have to be prepared
+ * to take another exception from the point where we first touch the
+ * kernel stack onwards.
+ *
+ * On entry r13 points to the paca, r9-r13 are saved in the paca,
+ * r9 contains the saved CR, r11 and r12 contain the saved SRR0 and
+ * SRR1, and relocation is on.
+ */
+#define EXCEPTION_PROLOG_COMMON(n, area)                                  \
+       andi.   r10,r12,MSR_PR;         /* See if coming from user      */ \
+       mr      r10,r1;                 /* Save r1                      */ \
+       subi    r1,r1,INT_FRAME_SIZE;   /* alloc frame on kernel stack  */ \
+       beq-    1f;                                                        \
+       ld      r1,PACAKSAVE(r13);      /* kernel stack to use          */ \
+1:     cmpdi   cr1,r1,0;               /* check if r1 is in userspace  */ \
+       bge-    cr1,2f;                 /* abort if it is               */ \
+       b       3f;                                                        \
+2:     li      r1,(n);                 /* will be reloaded later       */ \
+       sth     r1,PACA_TRAP_SAVE(r13);                                    \
+       b       bad_stack;                                                 \
+3:     std     r9,_CCR(r1);            /* save CR in stackframe        */ \
+       std     r11,_NIP(r1);           /* save SRR0 in stackframe      */ \
+       std     r12,_MSR(r1);           /* save SRR1 in stackframe      */ \
+       std     r10,0(r1);              /* make stack chain pointer     */ \
+       std     r0,GPR0(r1);            /* save r0 in stackframe        */ \
+       std     r10,GPR1(r1);           /* save r1 in stackframe        */ \
+       ACCOUNT_CPU_USER_ENTRY(r9, r10);                                   \
+       std     r2,GPR2(r1);            /* save r2 in stackframe        */ \
+       SAVE_4GPRS(3, r1);              /* save r3 - r6 in stackframe   */ \
+       SAVE_2GPRS(7, r1);              /* save r7, r8 in stackframe    */ \
+       ld      r9,area+EX_R9(r13);     /* move r9, r10 to stackframe   */ \
+       ld      r10,area+EX_R10(r13);                                      \
+       std     r9,GPR9(r1);                                               \
+       std     r10,GPR10(r1);                                             \
+       ld      r9,area+EX_R11(r13);    /* move r11 - r13 to stackframe */ \
+       ld      r10,area+EX_R12(r13);                                      \
+       ld      r11,area+EX_R13(r13);                                      \
+       std     r9,GPR11(r1);                                              \
+       std     r10,GPR12(r1);                                             \
+       std     r11,GPR13(r1);                                             \
+       ld      r2,PACATOC(r13);        /* get kernel TOC into r2       */ \
+       mflr    r9;                     /* save LR in stackframe        */ \
+       std     r9,_LINK(r1);                                              \
+       mfctr   r10;                    /* save CTR in stackframe       */ \
+       std     r10,_CTR(r1);                                              \
+       lbz     r10,PACASOFTIRQEN(r13);                            \
+       mfspr   r11,SPRN_XER;           /* save XER in stackframe       */ \
+       std     r10,SOFTE(r1);                                             \
+       std     r11,_XER(r1);                                              \
+       li      r9,(n)+1;                                                  \
+       std     r9,_TRAP(r1);           /* set trap number              */ \
+       li      r10,0;                                                     \
+       ld      r11,exception_marker@toc(r2);                              \
+       std     r10,RESULT(r1);         /* clear regs->result           */ \
+       std     r11,STACK_FRAME_OVERHEAD-16(r1); /* mark the frame      */
+
+/*
+ * Exception vectors.
+ */
+#define STD_EXCEPTION_PSERIES(n, label)                        \
+       . = n;                                          \
+       .globl label##_pSeries;                         \
+label##_pSeries:                                       \
+       HMT_MEDIUM;                                     \
+       mtspr   SPRN_SPRG_SCRATCH0,r13;         /* save r13 */  \
+       EXCEPTION_PROLOG_PSERIES(PACA_EXGEN, label##_common)
+
+#define HSTD_EXCEPTION_PSERIES(n, label)               \
+       . = n;                                          \
+       .globl label##_pSeries;                         \
+label##_pSeries:                                       \
+       HMT_MEDIUM;                                     \
+       mtspr   SPRN_SPRG_SCRATCH0,r20; /* save r20 */  \
+       mfspr   r20,SPRN_HSRR0;         /* copy HSRR0 to SRR0 */ \
+       mtspr   SPRN_SRR0,r20;                          \
+       mfspr   r20,SPRN_HSRR1;         /* copy HSRR0 to SRR0 */ \
+       mtspr   SPRN_SRR1,r20;                          \
+       mfspr   r20,SPRN_SPRG_SCRATCH0; /* restore r20 */ \
+       mtspr   SPRN_SPRG_SCRATCH0,r13;         /* save r13 */  \
+       EXCEPTION_PROLOG_PSERIES(PACA_EXGEN, label##_common)
+
+
+#define MASKABLE_EXCEPTION_PSERIES(n, label)                           \
+       . = n;                                                          \
+       .globl label##_pSeries;                                         \
+label##_pSeries:                                                       \
+       HMT_MEDIUM;                                                     \
+       mtspr   SPRN_SPRG_SCRATCH0,r13; /* save r13 */                  \
+       mfspr   r13,SPRN_SPRG_PACA;     /* get paca address into r13 */ \
+       std     r9,PACA_EXGEN+EX_R9(r13);       /* save r9, r10 */      \
+       std     r10,PACA_EXGEN+EX_R10(r13);                             \
+       lbz     r10,PACASOFTIRQEN(r13);                                 \
+       mfcr    r9;                                                     \
+       cmpwi   r10,0;                                                  \
+       beq     masked_interrupt;                                       \
+       mfspr   r10,SPRN_SPRG_SCRATCH0;                                 \
+       std     r10,PACA_EXGEN+EX_R13(r13);                             \
+       std     r11,PACA_EXGEN+EX_R11(r13);                             \
+       std     r12,PACA_EXGEN+EX_R12(r13);                             \
+       ld      r12,PACAKBASE(r13);     /* get high part of &label */   \
+       ld      r10,PACAKMSR(r13);      /* get MSR value for kernel */  \
+       mfspr   r11,SPRN_SRR0;          /* save SRR0 */                 \
+       LOAD_HANDLER(r12,label##_common)                                \
+       mtspr   SPRN_SRR0,r12;                                          \
+       mfspr   r12,SPRN_SRR1;          /* and SRR1 */                  \
+       mtspr   SPRN_SRR1,r10;                                          \
+       rfid;                                                           \
+       b       .       /* prevent speculative execution */
+
+#ifdef CONFIG_PPC_ISERIES
+#define DISABLE_INTS                           \
+       li      r11,0;                          \
+       stb     r11,PACASOFTIRQEN(r13);         \
+BEGIN_FW_FTR_SECTION;                          \
+       stb     r11,PACAHARDIRQEN(r13);         \
+END_FW_FTR_SECTION_IFCLR(FW_FEATURE_ISERIES);  \
+       TRACE_DISABLE_INTS;                     \
+BEGIN_FW_FTR_SECTION;                          \
+       mfmsr   r10;                            \
+       ori     r10,r10,MSR_EE;                 \
+       mtmsrd  r10,1;                          \
+END_FW_FTR_SECTION_IFSET(FW_FEATURE_ISERIES)
+#else
+#define DISABLE_INTS                           \
+       li      r11,0;                          \
+       stb     r11,PACASOFTIRQEN(r13);         \
+       stb     r11,PACAHARDIRQEN(r13);         \
+       TRACE_DISABLE_INTS
+#endif /* CONFIG_PPC_ISERIES */
+
+#define ENABLE_INTS                            \
+       ld      r12,_MSR(r1);                   \
+       mfmsr   r11;                            \
+       rlwimi  r11,r12,0,MSR_EE;               \
+       mtmsrd  r11,1
+
+#define STD_EXCEPTION_COMMON(trap, label, hdlr)                \
+       .align  7;                                      \
+       .globl label##_common;                          \
+label##_common:                                                \
+       EXCEPTION_PROLOG_COMMON(trap, PACA_EXGEN);      \
+       DISABLE_INTS;                                   \
+       bl      .save_nvgprs;                           \
+       addi    r3,r1,STACK_FRAME_OVERHEAD;             \
+       bl      hdlr;                                   \
+       b       .ret_from_except
+
+/*
+ * Like STD_EXCEPTION_COMMON, but for exceptions that can occur
+ * in the idle task and therefore need the special idle handling.
+ */
+#define STD_EXCEPTION_COMMON_IDLE(trap, label, hdlr)   \
+       .align  7;                                      \
+       .globl label##_common;                          \
+label##_common:                                                \
+       EXCEPTION_PROLOG_COMMON(trap, PACA_EXGEN);      \
+       FINISH_NAP;                                     \
+       DISABLE_INTS;                                   \
+       bl      .save_nvgprs;                           \
+       addi    r3,r1,STACK_FRAME_OVERHEAD;             \
+       bl      hdlr;                                   \
+       b       .ret_from_except
+
+#define STD_EXCEPTION_COMMON_LITE(trap, label, hdlr)   \
+       .align  7;                                      \
+       .globl label##_common;                          \
+label##_common:                                                \
+       EXCEPTION_PROLOG_COMMON(trap, PACA_EXGEN);      \
+       FINISH_NAP;                                     \
+       DISABLE_INTS;                                   \
+BEGIN_FTR_SECTION                                      \
+       bl      .ppc64_runlatch_on;                     \
+END_FTR_SECTION_IFSET(CPU_FTR_CTRL)                    \
+       addi    r3,r1,STACK_FRAME_OVERHEAD;             \
+       bl      hdlr;                                   \
+       b       .ret_from_except_lite
+
+/*
+ * When the idle code in power4_idle puts the CPU into NAP mode,
+ * it has to do so in a loop, and relies on the external interrupt
+ * and decrementer interrupt entry code to get it out of the loop.
+ * It sets the _TLF_NAPPING bit in current_thread_info()->local_flags
+ * to signal that it is in the loop and needs help to get out.
+ */
+#ifdef CONFIG_PPC_970_NAP
+#define FINISH_NAP                             \
+BEGIN_FTR_SECTION                              \
+       clrrdi  r11,r1,THREAD_SHIFT;            \
+       ld      r9,TI_LOCAL_FLAGS(r11);         \
+       andi.   r10,r9,_TLF_NAPPING;            \
+       bnel    power4_fixup_nap;               \
+END_FTR_SECTION_IFSET(CPU_FTR_CAN_NAP)
+#else
+#define FINISH_NAP
+#endif
+
+#endif /* _ASM_POWERPC_EXCEPTION_H */
diff --git a/arch/powerpc/include/asm/exception.h b/arch/powerpc/include/asm/exception.h
deleted file mode 100644 (file)
index d3d4534..0000000
+++ /dev/null
@@ -1,279 +0,0 @@
-#ifndef _ASM_POWERPC_EXCEPTION_H
-#define _ASM_POWERPC_EXCEPTION_H
-/*
- * Extracted from head_64.S
- *
- *  PowerPC version
- *    Copyright (C) 1995-1996 Gary Thomas (gdt@linuxppc.org)
- *
- *  Rewritten by Cort Dougan (cort@cs.nmt.edu) for PReP
- *    Copyright (C) 1996 Cort Dougan <cort@cs.nmt.edu>
- *  Adapted for Power Macintosh by Paul Mackerras.
- *  Low-level exception handlers and MMU support
- *  rewritten by Paul Mackerras.
- *    Copyright (C) 1996 Paul Mackerras.
- *
- *  Adapted for 64bit PowerPC by Dave Engebretsen, Peter Bergner, and
- *    Mike Corrigan {engebret|bergner|mikejc}@us.ibm.com
- *
- *  This file contains the low-level support and setup for the
- *  PowerPC-64 platform, including trap and interrupt dispatch.
- *
- *  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.
- */
-/*
- * The following macros define the code that appears as
- * the prologue to each of the exception handlers.  They
- * are split into two parts to allow a single kernel binary
- * to be used for pSeries and iSeries.
- *
- * We make as much of the exception code common between native
- * exception handlers (including pSeries LPAR) and iSeries LPAR
- * implementations as possible.
- */
-
-#define EX_R9          0
-#define EX_R10         8
-#define EX_R11         16
-#define EX_R12         24
-#define EX_R13         32
-#define EX_SRR0                40
-#define EX_DAR         48
-#define EX_DSISR       56
-#define EX_CCR         60
-#define EX_R3          64
-#define EX_LR          72
-
-/*
- * We're short on space and time in the exception prolog, so we can't
- * use the normal SET_REG_IMMEDIATE macro. Normally we just need the
- * low halfword of the address, but for Kdump we need the whole low
- * word.
- */
-#define LOAD_HANDLER(reg, label)                                       \
-       addi    reg,reg,(label)-_stext; /* virt addr of handler ... */
-
-#define EXCEPTION_PROLOG_1(area)                               \
-       mfspr   r13,SPRN_SPRG3;         /* get paca address into r13 */ \
-       std     r9,area+EX_R9(r13);     /* save r9 - r12 */             \
-       std     r10,area+EX_R10(r13);                                   \
-       std     r11,area+EX_R11(r13);                                   \
-       std     r12,area+EX_R12(r13);                                   \
-       mfspr   r9,SPRN_SPRG1;                                          \
-       std     r9,area+EX_R13(r13);                                    \
-       mfcr    r9
-
-#define EXCEPTION_PROLOG_PSERIES(area, label)                          \
-       EXCEPTION_PROLOG_1(area);                                       \
-       ld      r12,PACAKBASE(r13);     /* get high part of &label */   \
-       ld      r10,PACAKMSR(r13);      /* get MSR value for kernel */  \
-       mfspr   r11,SPRN_SRR0;          /* save SRR0 */                 \
-       LOAD_HANDLER(r12,label)                                         \
-       mtspr   SPRN_SRR0,r12;                                          \
-       mfspr   r12,SPRN_SRR1;          /* and SRR1 */                  \
-       mtspr   SPRN_SRR1,r10;                                          \
-       rfid;                                                           \
-       b       .       /* prevent speculative execution */
-
-/*
- * The common exception prolog is used for all except a few exceptions
- * such as a segment miss on a kernel address.  We have to be prepared
- * to take another exception from the point where we first touch the
- * kernel stack onwards.
- *
- * On entry r13 points to the paca, r9-r13 are saved in the paca,
- * r9 contains the saved CR, r11 and r12 contain the saved SRR0 and
- * SRR1, and relocation is on.
- */
-#define EXCEPTION_PROLOG_COMMON(n, area)                                  \
-       andi.   r10,r12,MSR_PR;         /* See if coming from user      */ \
-       mr      r10,r1;                 /* Save r1                      */ \
-       subi    r1,r1,INT_FRAME_SIZE;   /* alloc frame on kernel stack  */ \
-       beq-    1f;                                                        \
-       ld      r1,PACAKSAVE(r13);      /* kernel stack to use          */ \
-1:     cmpdi   cr1,r1,0;               /* check if r1 is in userspace  */ \
-       bge-    cr1,2f;                 /* abort if it is               */ \
-       b       3f;                                                        \
-2:     li      r1,(n);                 /* will be reloaded later       */ \
-       sth     r1,PACA_TRAP_SAVE(r13);                                    \
-       b       bad_stack;                                                 \
-3:     std     r9,_CCR(r1);            /* save CR in stackframe        */ \
-       std     r11,_NIP(r1);           /* save SRR0 in stackframe      */ \
-       std     r12,_MSR(r1);           /* save SRR1 in stackframe      */ \
-       std     r10,0(r1);              /* make stack chain pointer     */ \
-       std     r0,GPR0(r1);            /* save r0 in stackframe        */ \
-       std     r10,GPR1(r1);           /* save r1 in stackframe        */ \
-       ACCOUNT_CPU_USER_ENTRY(r9, r10);                                   \
-       std     r2,GPR2(r1);            /* save r2 in stackframe        */ \
-       SAVE_4GPRS(3, r1);              /* save r3 - r6 in stackframe   */ \
-       SAVE_2GPRS(7, r1);              /* save r7, r8 in stackframe    */ \
-       ld      r9,area+EX_R9(r13);     /* move r9, r10 to stackframe   */ \
-       ld      r10,area+EX_R10(r13);                                      \
-       std     r9,GPR9(r1);                                               \
-       std     r10,GPR10(r1);                                             \
-       ld      r9,area+EX_R11(r13);    /* move r11 - r13 to stackframe */ \
-       ld      r10,area+EX_R12(r13);                                      \
-       ld      r11,area+EX_R13(r13);                                      \
-       std     r9,GPR11(r1);                                              \
-       std     r10,GPR12(r1);                                             \
-       std     r11,GPR13(r1);                                             \
-       ld      r2,PACATOC(r13);        /* get kernel TOC into r2       */ \
-       mflr    r9;                     /* save LR in stackframe        */ \
-       std     r9,_LINK(r1);                                              \
-       mfctr   r10;                    /* save CTR in stackframe       */ \
-       std     r10,_CTR(r1);                                              \
-       lbz     r10,PACASOFTIRQEN(r13);                            \
-       mfspr   r11,SPRN_XER;           /* save XER in stackframe       */ \
-       std     r10,SOFTE(r1);                                             \
-       std     r11,_XER(r1);                                              \
-       li      r9,(n)+1;                                                  \
-       std     r9,_TRAP(r1);           /* set trap number              */ \
-       li      r10,0;                                                     \
-       ld      r11,exception_marker@toc(r2);                              \
-       std     r10,RESULT(r1);         /* clear regs->result           */ \
-       std     r11,STACK_FRAME_OVERHEAD-16(r1); /* mark the frame      */
-
-/*
- * Exception vectors.
- */
-#define STD_EXCEPTION_PSERIES(n, label)                        \
-       . = n;                                          \
-       .globl label##_pSeries;                         \
-label##_pSeries:                                       \
-       HMT_MEDIUM;                                     \
-       mtspr   SPRN_SPRG1,r13;         /* save r13 */  \
-       EXCEPTION_PROLOG_PSERIES(PACA_EXGEN, label##_common)
-
-#define HSTD_EXCEPTION_PSERIES(n, label)               \
-       . = n;                                          \
-       .globl label##_pSeries;                         \
-label##_pSeries:                                       \
-       HMT_MEDIUM;                                     \
-       mtspr   SPRN_SPRG1,r20;         /* save r20 */  \
-       mfspr   r20,SPRN_HSRR0;         /* copy HSRR0 to SRR0 */ \
-       mtspr   SPRN_SRR0,r20;                          \
-       mfspr   r20,SPRN_HSRR1;         /* copy HSRR0 to SRR0 */ \
-       mtspr   SPRN_SRR1,r20;                          \
-       mfspr   r20,SPRN_SPRG1;         /* restore r20 */ \
-       mtspr   SPRN_SPRG1,r13;         /* save r13 */  \
-       EXCEPTION_PROLOG_PSERIES(PACA_EXGEN, label##_common)
-
-
-#define MASKABLE_EXCEPTION_PSERIES(n, label)                           \
-       . = n;                                                          \
-       .globl label##_pSeries;                                         \
-label##_pSeries:                                                       \
-       HMT_MEDIUM;                                                     \
-       mtspr   SPRN_SPRG1,r13;         /* save r13 */                  \
-       mfspr   r13,SPRN_SPRG3;         /* get paca address into r13 */ \
-       std     r9,PACA_EXGEN+EX_R9(r13);       /* save r9, r10 */      \
-       std     r10,PACA_EXGEN+EX_R10(r13);                             \
-       lbz     r10,PACASOFTIRQEN(r13);                                 \
-       mfcr    r9;                                                     \
-       cmpwi   r10,0;                                                  \
-       beq     masked_interrupt;                                       \
-       mfspr   r10,SPRN_SPRG1;                                         \
-       std     r10,PACA_EXGEN+EX_R13(r13);                             \
-       std     r11,PACA_EXGEN+EX_R11(r13);                             \
-       std     r12,PACA_EXGEN+EX_R12(r13);                             \
-       ld      r12,PACAKBASE(r13);     /* get high part of &label */   \
-       ld      r10,PACAKMSR(r13);      /* get MSR value for kernel */  \
-       mfspr   r11,SPRN_SRR0;          /* save SRR0 */                 \
-       LOAD_HANDLER(r12,label##_common)                                \
-       mtspr   SPRN_SRR0,r12;                                          \
-       mfspr   r12,SPRN_SRR1;          /* and SRR1 */                  \
-       mtspr   SPRN_SRR1,r10;                                          \
-       rfid;                                                           \
-       b       .       /* prevent speculative execution */
-
-#ifdef CONFIG_PPC_ISERIES
-#define DISABLE_INTS                           \
-       li      r11,0;                          \
-       stb     r11,PACASOFTIRQEN(r13);         \
-BEGIN_FW_FTR_SECTION;                          \
-       stb     r11,PACAHARDIRQEN(r13);         \
-END_FW_FTR_SECTION_IFCLR(FW_FEATURE_ISERIES);  \
-       TRACE_DISABLE_INTS;                     \
-BEGIN_FW_FTR_SECTION;                          \
-       mfmsr   r10;                            \
-       ori     r10,r10,MSR_EE;                 \
-       mtmsrd  r10,1;                          \
-END_FW_FTR_SECTION_IFSET(FW_FEATURE_ISERIES)
-#else
-#define DISABLE_INTS                           \
-       li      r11,0;                          \
-       stb     r11,PACASOFTIRQEN(r13);         \
-       stb     r11,PACAHARDIRQEN(r13);         \
-       TRACE_DISABLE_INTS
-#endif /* CONFIG_PPC_ISERIES */
-
-#define ENABLE_INTS                            \
-       ld      r12,_MSR(r1);                   \
-       mfmsr   r11;                            \
-       rlwimi  r11,r12,0,MSR_EE;               \
-       mtmsrd  r11,1
-
-#define STD_EXCEPTION_COMMON(trap, label, hdlr)                \
-       .align  7;                                      \
-       .globl label##_common;                          \
-label##_common:                                                \
-       EXCEPTION_PROLOG_COMMON(trap, PACA_EXGEN);      \
-       DISABLE_INTS;                                   \
-       bl      .save_nvgprs;                           \
-       addi    r3,r1,STACK_FRAME_OVERHEAD;             \
-       bl      hdlr;                                   \
-       b       .ret_from_except
-
-/*
- * Like STD_EXCEPTION_COMMON, but for exceptions that can occur
- * in the idle task and therefore need the special idle handling.
- */
-#define STD_EXCEPTION_COMMON_IDLE(trap, label, hdlr)   \
-       .align  7;                                      \
-       .globl label##_common;                          \
-label##_common:                                                \
-       EXCEPTION_PROLOG_COMMON(trap, PACA_EXGEN);      \
-       FINISH_NAP;                                     \
-       DISABLE_INTS;                                   \
-       bl      .save_nvgprs;                           \
-       addi    r3,r1,STACK_FRAME_OVERHEAD;             \
-       bl      hdlr;                                   \
-       b       .ret_from_except
-
-#define STD_EXCEPTION_COMMON_LITE(trap, label, hdlr)   \
-       .align  7;                                      \
-       .globl label##_common;                          \
-label##_common:                                                \
-       EXCEPTION_PROLOG_COMMON(trap, PACA_EXGEN);      \
-       FINISH_NAP;                                     \
-       DISABLE_INTS;                                   \
-BEGIN_FTR_SECTION                                      \
-       bl      .ppc64_runlatch_on;                     \
-END_FTR_SECTION_IFSET(CPU_FTR_CTRL)                    \
-       addi    r3,r1,STACK_FRAME_OVERHEAD;             \
-       bl      hdlr;                                   \
-       b       .ret_from_except_lite
-
-/*
- * When the idle code in power4_idle puts the CPU into NAP mode,
- * it has to do so in a loop, and relies on the external interrupt
- * and decrementer interrupt entry code to get it out of the loop.
- * It sets the _TLF_NAPPING bit in current_thread_info()->local_flags
- * to signal that it is in the loop and needs help to get out.
- */
-#ifdef CONFIG_PPC_970_NAP
-#define FINISH_NAP                             \
-BEGIN_FTR_SECTION                              \
-       clrrdi  r11,r1,THREAD_SHIFT;            \
-       ld      r9,TI_LOCAL_FLAGS(r11);         \
-       andi.   r10,r9,_TLF_NAPPING;            \
-       bnel    power4_fixup_nap;               \
-END_FTR_SECTION_IFSET(CPU_FTR_CAN_NAP)
-#else
-#define FINISH_NAP
-#endif
-
-#endif /* _ASM_POWERPC_EXCEPTION_H */
index 288e14d53b7fa2a17b4012c4b21b413a037a8521..fb3c05a0cbbf11e48551550270d354b0e0eb7dc1 100644 (file)
@@ -1,29 +1 @@
-#ifndef _ASM_POWERPC_HARDIRQ_H
-#define _ASM_POWERPC_HARDIRQ_H
-#ifdef __KERNEL__
-
-#include <asm/irq.h>
-#include <asm/bug.h>
-
-/* The __last_jiffy_stamp field is needed to ensure that no decrementer
- * interrupt is lost on SMP machines. Since on most CPUs it is in the same
- * cache line as local_irq_count, it is cheap to access and is also used on UP
- * for uniformity.
- */
-typedef struct {
-       unsigned int __softirq_pending; /* set_bit is used on this */
-       unsigned int __last_jiffy_stamp;
-} ____cacheline_aligned irq_cpustat_t;
-
-#include <linux/irq_cpustat.h> /* Standard mappings for irq_cpustat_t above */
-
-#define last_jiffy_stamp(cpu) __IRQ_STAT((cpu), __last_jiffy_stamp)
-
-static inline void ack_bad_irq(int irq)
-{
-       printk(KERN_CRIT "illegal vector %d received!\n", irq);
-       BUG();
-}
-
-#endif /* __KERNEL__ */
-#endif /* _ASM_POWERPC_HARDIRQ_H */
+#include <asm-generic/hardirq.h>
index 8b505eaaa38a173b0f86154654879ad914d35fb7..e73d554538dd0edd3fd9e4ddb536869b3e81af8b 100644 (file)
@@ -49,8 +49,13 @@ extern void iseries_handle_interrupts(void);
 #define raw_irqs_disabled()            (local_get_flags() == 0)
 #define raw_irqs_disabled_flags(flags) ((flags) == 0)
 
+#ifdef CONFIG_PPC_BOOK3E
+#define __hard_irq_enable()    __asm__ __volatile__("wrteei 1": : :"memory");
+#define __hard_irq_disable()   __asm__ __volatile__("wrteei 0": : :"memory");
+#else
 #define __hard_irq_enable()    __mtmsrd(mfmsr() | MSR_EE, 1)
 #define __hard_irq_disable()   __mtmsrd(mfmsr() & ~MSR_EE, 1)
+#endif
 
 #define  hard_irq_disable()                    \
        do {                                    \
index 7ead7c16fb7cdb563ee41f0146b16471bf700d7a..7464c0daddd1d02f5f8f66d1df9a26f92bbc7783 100644 (file)
 #define IOMMU_PAGE_MASK       (~((1 << IOMMU_PAGE_SHIFT) - 1))
 #define IOMMU_PAGE_ALIGN(addr) _ALIGN_UP(addr, IOMMU_PAGE_SIZE)
 
-/* Cell page table entries */
-#define CBE_IOPTE_PP_W         0x8000000000000000ul /* protection: write */
-#define CBE_IOPTE_PP_R         0x4000000000000000ul /* protection: read */
-#define CBE_IOPTE_M            0x2000000000000000ul /* coherency required */
-#define CBE_IOPTE_SO_R         0x1000000000000000ul /* ordering: writes */
-#define CBE_IOPTE_SO_RW                0x1800000000000000ul /* ordering: r & w */
-#define CBE_IOPTE_RPN_Mask     0x07fffffffffff000ul /* RPN */
-#define CBE_IOPTE_H            0x0000000000000800ul /* cache hint */
-#define CBE_IOPTE_IOID_Mask    0x00000000000007fful /* ioid */
-
 /* Boot time flags */
 extern int iommu_is_off;
 extern int iommu_force_on;
index 0a5137676e1b89f4f76d2532d820399c2413743c..bbcd1aaf3dfdfe79b00cc31e00850378139b1439 100644 (file)
@@ -302,7 +302,8 @@ extern void irq_free_virt(unsigned int virq, unsigned int count);
 
 /* -- OF helpers -- */
 
-/* irq_create_of_mapping - Map a hardware interrupt into linux virq space
+/**
+ * irq_create_of_mapping - Map a hardware interrupt into linux virq space
  * @controller: Device node of the interrupt controller
  * @inspec: Interrupt specifier from the device-tree
  * @intsize: Size of the interrupt specifier from the device-tree
@@ -314,8 +315,8 @@ extern void irq_free_virt(unsigned int virq, unsigned int count);
 extern unsigned int irq_create_of_mapping(struct device_node *controller,
                                          u32 *intspec, unsigned int intsize);
 
-
-/* irq_of_parse_and_map - Parse nad Map an interrupt into linux virq space
+/**
+ * irq_of_parse_and_map - Parse and Map an interrupt into linux virq space
  * @device: Device node of the device whose interrupt is to be mapped
  * @index: Index of the interrupt to map
  *
index 11d1fc3a89629ae39d685e5d450a2f29160d3c56..9efa2be78331036ea4ae71cd10ba3aaff8141e84 100644 (file)
@@ -209,14 +209,14 @@ struct machdep_calls {
        /*
         * optional PCI "hooks"
         */
-       /* Called in indirect_* to avoid touching devices */
-       int (*pci_exclude_device)(struct pci_controller *, unsigned char, unsigned char);
-
        /* Called at then very end of pcibios_init() */
        void (*pcibios_after_init)(void);
 
 #endif /* CONFIG_PPC32 */
 
+       /* Called in indirect_* to avoid touching devices */
+       int (*pci_exclude_device)(struct pci_controller *, unsigned char, unsigned char);
+
        /* Called after PPC generic resource fixup to perform
           machine specific fixups */
        void (*pcibios_fixup_resources)(struct pci_dev *);
index 776f415a36aa36da64c4d78084514730a16d2c61..34916865eaef27d16c52121848a8e90f7228a3a7 100644 (file)
@@ -61,4 +61,7 @@ typedef struct {
 
 #endif /* !__ASSEMBLY__ */
 
+#define mmu_virtual_psize      MMU_PAGE_4K
+#define mmu_linear_psize       MMU_PAGE_256M
+
 #endif /* _ASM_POWERPC_MMU_40X_H_ */
index 3c86576bfefa616b6a6e37f6857ec63d17578cf4..0372669383a834f8ff0fe60cbee09dd56f465e40 100644 (file)
@@ -79,16 +79,22 @@ typedef struct {
 
 #if (PAGE_SHIFT == 12)
 #define PPC44x_TLBE_SIZE       PPC44x_TLB_4K
+#define mmu_virtual_psize      MMU_PAGE_4K
 #elif (PAGE_SHIFT == 14)
 #define PPC44x_TLBE_SIZE       PPC44x_TLB_16K
+#define mmu_virtual_psize      MMU_PAGE_16K
 #elif (PAGE_SHIFT == 16)
 #define PPC44x_TLBE_SIZE       PPC44x_TLB_64K
+#define mmu_virtual_psize      MMU_PAGE_64K
 #elif (PAGE_SHIFT == 18)
 #define PPC44x_TLBE_SIZE       PPC44x_TLB_256K
+#define mmu_virtual_psize      MMU_PAGE_256K
 #else
 #error "Unsupported PAGE_SIZE"
 #endif
 
+#define mmu_linear_psize       MMU_PAGE_256M
+
 #define PPC44x_PGD_OFF_SHIFT   (32 - PGDIR_SHIFT + PGD_T_LOG2)
 #define PPC44x_PGD_OFF_MASK_BIT        (PGDIR_SHIFT - PGD_T_LOG2)
 #define PPC44x_PTE_ADD_SHIFT   (32 - PGDIR_SHIFT + PTE_SHIFT + PTE_T_LOG2)
index 07865a357848e66f204f7e9a94da1191eec72cac..3d11d3ce79ec61fa3192381e21214b54f6db6cdf 100644 (file)
@@ -143,4 +143,7 @@ typedef struct {
 } mm_context_t;
 #endif /* !__ASSEMBLY__ */
 
+#define mmu_virtual_psize      MMU_PAGE_4K
+#define mmu_linear_psize       MMU_PAGE_8M
+
 #endif /* _ASM_POWERPC_MMU_8XX_H_ */
index 7e74cff81d864556b12030da29805d590334fe9a..74695816205cb3cb44f1498d06b3ecc7f2751d03 100644 (file)
 #define BOOK3E_PAGESZ_1TB      30
 #define BOOK3E_PAGESZ_2TB      31
 
-#define MAS0_TLBSEL(x) ((x << 28) & 0x30000000)
-#define MAS0_ESEL(x)   ((x << 16) & 0x0FFF0000)
-#define MAS0_NV(x)     ((x) & 0x00000FFF)
-
-#define MAS1_VALID     0x80000000
-#define MAS1_IPROT     0x40000000
-#define MAS1_TID(x)    ((x << 16) & 0x3FFF0000)
-#define MAS1_IND       0x00002000
-#define MAS1_TS                0x00001000
-#define MAS1_TSIZE(x)  ((x << 7) & 0x00000F80)
-
-#define MAS2_EPN       0xFFFFF000
-#define MAS2_X0                0x00000040
-#define MAS2_X1                0x00000020
-#define MAS2_W         0x00000010
-#define MAS2_I         0x00000008
-#define MAS2_M         0x00000004
-#define MAS2_G         0x00000002
-#define MAS2_E         0x00000001
+/* MAS registers bit definitions */
+
+#define MAS0_TLBSEL(x)         ((x << 28) & 0x30000000)
+#define MAS0_ESEL(x)           ((x << 16) & 0x0FFF0000)
+#define MAS0_NV(x)             ((x) & 0x00000FFF)
+#define MAS0_HES               0x00004000
+#define MAS0_WQ_ALLWAYS                0x00000000
+#define MAS0_WQ_COND           0x00001000
+#define MAS0_WQ_CLR_RSRV               0x00002000
+
+#define MAS1_VALID             0x80000000
+#define MAS1_IPROT             0x40000000
+#define MAS1_TID(x)            ((x << 16) & 0x3FFF0000)
+#define MAS1_IND               0x00002000
+#define MAS1_TS                        0x00001000
+#define MAS1_TSIZE_MASK                0x00000f80
+#define MAS1_TSIZE_SHIFT       7
+#define MAS1_TSIZE(x)          ((x << MAS1_TSIZE_SHIFT) & MAS1_TSIZE_MASK)
+
+#define MAS2_EPN               0xFFFFF000
+#define MAS2_X0                        0x00000040
+#define MAS2_X1                        0x00000020
+#define MAS2_W                 0x00000010
+#define MAS2_I                 0x00000008
+#define MAS2_M                 0x00000004
+#define MAS2_G                 0x00000002
+#define MAS2_E                 0x00000001
 #define MAS2_EPN_MASK(size)            (~0 << (size + 10))
 #define MAS2_VAL(addr, size, flags)    ((addr) & MAS2_EPN_MASK(size) | (flags))
 
-#define MAS3_RPN       0xFFFFF000
-#define MAS3_U0                0x00000200
-#define MAS3_U1                0x00000100
-#define MAS3_U2                0x00000080
-#define MAS3_U3                0x00000040
-#define MAS3_UX                0x00000020
-#define MAS3_SX                0x00000010
-#define MAS3_UW                0x00000008
-#define MAS3_SW                0x00000004
-#define MAS3_UR                0x00000002
-#define MAS3_SR                0x00000001
-
-#define MAS4_TLBSELD(x) MAS0_TLBSEL(x)
-#define MAS4_INDD      0x00008000
-#define MAS4_TSIZED(x) MAS1_TSIZE(x)
-#define MAS4_X0D       0x00000040
-#define MAS4_X1D       0x00000020
-#define MAS4_WD                0x00000010
-#define MAS4_ID                0x00000008
-#define MAS4_MD                0x00000004
-#define MAS4_GD                0x00000002
-#define MAS4_ED                0x00000001
-
-#define MAS6_SPID0     0x3FFF0000
-#define MAS6_SPID1     0x00007FFE
-#define MAS6_ISIZE(x)  MAS1_TSIZE(x)
-#define MAS6_SAS       0x00000001
-#define MAS6_SPID      MAS6_SPID0
-
-#define MAS7_RPN       0xFFFFFFFF
+#define MAS3_RPN               0xFFFFF000
+#define MAS3_U0                        0x00000200
+#define MAS3_U1                        0x00000100
+#define MAS3_U2                        0x00000080
+#define MAS3_U3                        0x00000040
+#define MAS3_UX                        0x00000020
+#define MAS3_SX                        0x00000010
+#define MAS3_UW                        0x00000008
+#define MAS3_SW                        0x00000004
+#define MAS3_UR                        0x00000002
+#define MAS3_SR                        0x00000001
+#define MAS3_SPSIZE            0x0000003e
+#define MAS3_SPSIZE_SHIFT      1
+
+#define MAS4_TLBSELD(x)        MAS0_TLBSEL(x)
+#define MAS4_INDD              0x00008000      /* Default IND */
+#define MAS4_TSIZED(x)         MAS1_TSIZE(x)
+#define MAS4_X0D               0x00000040
+#define MAS4_X1D               0x00000020
+#define MAS4_WD                        0x00000010
+#define MAS4_ID                        0x00000008
+#define MAS4_MD                        0x00000004
+#define MAS4_GD                        0x00000002
+#define MAS4_ED                        0x00000001
+#define MAS4_WIMGED_MASK       0x0000001f      /* Default WIMGE */
+#define MAS4_WIMGED_SHIFT      0
+#define MAS4_VLED              MAS4_X1D        /* Default VLE */
+#define MAS4_ACMD              0x000000c0      /* Default ACM */
+#define MAS4_ACMD_SHIFT                6
+#define MAS4_TSIZED_MASK       0x00000f80      /* Default TSIZE */
+#define MAS4_TSIZED_SHIFT      7
+
+#define MAS6_SPID0             0x3FFF0000
+#define MAS6_SPID1             0x00007FFE
+#define MAS6_ISIZE(x)          MAS1_TSIZE(x)
+#define MAS6_SAS               0x00000001
+#define MAS6_SPID              MAS6_SPID0
+#define MAS6_SIND              0x00000002      /* Indirect page */
+#define MAS6_SIND_SHIFT                1
+#define MAS6_SPID_MASK         0x3fff0000
+#define MAS6_SPID_SHIFT                16
+#define MAS6_ISIZE_MASK                0x00000f80
+#define MAS6_ISIZE_SHIFT       7
+
+#define MAS7_RPN               0xFFFFFFFF
+
+/* Bit definitions for MMUCSR0 */
+#define MMUCSR0_TLB1FI 0x00000002      /* TLB1 Flash invalidate */
+#define MMUCSR0_TLB0FI 0x00000004      /* TLB0 Flash invalidate */
+#define MMUCSR0_TLB2FI 0x00000040      /* TLB2 Flash invalidate */
+#define MMUCSR0_TLB3FI 0x00000020      /* TLB3 Flash invalidate */
+#define MMUCSR0_TLBFI  (MMUCSR0_TLB0FI | MMUCSR0_TLB1FI | \
+                        MMUCSR0_TLB2FI | MMUCSR0_TLB3FI)
+#define MMUCSR0_TLB0PS 0x00000780      /* TLB0 Page Size */
+#define MMUCSR0_TLB1PS 0x00007800      /* TLB1 Page Size */
+#define MMUCSR0_TLB2PS 0x00078000      /* TLB2 Page Size */
+#define MMUCSR0_TLB3PS 0x00780000      /* TLB3 Page Size */
+
+/* TLBnCFG encoding */
+#define TLBnCFG_N_ENTRY                0x00000fff      /* number of entries */
+#define TLBnCFG_HES            0x00002000      /* HW select supported */
+#define TLBnCFG_IPROT          0x00008000      /* IPROT supported */
+#define TLBnCFG_GTWE           0x00010000      /* Guest can write */
+#define TLBnCFG_IND            0x00020000      /* IND entries supported */
+#define TLBnCFG_PT             0x00040000      /* Can load from page table */
+#define TLBnCFG_ASSOC          0xff000000      /* Associativity */
+
+/* TLBnPS encoding */
+#define TLBnPS_4K              0x00000004
+#define TLBnPS_8K              0x00000008
+#define TLBnPS_16K             0x00000010
+#define TLBnPS_32K             0x00000020
+#define TLBnPS_64K             0x00000040
+#define TLBnPS_128K            0x00000080
+#define TLBnPS_256K            0x00000100
+#define TLBnPS_512K            0x00000200
+#define TLBnPS_1M              0x00000400
+#define TLBnPS_2M              0x00000800
+#define TLBnPS_4M              0x00001000
+#define TLBnPS_8M              0x00002000
+#define TLBnPS_16M             0x00004000
+#define TLBnPS_32M             0x00008000
+#define TLBnPS_64M             0x00010000
+#define TLBnPS_128M            0x00020000
+#define TLBnPS_256M            0x00040000
+#define TLBnPS_512M            0x00080000
+#define TLBnPS_1G              0x00100000
+#define TLBnPS_2G              0x00200000
+#define TLBnPS_4G              0x00400000
+#define TLBnPS_8G              0x00800000
+#define TLBnPS_16G             0x01000000
+#define TLBnPS_32G             0x02000000
+#define TLBnPS_64G             0x04000000
+#define TLBnPS_128G            0x08000000
+#define TLBnPS_256G            0x10000000
+
+/* tlbilx action encoding */
+#define TLBILX_T_ALL                   0
+#define TLBILX_T_TID                   1
+#define TLBILX_T_FULLMATCH             3
+#define TLBILX_T_CLASS0                        4
+#define TLBILX_T_CLASS1                        5
+#define TLBILX_T_CLASS2                        6
+#define TLBILX_T_CLASS3                        7
 
 #ifndef __ASSEMBLY__
 
@@ -100,6 +182,34 @@ typedef struct {
        unsigned int    active;
        unsigned long   vdso_base;
 } mm_context_t;
+
+/* Page size definitions, common between 32 and 64-bit
+ *
+ *    shift : is the "PAGE_SHIFT" value for that page size
+ *    penc  : is the pte encoding mask
+ *
+ */
+struct mmu_psize_def
+{
+       unsigned int    shift;  /* number of bits */
+       unsigned int    enc;    /* PTE encoding */
+};
+extern struct mmu_psize_def mmu_psize_defs[MMU_PAGE_COUNT];
+
+/* The page sizes use the same names as 64-bit hash but are
+ * constants
+ */
+#if defined(CONFIG_PPC_4K_PAGES)
+#define mmu_virtual_psize      MMU_PAGE_4K
+#elif defined(CONFIG_PPC_64K_PAGES)
+#define mmu_virtual_psize      MMU_PAGE_64K
+#else
+#error Unsupported page size
+#endif
+
+extern int mmu_linear_psize;
+extern int mmu_vmemmap_psize;
+
 #endif /* !__ASSEMBLY__ */
 
 #endif /* _ASM_POWERPC_MMU_BOOK3E_H_ */
index 16b1a1e77e64e5b5adeaba606db3aee1047f29c1..16f513e5cbd74f2cc42460ba3c7d28524bb86e81 100644 (file)
@@ -55,21 +55,25 @@ struct ppc_bat {
 
 #ifndef __ASSEMBLY__
 
-/* Hardware Page Table Entry */
+/*
+ * Hardware Page Table Entry
+ * Note that the xpn and x bitfields are used only by processors that
+ * support extended addressing; otherwise, those bits are reserved.
+ */
 struct hash_pte {
        unsigned long v:1;      /* Entry is valid */
        unsigned long vsid:24;  /* Virtual segment identifier */
        unsigned long h:1;      /* Hash algorithm indicator */
        unsigned long api:6;    /* Abbreviated page index */
        unsigned long rpn:20;   /* Real (physical) page number */
-       unsigned long    :3;    /* Unused */
+       unsigned long xpn:3;    /* Real page number bits 0-2, optional */
        unsigned long r:1;      /* Referenced */
        unsigned long c:1;      /* Changed */
        unsigned long w:1;      /* Write-thru cache mode */
        unsigned long i:1;      /* Cache inhibited */
        unsigned long m:1;      /* Memory coherence */
        unsigned long g:1;      /* Guarded */
-       unsigned long  :1;      /* Unused */
+       unsigned long x:1;      /* Real page number bit 3, optional */
        unsigned long pp:2;     /* Page protection */
 };
 
@@ -80,4 +84,10 @@ typedef struct {
 
 #endif /* !__ASSEMBLY__ */
 
+/* We happily ignore the smaller BATs on 601, we don't actually use
+ * those definitions on hash32 at the moment anyway
+ */
+#define mmu_virtual_psize      MMU_PAGE_4K
+#define mmu_linear_psize       MMU_PAGE_256M
+
 #endif /* _ASM_POWERPC_MMU_HASH32_H_ */
index 98c104a0996196a7932e83c846e80a81a315e87c..bebe31c2e9072bbd79144fbb616672b092e4d84e 100644 (file)
@@ -41,6 +41,7 @@ extern char initial_stab[];
 
 #define SLB_NUM_BOLTED         3
 #define SLB_CACHE_ENTRIES      8
+#define SLB_MIN_SIZE           32
 
 /* Bits in the SLB ESID word */
 #define SLB_ESID_V             ASM_CONST(0x0000000008000000) /* valid */
@@ -138,26 +139,6 @@ struct mmu_psize_def
 
 #endif /* __ASSEMBLY__ */
 
-/*
- * The kernel use the constants below to index in the page sizes array.
- * The use of fixed constants for this purpose is better for performances
- * of the low level hash refill handlers.
- *
- * A non supported page size has a "shift" field set to 0
- *
- * Any new page size being implemented can get a new entry in here. Whether
- * the kernel will use it or not is a different matter though. The actual page
- * size used by hugetlbfs is not defined here and may be made variable
- */
-
-#define MMU_PAGE_4K            0       /* 4K */
-#define MMU_PAGE_64K           1       /* 64K */
-#define MMU_PAGE_64K_AP                2       /* 64K Admixed (in a 4K segment) */
-#define MMU_PAGE_1M            3       /* 1M */
-#define MMU_PAGE_16M           4       /* 16M */
-#define MMU_PAGE_16G           5       /* 16G */
-#define MMU_PAGE_COUNT         6
-
 /*
  * Segment sizes.
  * These are the values used by hardware in the B field of
@@ -296,6 +277,7 @@ extern void slb_flush_and_rebolt(void);
 extern void stab_initialize(unsigned long stab);
 
 extern void slb_vmalloc_update(void);
+extern void slb_set_size(u16 size);
 #endif /* __ASSEMBLY__ */
 
 /*
index fb57ded592f9f1b8ccdb6affbd245e7425159309..7ffbb65ff7a9815325088a862fb46d250a895547 100644 (file)
@@ -17,6 +17,7 @@
 #define MMU_FTR_TYPE_40x               ASM_CONST(0x00000004)
 #define MMU_FTR_TYPE_44x               ASM_CONST(0x00000008)
 #define MMU_FTR_TYPE_FSL_E             ASM_CONST(0x00000010)
+#define MMU_FTR_TYPE_3E                        ASM_CONST(0x00000020)
 
 /*
  * This is individual features
  */
 #define MMU_FTR_TLBIE_206              ASM_CONST(0x00400000)
 
+/* Enable use of TLB reservation.  Processor should support tlbsrx.
+ * instruction and MAS0[WQ].
+ */
+#define MMU_FTR_USE_TLBRSRV            ASM_CONST(0x00800000)
+
+/* Use paired MAS registers (MAS7||MAS3, etc.)
+ */
+#define MMU_FTR_USE_PAIRED_MAS         ASM_CONST(0x01000000)
+
 #ifndef __ASSEMBLY__
 #include <asm/cputable.h>
 
@@ -73,6 +83,41 @@ extern void early_init_mmu_secondary(void);
 
 #endif /* !__ASSEMBLY__ */
 
+/* The kernel use the constants below to index in the page sizes array.
+ * The use of fixed constants for this purpose is better for performances
+ * of the low level hash refill handlers.
+ *
+ * A non supported page size has a "shift" field set to 0
+ *
+ * Any new page size being implemented can get a new entry in here. Whether
+ * the kernel will use it or not is a different matter though. The actual page
+ * size used by hugetlbfs is not defined here and may be made variable
+ *
+ * Note: This array ended up being a false good idea as it's growing to the
+ * point where I wonder if we should replace it with something different,
+ * to think about, feedback welcome. --BenH.
+ */
+
+/* There are #define as they have to be used in assembly
+ *
+ * WARNING: If you change this list, make sure to update the array of
+ * names currently in arch/powerpc/mm/hugetlbpage.c or bad things will
+ * happen
+ */
+#define MMU_PAGE_4K    0
+#define MMU_PAGE_16K   1
+#define MMU_PAGE_64K   2
+#define MMU_PAGE_64K_AP        3       /* "Admixed pages" (hash64 only) */
+#define MMU_PAGE_256K  4
+#define MMU_PAGE_1M    5
+#define MMU_PAGE_8M    6
+#define MMU_PAGE_16M   7
+#define MMU_PAGE_256M  8
+#define MMU_PAGE_1G    9
+#define MMU_PAGE_16G   10
+#define MMU_PAGE_64G   11
+#define MMU_PAGE_COUNT 12
+
 
 #if defined(CONFIG_PPC_STD_MMU_64)
 /* 64-bit classic hash table MMU */
@@ -94,5 +139,6 @@ extern void early_init_mmu_secondary(void);
 #  include <asm/mmu-8xx.h>
 #endif
 
+
 #endif /* __KERNEL__ */
 #endif /* _ASM_POWERPC_MMU_H_ */
index b7063669f972b04238c16c945c34987a67e81524..b34e94d9443583d1bd17729a1230e38adde53479 100644 (file)
@@ -14,7 +14,6 @@
 /*
  * Most if the context management is out of line
  */
-extern void mmu_context_init(void);
 extern int init_new_context(struct task_struct *tsk, struct mm_struct *mm);
 extern void destroy_context(struct mm_struct *mm);
 
@@ -23,6 +22,12 @@ extern void switch_stab(struct task_struct *tsk, struct mm_struct *mm);
 extern void switch_slb(struct task_struct *tsk, struct mm_struct *mm);
 extern void set_context(unsigned long id, pgd_t *pgd);
 
+#ifdef CONFIG_PPC_BOOK3S_64
+static inline void mmu_context_init(void) { }
+#else
+extern void mmu_context_init(void);
+#endif
+
 /*
  * switch_mm is the entry point called from the architecture independent
  * code in kernel/sched.c
@@ -38,6 +43,10 @@ static inline void switch_mm(struct mm_struct *prev, struct mm_struct *next,
        tsk->thread.pgdir = next->pgd;
 #endif /* CONFIG_PPC32 */
 
+       /* 64-bit Book3E keeps track of current PGD in the PACA */
+#ifdef CONFIG_PPC_BOOK3E_64
+       get_paca()->pgd = next->pgd;
+#endif
        /* Nothing else to do if we aren't actually switching */
        if (prev == next)
                return;
@@ -84,6 +93,10 @@ static inline void activate_mm(struct mm_struct *prev, struct mm_struct *next)
 static inline void enter_lazy_tlb(struct mm_struct *mm,
                                  struct task_struct *tsk)
 {
+       /* 64-bit Book3E keeps track of current PGD in the PACA */
+#ifdef CONFIG_PPC_BOOK3E_64
+       get_paca()->pgd = NULL;
+#endif
 }
 
 #endif /* __KERNEL__ */
index efde5ac82f7b915df030d42cae81c38fc63803fe..6c587eddee59a3fd371dd83af6714d308c8d1aeb 100644 (file)
@@ -107,6 +107,9 @@ extern void pmac_xpram_write(int xpaddr, u8 data);
 /* Synchronize NVRAM */
 extern void    nvram_sync(void);
 
+/* Determine NVRAM size */
+extern ssize_t nvram_get_size(void);
+
 /* Normal access to NVRAM */
 extern unsigned char nvram_read_byte(int i);
 extern void nvram_write_byte(unsigned char c, int i);
index c8a3cbfe02ffaea0bca9be6d35a9fa8ef218bf18..b634456ea893541de7c7050aebca65429fb38d50 100644 (file)
 #define _ASM_POWERPC_PACA_H
 #ifdef __KERNEL__
 
-#include       <asm/types.h>
-#include       <asm/lppaca.h>
-#include       <asm/mmu.h>
+#include <asm/types.h>
+#include <asm/lppaca.h>
+#include <asm/mmu.h>
+#include <asm/page.h>
+#include <asm/exception-64e.h>
 
 register struct paca_struct *local_paca asm("r13");
 
@@ -91,6 +93,21 @@ struct paca_struct {
        u16 slb_cache[SLB_CACHE_ENTRIES];
 #endif /* CONFIG_PPC_STD_MMU_64 */
 
+#ifdef CONFIG_PPC_BOOK3E
+       pgd_t *pgd;                     /* Current PGD */
+       pgd_t *kernel_pgd;              /* Kernel PGD */
+       u64 exgen[8] __attribute__((aligned(0x80)));
+       u64 extlb[EX_TLB_SIZE*3] __attribute__((aligned(0x80)));
+       u64 exmc[8];            /* used for machine checks */
+       u64 excrit[8];          /* used for crit interrupts */
+       u64 exdbg[8];           /* used for debug interrupts */
+
+       /* Kernel stack pointers for use by special exceptions */
+       void *mc_kstack;
+       void *crit_kstack;
+       void *dbg_kstack;
+#endif /* CONFIG_PPC_BOOK3E */
+
        mm_context_t context;
 
        /*
index 4940662ee87ef09c512d46c437ed0e848e51a2d3..ff24254990e11c4b64c35ee44f3ae664c36e8063 100644 (file)
@@ -139,7 +139,11 @@ extern phys_addr_t kernstart_addr;
  * Don't compare things with KERNELBASE or PAGE_OFFSET to test for
  * "kernelness", use is_kernel_addr() - it should do what you want.
  */
+#ifdef CONFIG_PPC_BOOK3E_64
+#define is_kernel_addr(x)      ((x) >= 0x8000000000000000ul)
+#else
 #define is_kernel_addr(x)      ((x) >= PAGE_OFFSET)
+#endif
 
 #ifndef __ASSEMBLY__
 
index 5817a3b747e53c12b516fd8229381b40486cd0e2..3f17b83f55a18d8e4c8525136e257664414552f1 100644 (file)
@@ -135,12 +135,22 @@ extern void slice_set_range_psize(struct mm_struct *mm, unsigned long start,
 #endif /* __ASSEMBLY__ */
 #else
 #define slice_init()
+#ifdef CONFIG_PPC_STD_MMU_64
 #define get_slice_psize(mm, addr)      ((mm)->context.user_psize)
 #define slice_set_user_psize(mm, psize)                \
 do {                                           \
        (mm)->context.user_psize = (psize);     \
        (mm)->context.sllp = SLB_VSID_USER | mmu_psize_defs[(psize)].sllp; \
 } while (0)
+#else /* CONFIG_PPC_STD_MMU_64 */
+#ifdef CONFIG_PPC_64K_PAGES
+#define get_slice_psize(mm, addr)      MMU_PAGE_64K
+#else /* CONFIG_PPC_64K_PAGES */
+#define get_slice_psize(mm, addr)      MMU_PAGE_4K
+#endif /* !CONFIG_PPC_64K_PAGES */
+#define slice_set_user_psize(mm, psize)        do { BUG(); } while(0)
+#endif /* !CONFIG_PPC_STD_MMU_64 */
+
 #define slice_set_range_psize(mm, start, len, psize)   \
        slice_set_user_psize((mm), (psize))
 #define slice_mm_new_context(mm)       1
index 4c61fa0b8d75f946bdd5de16ac72fc947c90e7fd..76e1f313a58e2306451f6f933915690db1b4ddd9 100644 (file)
@@ -77,9 +77,7 @@ struct pci_controller {
 
        int first_busno;
        int last_busno;
-#ifndef CONFIG_PPC64
        int self_busno;
-#endif
 
        void __iomem *io_base_virt;
 #ifdef CONFIG_PPC64
@@ -104,7 +102,6 @@ struct pci_controller {
        unsigned int __iomem *cfg_addr;
        void __iomem *cfg_data;
 
-#ifndef CONFIG_PPC64
        /*
         * Used for variants of PCI indirect handling and possible quirks:
         *  SET_CFG_TYPE - used on 4xx or any PHB that does explicit type0/1
@@ -128,7 +125,6 @@ struct pci_controller {
 #define PPC_INDIRECT_TYPE_BIG_ENDIAN           0x00000010
 #define PPC_INDIRECT_TYPE_BROKEN_MRM           0x00000020
        u32 indirect_type;
-#endif /* !CONFIG_PPC64 */
        /* Currently, we limit ourselves to 1 IO range and 3 mem
         * ranges since the common pci_bus structure can't handle more
         */
@@ -146,21 +142,6 @@ struct pci_controller {
 #endif /* CONFIG_PPC64 */
 };
 
-#ifndef CONFIG_PPC64
-
-static inline struct pci_controller *pci_bus_to_host(const struct pci_bus *bus)
-{
-       return bus->sysdata;
-}
-
-static inline int isa_vaddr_is_ioport(void __iomem *address)
-{
-       /* No specific ISA handling on ppc32 at this stage, it
-        * all goes through PCI
-        */
-       return 0;
-}
-
 /* These are used for config access before all the PCI probing
    has been done. */
 extern int early_read_config_byte(struct pci_controller *hose, int bus,
@@ -182,6 +163,22 @@ extern int early_find_capability(struct pci_controller *hose, int bus,
 extern void setup_indirect_pci(struct pci_controller* hose,
                               resource_size_t cfg_addr,
                               resource_size_t cfg_data, u32 flags);
+
+#ifndef CONFIG_PPC64
+
+static inline struct pci_controller *pci_bus_to_host(const struct pci_bus *bus)
+{
+       return bus->sysdata;
+}
+
+static inline int isa_vaddr_is_ioport(void __iomem *address)
+{
+       /* No specific ISA handling on ppc32 at this stage, it
+        * all goes through PCI
+        */
+       return 0;
+}
+
 #else  /* CONFIG_PPC64 */
 
 /*
@@ -284,11 +281,6 @@ static inline int isa_vaddr_is_ioport(void __iomem *address)
 extern int pcibios_unmap_io_space(struct pci_bus *bus);
 extern int pcibios_map_io_space(struct pci_bus *bus);
 
-/* Return values for ppc_md.pci_probe_mode function */
-#define PCI_PROBE_NONE         -1      /* Don't look at this bus at all */
-#define PCI_PROBE_NORMAL       0       /* Do normal PCI probing */
-#define PCI_PROBE_DEVTREE      1       /* Instantiate from device tree */
-
 #ifdef CONFIG_NUMA
 #define PHB_SET_NODE(PHB, NODE)                ((PHB)->node = (NODE))
 #else
index d9483c504d2d37cffeb6a3171f1d040e1b7f6194..7aca4839387bdb8c4d82e94ccaa8d16458d9b939 100644 (file)
 
 #include <asm-generic/pci-dma-compat.h>
 
+/* Return values for ppc_md.pci_probe_mode function */
+#define PCI_PROBE_NONE         -1      /* Don't look at this bus at all */
+#define PCI_PROBE_NORMAL       0       /* Do normal PCI probing */
+#define PCI_PROBE_DEVTREE      1       /* Instantiate from device tree */
+
 #define PCIBIOS_MIN_IO         0x1000
 #define PCIBIOS_MIN_MEM                0x10000000
 
@@ -61,8 +66,8 @@ static inline int pci_get_legacy_ide_irq(struct pci_dev *dev, int channel)
 }
 
 #ifdef CONFIG_PCI
-extern void set_pci_dma_ops(struct dma_mapping_ops *dma_ops);
-extern struct dma_mapping_ops *get_pci_dma_ops(void);
+extern void set_pci_dma_ops(struct dma_map_ops *dma_ops);
+extern struct dma_map_ops *get_pci_dma_ops(void);
 #else  /* CONFIG_PCI */
 #define set_pci_dma_ops(d)
 #define get_pci_dma_ops()      NULL
@@ -228,6 +233,8 @@ extern void pci_resource_to_user(const struct pci_dev *dev, int bar,
 
 extern void pcibios_setup_bus_devices(struct pci_bus *bus);
 extern void pcibios_setup_bus_self(struct pci_bus *bus);
+extern void pcibios_setup_phb_io_space(struct pci_controller *hose);
+extern void pcibios_scan_phb(struct pci_controller *hose, void *sysdata);
 
 #endif /* __KERNEL__ */
 #endif /* __ASM_POWERPC_PCI_H */
index 1730e5e298d61b07df858de4e32078c7ff4201e4..f2e812de7c3cb919f26074f79414a77271626429 100644 (file)
@@ -4,6 +4,15 @@
 
 #include <linux/mm.h>
 
+#ifdef CONFIG_PPC_BOOK3E
+extern void tlb_flush_pgtable(struct mmu_gather *tlb, unsigned long address);
+#else /* CONFIG_PPC_BOOK3E */
+static inline void tlb_flush_pgtable(struct mmu_gather *tlb,
+                                    unsigned long address)
+{
+}
+#endif /* !CONFIG_PPC_BOOK3E */
+
 static inline void pte_free_kernel(struct mm_struct *mm, pte_t *pte)
 {
        free_page((unsigned long)pte);
@@ -19,7 +28,12 @@ typedef struct pgtable_free {
        unsigned long val;
 } pgtable_free_t;
 
-#define PGF_CACHENUM_MASK      0x7
+/* This needs to be big enough to allow for MMU_PAGE_COUNT + 2 to be stored
+ * and small enough to fit in the low bits of any naturally aligned page
+ * table cache entry. Arbitrarily set to 0x1f, that should give us some
+ * room to grow
+ */
+#define PGF_CACHENUM_MASK      0x1f
 
 static inline pgtable_free_t pgtable_free_cache(void *p, int cachenum,
                                                unsigned long mask)
@@ -35,19 +49,27 @@ static inline pgtable_free_t pgtable_free_cache(void *p, int cachenum,
 #include <asm/pgalloc-32.h>
 #endif
 
-extern void pgtable_free_tlb(struct mmu_gather *tlb, pgtable_free_t pgf);
-
 #ifdef CONFIG_SMP
-#define __pte_free_tlb(tlb,ptepage,address)            \
-do { \
-       pgtable_page_dtor(ptepage); \
-       pgtable_free_tlb(tlb, pgtable_free_cache(page_address(ptepage), \
-                                       PTE_NONCACHE_NUM, PTE_TABLE_SIZE-1)); \
-} while (0)
-#else
-#define __pte_free_tlb(tlb, pte, address)      pte_free((tlb)->mm, (pte))
-#endif
+extern void pgtable_free_tlb(struct mmu_gather *tlb, pgtable_free_t pgf);
+extern void pte_free_finish(void);
+#else /* CONFIG_SMP */
+static inline void pgtable_free_tlb(struct mmu_gather *tlb, pgtable_free_t pgf)
+{
+       pgtable_free(pgf);
+}
+static inline void pte_free_finish(void) { }
+#endif /* !CONFIG_SMP */
 
+static inline void __pte_free_tlb(struct mmu_gather *tlb, struct page *ptepage,
+                                 unsigned long address)
+{
+       pgtable_free_t pgf = pgtable_free_cache(page_address(ptepage),
+                                               PTE_NONCACHE_NUM,
+                                               PTE_TABLE_SIZE-1);
+       tlb_flush_pgtable(tlb, address);
+       pgtable_page_dtor(ptepage);
+       pgtable_free_tlb(tlb, pgf);
+}
 
 #endif /* __KERNEL__ */
 #endif /* _ASM_POWERPC_PGALLOC_H */
index c9ff9d75990eb94eaf55944482dff6b5301d3afe..55646adfa843f604019fe5c35d9da6425b2d0e6e 100644 (file)
@@ -111,6 +111,8 @@ extern int icache_44x_need_flush;
 #include <asm/pte-40x.h>
 #elif defined(CONFIG_44x)
 #include <asm/pte-44x.h>
+#elif defined(CONFIG_FSL_BOOKE) && defined(CONFIG_PTE_64BIT)
+#include <asm/pte-book3e.h>
 #elif defined(CONFIG_FSL_BOOKE)
 #include <asm/pte-fsl-booke.h>
 #elif defined(CONFIG_8xx)
@@ -186,7 +188,7 @@ static inline unsigned long pte_update(pte_t *p,
 #endif /* !PTE_ATOMIC_UPDATES */
 
 #ifdef CONFIG_44x
-       if ((old & _PAGE_USER) && (old & _PAGE_HWEXEC))
+       if ((old & _PAGE_USER) && (old & _PAGE_EXEC))
                icache_44x_need_flush = 1;
 #endif
        return old;
@@ -217,7 +219,7 @@ static inline unsigned long long pte_update(pte_t *p,
 #endif /* !PTE_ATOMIC_UPDATES */
 
 #ifdef CONFIG_44x
-       if ((old & _PAGE_USER) && (old & _PAGE_HWEXEC))
+       if ((old & _PAGE_USER) && (old & _PAGE_EXEC))
                icache_44x_need_flush = 1;
 #endif
        return old;
@@ -267,8 +269,7 @@ static inline void huge_ptep_set_wrprotect(struct mm_struct *mm,
 static inline void __ptep_set_access_flags(pte_t *ptep, pte_t entry)
 {
        unsigned long bits = pte_val(entry) &
-               (_PAGE_DIRTY | _PAGE_ACCESSED | _PAGE_RW |
-                _PAGE_HWEXEC | _PAGE_EXEC);
+               (_PAGE_DIRTY | _PAGE_ACCESSED | _PAGE_RW | _PAGE_EXEC);
        pte_update(ptep, 0, bits);
 }
 
index 6cc085b945a5aa8546e4aa171f4920d3f429f92f..90533ddcd7035241cb14372fb8f0b2a284a64c5a 100644 (file)
 #define PGD_INDEX_SIZE  4
 
 #ifndef __ASSEMBLY__
-
 #define PTE_TABLE_SIZE (sizeof(real_pte_t) << PTE_INDEX_SIZE)
 #define PMD_TABLE_SIZE (sizeof(pmd_t) << PMD_INDEX_SIZE)
 #define PGD_TABLE_SIZE (sizeof(pgd_t) << PGD_INDEX_SIZE)
+#endif /* __ASSEMBLY__ */
 
 #define PTRS_PER_PTE   (1 << PTE_INDEX_SIZE)
 #define PTRS_PER_PMD   (1 << PMD_INDEX_SIZE)
@@ -32,8 +32,6 @@
 #define PGDIR_SIZE     (1UL << PGDIR_SHIFT)
 #define PGDIR_MASK     (~(PGDIR_SIZE-1))
 
-#endif /* __ASSEMBLY__ */
-
 /* Bits to mask out from a PMD to get to the PTE page */
 #define PMD_MASKED_BITS                0x1ff
 /* Bits to mask out from a PGD/PUD to get to the PMD page */
index 8cd083c6150384eeca4c28a38d5a49e643efab1a..806abe7a3fa58c32523a167f90ad18a0ef5f8aa0 100644 (file)
@@ -5,11 +5,6 @@
  * the ppc64 hashed page table.
  */
 
-#ifndef __ASSEMBLY__
-#include <linux/stddef.h>
-#include <asm/tlbflush.h>
-#endif /* __ASSEMBLY__ */
-
 #ifdef CONFIG_PPC_64K_PAGES
 #include <asm/pgtable-ppc64-64k.h>
 #else
 #endif
 
 /*
- * Define the address range of the vmalloc VM area.
+ * Define the address range of the kernel non-linear virtual area
+ */
+
+#ifdef CONFIG_PPC_BOOK3E
+#define KERN_VIRT_START ASM_CONST(0x8000000000000000)
+#else
+#define KERN_VIRT_START ASM_CONST(0xD000000000000000)
+#endif
+#define KERN_VIRT_SIZE PGTABLE_RANGE
+
+/*
+ * The vmalloc space starts at the beginning of that region, and
+ * occupies half of it on hash CPUs and a quarter of it on Book3E
+ * (we keep a quarter for the virtual memmap)
  */
-#define VMALLOC_START ASM_CONST(0xD000000000000000)
-#define VMALLOC_SIZE  (PGTABLE_RANGE >> 1)
-#define VMALLOC_END   (VMALLOC_START + VMALLOC_SIZE)
+#define VMALLOC_START  KERN_VIRT_START
+#ifdef CONFIG_PPC_BOOK3E
+#define VMALLOC_SIZE   (KERN_VIRT_SIZE >> 2)
+#else
+#define VMALLOC_SIZE   (KERN_VIRT_SIZE >> 1)
+#endif
+#define VMALLOC_END    (VMALLOC_START + VMALLOC_SIZE)
 
 /*
- * Define the address ranges for MMIO and IO space :
+ * The second half of the kernel virtual space is used for IO mappings,
+ * it's itself carved into the PIO region (ISA and PHB IO space) and
+ * the ioremap space
  *
- *  ISA_IO_BASE = VMALLOC_END, 64K reserved area
+ *  ISA_IO_BASE = KERN_IO_START, 64K reserved area
  *  PHB_IO_BASE = ISA_IO_BASE + 64K to ISA_IO_BASE + 2G, PHB IO spaces
  * IOREMAP_BASE = ISA_IO_BASE + 2G to VMALLOC_START + PGTABLE_RANGE
  */
+#define KERN_IO_START  (KERN_VIRT_START + (KERN_VIRT_SIZE >> 1))
 #define FULL_IO_SIZE   0x80000000ul
-#define  ISA_IO_BASE   (VMALLOC_END)
-#define  ISA_IO_END    (VMALLOC_END + 0x10000ul)
+#define  ISA_IO_BASE   (KERN_IO_START)
+#define  ISA_IO_END    (KERN_IO_START + 0x10000ul)
 #define  PHB_IO_BASE   (ISA_IO_END)
-#define  PHB_IO_END    (VMALLOC_END + FULL_IO_SIZE)
+#define  PHB_IO_END    (KERN_IO_START + FULL_IO_SIZE)
 #define IOREMAP_BASE   (PHB_IO_END)
-#define IOREMAP_END    (VMALLOC_START + PGTABLE_RANGE)
+#define IOREMAP_END    (KERN_VIRT_START + KERN_VIRT_SIZE)
+
 
 /*
  * Region IDs
 
 #define VMALLOC_REGION_ID      (REGION_ID(VMALLOC_START))
 #define KERNEL_REGION_ID       (REGION_ID(PAGE_OFFSET))
-#define VMEMMAP_REGION_ID      (0xfUL)
+#define VMEMMAP_REGION_ID      (0xfUL) /* Server only */
 #define USER_REGION_ID         (0UL)
 
 /*
- * Defines the address of the vmemap area, in its own region
+ * Defines the address of the vmemap area, in its own region on
+ * hash table CPUs and after the vmalloc space on Book3E
  */
+#ifdef CONFIG_PPC_BOOK3E
+#define VMEMMAP_BASE           VMALLOC_END
+#define VMEMMAP_END            KERN_IO_START
+#else
 #define VMEMMAP_BASE           (VMEMMAP_REGION_ID << REGION_SHIFT)
+#endif
 #define vmemmap                        ((struct page *)VMEMMAP_BASE)
 
 
 /*
  * Include the PTE bits definitions
  */
+#ifdef CONFIG_PPC_BOOK3S
 #include <asm/pte-hash64.h>
+#else
+#include <asm/pte-book3e.h>
+#endif
 #include <asm/pte-common.h>
 
-
 #ifdef CONFIG_PPC_MM_SLICES
 #define HAVE_ARCH_UNMAPPED_AREA
 #define HAVE_ARCH_UNMAPPED_AREA_TOPDOWN
 
 #ifndef __ASSEMBLY__
 
+#include <linux/stddef.h>
+#include <asm/tlbflush.h>
+
 /*
  * This is the default implementation of various PTE accessors, it's
  * used in all cases except Book3S with 64K pages where we have a
@@ -285,8 +313,7 @@ static inline void pte_clear(struct mm_struct *mm, unsigned long addr,
 static inline void __ptep_set_access_flags(pte_t *ptep, pte_t entry)
 {
        unsigned long bits = pte_val(entry) &
-               (_PAGE_DIRTY | _PAGE_ACCESSED | _PAGE_RW |
-                _PAGE_EXEC | _PAGE_HWEXEC);
+               (_PAGE_DIRTY | _PAGE_ACCESSED | _PAGE_RW | _PAGE_EXEC);
 
 #ifdef PTE_ATOMIC_UPDATES
        unsigned long old, tmp;
index d6a616a1b3ea8f8d4614ea9e236c4758589af605..ccc68b50d05d70f9a413b6f1f7fa3d66af01670f 100644 (file)
@@ -27,10 +27,22 @@ extern perf_irq_t perf_irq;
 
 int reserve_pmc_hardware(perf_irq_t new_perf_irq);
 void release_pmc_hardware(void);
+void ppc_enable_pmcs(void);
 
 #ifdef CONFIG_PPC64
-void power4_enable_pmcs(void);
-void pasemi_enable_pmcs(void);
+#include <asm/lppaca.h>
+
+static inline void ppc_set_pmu_inuse(int inuse)
+{
+       get_lppaca()->pmcregs_in_use = inuse;
+}
+
+extern void power4_enable_pmcs(void);
+
+#else /* CONFIG_PPC64 */
+
+static inline void ppc_set_pmu_inuse(int inuse) { }
+
 #endif
 
 #endif /* __KERNEL__ */
index b74f16d45cb45f7945687003c399379730098f5f..ef9aa84cac5ad290eaeb53032491eae92dcd2808 100644 (file)
@@ -48,6 +48,8 @@
 #define PPC_INST_TLBIE                 0x7c000264
 #define PPC_INST_TLBILX                        0x7c000024
 #define PPC_INST_WAIT                  0x7c00007c
+#define PPC_INST_TLBIVAX               0x7c000624
+#define PPC_INST_TLBSRX_DOT            0x7c0006a5
 
 /* macros to insert fields into opcodes */
 #define __PPC_RA(a)    (((a) & 0x1f) << 16)
                                        __PPC_WC(w))
 #define PPC_TLBIE(lp,a)        stringify_in_c(.long PPC_INST_TLBIE | \
                                               __PPC_RB(a) | __PPC_RS(lp))
+#define PPC_TLBSRX_DOT(a,b)    stringify_in_c(.long PPC_INST_TLBSRX_DOT | \
+                                       __PPC_RA(a) | __PPC_RB(b))
+#define PPC_TLBIVAX(a,b)       stringify_in_c(.long PPC_INST_TLBIVAX | \
+                                       __PPC_RA(a) | __PPC_RB(b))
 
 /*
  * Define what the VSX XX1 form instructions will look like, then add
index 854ab713f56cb62b857216285d3b343c13e9ea66..2828f9d0f66ddb1d66be47662c999282fc25fdaf 100644 (file)
@@ -39,7 +39,6 @@ void *traverse_pci_devices(struct device_node *start, traverse_func pre,
 
 extern void pci_devs_phb_init(void);
 extern void pci_devs_phb_init_dynamic(struct pci_controller *phb);
-extern void scan_phb(struct pci_controller *hose);
 
 /* From rtas_pci.h */
 extern void init_pci_config_tokens (void);
index f9729529c20d2a2339951216cf9ed565c73491a6..498fe09263d3e7df23ca37b848996339ff50b23c 100644 (file)
@@ -98,13 +98,13 @@ END_FTR_SECTION_IFCLR(CPU_FTR_PURR);                                        \
 #define REST_16FPRS(n, base)   REST_8FPRS(n, base); REST_8FPRS(n+8, base)
 #define REST_32FPRS(n, base)   REST_16FPRS(n, base); REST_16FPRS(n+16, base)
 
-#define SAVE_VR(n,b,base)      li b,THREAD_VR0+(16*(n));  stvx n,b,base
+#define SAVE_VR(n,b,base)      li b,THREAD_VR0+(16*(n));  stvx n,base,b
 #define SAVE_2VRS(n,b,base)    SAVE_VR(n,b,base); SAVE_VR(n+1,b,base)
 #define SAVE_4VRS(n,b,base)    SAVE_2VRS(n,b,base); SAVE_2VRS(n+2,b,base)
 #define SAVE_8VRS(n,b,base)    SAVE_4VRS(n,b,base); SAVE_4VRS(n+4,b,base)
 #define SAVE_16VRS(n,b,base)   SAVE_8VRS(n,b,base); SAVE_8VRS(n+8,b,base)
 #define SAVE_32VRS(n,b,base)   SAVE_16VRS(n,b,base); SAVE_16VRS(n+16,b,base)
-#define REST_VR(n,b,base)      li b,THREAD_VR0+(16*(n)); lvx n,b,base
+#define REST_VR(n,b,base)      li b,THREAD_VR0+(16*(n)); lvx n,base,b
 #define REST_2VRS(n,b,base)    REST_VR(n,b,base); REST_VR(n+1,b,base)
 #define REST_4VRS(n,b,base)    REST_2VRS(n,b,base); REST_2VRS(n+2,b,base)
 #define REST_8VRS(n,b,base)    REST_4VRS(n,b,base); REST_4VRS(n+4,b,base)
@@ -112,26 +112,26 @@ END_FTR_SECTION_IFCLR(CPU_FTR_PURR);                                      \
 #define REST_32VRS(n,b,base)   REST_16VRS(n,b,base); REST_16VRS(n+16,b,base)
 
 /* Save the lower 32 VSRs in the thread VSR region */
-#define SAVE_VSR(n,b,base)     li b,THREAD_VSR0+(16*(n));  STXVD2X(n,b,base)
+#define SAVE_VSR(n,b,base)     li b,THREAD_VSR0+(16*(n));  STXVD2X(n,base,b)
 #define SAVE_2VSRS(n,b,base)   SAVE_VSR(n,b,base); SAVE_VSR(n+1,b,base)
 #define SAVE_4VSRS(n,b,base)   SAVE_2VSRS(n,b,base); SAVE_2VSRS(n+2,b,base)
 #define SAVE_8VSRS(n,b,base)   SAVE_4VSRS(n,b,base); SAVE_4VSRS(n+4,b,base)
 #define SAVE_16VSRS(n,b,base)  SAVE_8VSRS(n,b,base); SAVE_8VSRS(n+8,b,base)
 #define SAVE_32VSRS(n,b,base)  SAVE_16VSRS(n,b,base); SAVE_16VSRS(n+16,b,base)
-#define REST_VSR(n,b,base)     li b,THREAD_VSR0+(16*(n)); LXVD2X(n,b,base)
+#define REST_VSR(n,b,base)     li b,THREAD_VSR0+(16*(n)); LXVD2X(n,base,b)
 #define REST_2VSRS(n,b,base)   REST_VSR(n,b,base); REST_VSR(n+1,b,base)
 #define REST_4VSRS(n,b,base)   REST_2VSRS(n,b,base); REST_2VSRS(n+2,b,base)
 #define REST_8VSRS(n,b,base)   REST_4VSRS(n,b,base); REST_4VSRS(n+4,b,base)
 #define REST_16VSRS(n,b,base)  REST_8VSRS(n,b,base); REST_8VSRS(n+8,b,base)
 #define REST_32VSRS(n,b,base)  REST_16VSRS(n,b,base); REST_16VSRS(n+16,b,base)
 /* Save the upper 32 VSRs (32-63) in the thread VSX region (0-31) */
-#define SAVE_VSRU(n,b,base)    li b,THREAD_VR0+(16*(n));  STXVD2X(n+32,b,base)
+#define SAVE_VSRU(n,b,base)    li b,THREAD_VR0+(16*(n));  STXVD2X(n+32,base,b)
 #define SAVE_2VSRSU(n,b,base)  SAVE_VSRU(n,b,base); SAVE_VSRU(n+1,b,base)
 #define SAVE_4VSRSU(n,b,base)  SAVE_2VSRSU(n,b,base); SAVE_2VSRSU(n+2,b,base)
 #define SAVE_8VSRSU(n,b,base)  SAVE_4VSRSU(n,b,base); SAVE_4VSRSU(n+4,b,base)
 #define SAVE_16VSRSU(n,b,base) SAVE_8VSRSU(n,b,base); SAVE_8VSRSU(n+8,b,base)
 #define SAVE_32VSRSU(n,b,base) SAVE_16VSRSU(n,b,base); SAVE_16VSRSU(n+16,b,base)
-#define REST_VSRU(n,b,base)    li b,THREAD_VR0+(16*(n)); LXVD2X(n+32,b,base)
+#define REST_VSRU(n,b,base)    li b,THREAD_VR0+(16*(n)); LXVD2X(n+32,base,b)
 #define REST_2VSRSU(n,b,base)  REST_VSRU(n,b,base); REST_VSRU(n+1,b,base)
 #define REST_4VSRSU(n,b,base)  REST_2VSRSU(n,b,base); REST_2VSRSU(n+2,b,base)
 #define REST_8VSRSU(n,b,base)  REST_4VSRSU(n,b,base); REST_4VSRSU(n+4,b,base)
@@ -375,8 +375,15 @@ END_FTR_SECTION_IFCLR(CPU_FTR_601)
 #define PPC440EP_ERR42
 #endif
 
-
-#if defined(CONFIG_BOOKE)
+/*
+ * toreal/fromreal/tophys/tovirt macros. 32-bit BookE makes them
+ * keep the address intact to be compatible with code shared with
+ * 32-bit classic.
+ *
+ * On the other hand, I find it useful to have them behave as expected
+ * by their name (ie always do the addition) on 64-bit BookE
+ */
+#if defined(CONFIG_BOOKE) && !defined(CONFIG_PPC64)
 #define toreal(rd)
 #define fromreal(rd)
 
@@ -426,10 +433,9 @@ END_FTR_SECTION_IFCLR(CPU_FTR_601)
        .previous
 #endif
 
-#ifdef CONFIG_PPC64
+#ifdef CONFIG_PPC_BOOK3S_64
 #define RFI            rfid
 #define MTMSRD(r)      mtmsrd  r
-
 #else
 #define FIX_SRR1(ra, rb)
 #ifndef CONFIG_40x
index 07630faae029c0f956c04868b56cab906f204ed6..6c3e1f4378d49efd93655a8d4d4d781cbd480682 100644 (file)
@@ -46,7 +46,7 @@
 #define        _PAGE_RW        0x040   /* software: Writes permitted */
 #define        _PAGE_DIRTY     0x080   /* software: dirty page */
 #define _PAGE_HWWRITE  0x100   /* hardware: Dirty & RW, set in exception */
-#define _PAGE_HWEXEC   0x200   /* hardware: EX permission */
+#define _PAGE_EXEC     0x200   /* hardware: EX permission */
 #define _PAGE_ACCESSED 0x400   /* software: R: page referenced */
 
 #define _PMD_PRESENT   0x400   /* PMD points to page of PTEs */
index 37e98bcf83e0150753466dd07bd08e24ae4fdc18..4192b9bad90164b41d928685547fa32ddf0aafd0 100644 (file)
@@ -78,7 +78,7 @@
 #define _PAGE_PRESENT  0x00000001              /* S: PTE valid */
 #define _PAGE_RW       0x00000002              /* S: Write permission */
 #define _PAGE_FILE     0x00000004              /* S: nonlinear file mapping */
-#define _PAGE_HWEXEC   0x00000004              /* H: Execute permission */
+#define _PAGE_EXEC     0x00000004              /* H: Execute permission */
 #define _PAGE_ACCESSED 0x00000008              /* S: Page referenced */
 #define _PAGE_DIRTY    0x00000010              /* S: Page dirty */
 #define _PAGE_SPECIAL  0x00000020              /* S: Special page */
index 8c6e31251034d853783152bdb36eaa245a37be36..94e979718dcf34011a1bcfb68c32a705d55cd4e3 100644 (file)
@@ -36,7 +36,6 @@
 /* These five software bits must be masked out when the entry is loaded
  * into the TLB.
  */
-#define _PAGE_EXEC     0x0008  /* software: i-cache coherency required */
 #define _PAGE_GUARDED  0x0010  /* software: guarded access */
 #define _PAGE_DIRTY    0x0020  /* software: page changed */
 #define _PAGE_RW       0x0040  /* software: user write access allowed */
diff --git a/arch/powerpc/include/asm/pte-book3e.h b/arch/powerpc/include/asm/pte-book3e.h
new file mode 100644 (file)
index 0000000..082d515
--- /dev/null
@@ -0,0 +1,84 @@
+#ifndef _ASM_POWERPC_PTE_BOOK3E_H
+#define _ASM_POWERPC_PTE_BOOK3E_H
+#ifdef __KERNEL__
+
+/* PTE bit definitions for processors compliant to the Book3E
+ * architecture 2.06 or later. The position of the PTE bits
+ * matches the HW definition of the optional Embedded Page Table
+ * category.
+ */
+
+/* Architected bits */
+#define _PAGE_PRESENT  0x000001 /* software: pte contains a translation */
+#define _PAGE_FILE     0x000002 /* (!present only) software: pte holds file offset */
+#define _PAGE_SW1      0x000002
+#define _PAGE_BAP_SR   0x000004
+#define _PAGE_BAP_UR   0x000008
+#define _PAGE_BAP_SW   0x000010
+#define _PAGE_BAP_UW   0x000020
+#define _PAGE_BAP_SX   0x000040
+#define _PAGE_BAP_UX   0x000080
+#define _PAGE_PSIZE_MSK        0x000f00
+#define _PAGE_PSIZE_4K 0x000200
+#define _PAGE_PSIZE_8K 0x000300
+#define _PAGE_PSIZE_16K        0x000400
+#define _PAGE_PSIZE_32K        0x000500
+#define _PAGE_PSIZE_64K        0x000600
+#define _PAGE_PSIZE_128K       0x000700
+#define _PAGE_PSIZE_256K       0x000800
+#define _PAGE_PSIZE_512K       0x000900
+#define _PAGE_PSIZE_1M 0x000a00
+#define _PAGE_PSIZE_2M 0x000b00
+#define _PAGE_PSIZE_4M 0x000c00
+#define _PAGE_PSIZE_8M 0x000d00
+#define _PAGE_PSIZE_16M        0x000e00
+#define _PAGE_PSIZE_32M        0x000f00
+#define _PAGE_DIRTY    0x001000 /* C: page changed */
+#define _PAGE_SW0      0x002000
+#define _PAGE_U3       0x004000
+#define _PAGE_U2       0x008000
+#define _PAGE_U1       0x010000
+#define _PAGE_U0       0x020000
+#define _PAGE_ACCESSED 0x040000
+#define _PAGE_LENDIAN  0x080000
+#define _PAGE_GUARDED  0x100000
+#define _PAGE_COHERENT 0x200000 /* M: enforce memory coherence */
+#define _PAGE_NO_CACHE 0x400000 /* I: cache inhibit */
+#define _PAGE_WRITETHRU        0x800000 /* W: cache write-through */
+
+/* "Higher level" linux bit combinations */
+#define _PAGE_EXEC             _PAGE_BAP_UX /* .. and was cache cleaned */
+#define _PAGE_RW               (_PAGE_BAP_SW | _PAGE_BAP_UW) /* User write permission */
+#define _PAGE_KERNEL_RW                (_PAGE_BAP_SW | _PAGE_BAP_SR | _PAGE_DIRTY)
+#define _PAGE_KERNEL_RO                (_PAGE_BAP_SR)
+#define _PAGE_KERNEL_RWX       (_PAGE_BAP_SW | _PAGE_BAP_SR | _PAGE_DIRTY | _PAGE_BAP_SX)
+#define _PAGE_KERNEL_ROX       (_PAGE_BAP_SR | _PAGE_BAP_SX)
+#define _PAGE_USER             (_PAGE_BAP_UR | _PAGE_BAP_SR) /* Can be read */
+
+#define _PAGE_HASHPTE  0
+#define _PAGE_BUSY     0
+
+#define _PAGE_SPECIAL  _PAGE_SW0
+
+/* Flags to be preserved on PTE modifications */
+#define _PAGE_HPTEFLAGS        _PAGE_BUSY
+
+/* Base page size */
+#ifdef CONFIG_PPC_64K_PAGES
+#define _PAGE_PSIZE    _PAGE_PSIZE_64K
+#define PTE_RPN_SHIFT  (28)
+#else
+#define _PAGE_PSIZE    _PAGE_PSIZE_4K
+#define        PTE_RPN_SHIFT   (24)
+#endif
+
+/* On 32-bit, we never clear the top part of the PTE */
+#ifdef CONFIG_PPC32
+#define _PTE_NONE_MASK 0xffffffff00000000ULL
+#define _PMD_PRESENT   0
+#define _PMD_PRESENT_MASK (PAGE_MASK)
+#define _PMD_BAD       (~PAGE_MASK)
+#endif
+
+#endif /* __KERNEL__ */
+#endif /*  _ASM_POWERPC_PTE_FSL_BOOKE_H */
index a7e210b6b48c347f4d7af601e56660cf824b1728..c3b65076a2635b1f43de1a7515492a529a6a74df 100644 (file)
@@ -13,9 +13,6 @@
 #ifndef _PAGE_HWWRITE
 #define _PAGE_HWWRITE  0
 #endif
-#ifndef _PAGE_HWEXEC
-#define _PAGE_HWEXEC   0
-#endif
 #ifndef _PAGE_EXEC
 #define _PAGE_EXEC     0
 #endif
@@ -34,6 +31,9 @@
 #ifndef _PAGE_4K_PFN
 #define _PAGE_4K_PFN           0
 #endif
+#ifndef _PAGE_SAO
+#define _PAGE_SAO      0
+#endif
 #ifndef _PAGE_PSIZE
 #define _PAGE_PSIZE            0
 #endif
 #define PMD_PAGE_SIZE(pmd)     bad_call_to_PMD_PAGE_SIZE()
 #endif
 #ifndef _PAGE_KERNEL_RO
-#define _PAGE_KERNEL_RO        0
+#define _PAGE_KERNEL_RO                0
+#endif
+#ifndef _PAGE_KERNEL_ROX
+#define _PAGE_KERNEL_ROX       (_PAGE_EXEC)
 #endif
 #ifndef _PAGE_KERNEL_RW
-#define _PAGE_KERNEL_RW        (_PAGE_DIRTY | _PAGE_RW | _PAGE_HWWRITE)
+#define _PAGE_KERNEL_RW                (_PAGE_DIRTY | _PAGE_RW | _PAGE_HWWRITE)
+#endif
+#ifndef _PAGE_KERNEL_RWX
+#define _PAGE_KERNEL_RWX       (_PAGE_DIRTY | _PAGE_RW | _PAGE_HWWRITE | _PAGE_EXEC)
 #endif
 #ifndef _PAGE_HPTEFLAGS
 #define _PAGE_HPTEFLAGS _PAGE_HASHPTE
@@ -93,8 +99,7 @@ extern unsigned long bad_call_to_PMD_PAGE_SIZE(void);
 #define PAGE_PROT_BITS (_PAGE_GUARDED | _PAGE_COHERENT | _PAGE_NO_CACHE | \
                         _PAGE_WRITETHRU | _PAGE_ENDIAN | _PAGE_4K_PFN | \
                         _PAGE_USER | _PAGE_ACCESSED | \
-                        _PAGE_RW | _PAGE_HWWRITE | _PAGE_DIRTY | \
-                        _PAGE_EXEC | _PAGE_HWEXEC)
+                        _PAGE_RW | _PAGE_HWWRITE | _PAGE_DIRTY | _PAGE_EXEC)
 
 /*
  * We define 2 sets of base prot bits, one for basic pages (ie,
@@ -151,11 +156,9 @@ extern unsigned long bad_call_to_PMD_PAGE_SIZE(void);
                                 _PAGE_NO_CACHE)
 #define PAGE_KERNEL_NCG        __pgprot(_PAGE_BASE_NC | _PAGE_KERNEL_RW | \
                                 _PAGE_NO_CACHE | _PAGE_GUARDED)
-#define PAGE_KERNEL_X  __pgprot(_PAGE_BASE | _PAGE_KERNEL_RW | _PAGE_EXEC | \
-                                _PAGE_HWEXEC)
+#define PAGE_KERNEL_X  __pgprot(_PAGE_BASE | _PAGE_KERNEL_RWX)
 #define PAGE_KERNEL_RO __pgprot(_PAGE_BASE | _PAGE_KERNEL_RO)
-#define PAGE_KERNEL_ROX        __pgprot(_PAGE_BASE | _PAGE_KERNEL_RO | _PAGE_EXEC | \
-                                _PAGE_HWEXEC)
+#define PAGE_KERNEL_ROX        __pgprot(_PAGE_BASE | _PAGE_KERNEL_ROX)
 
 /* Protection used for kernel text. We want the debuggers to be able to
  * set breakpoints anywhere, so don't write protect the kernel text
index 10820f58acf572355b973a62e5b9d1cb8a1886a5..2c12be5f677a1cf0468f0afcba993905dc1a7538 100644 (file)
@@ -23,7 +23,7 @@
 #define _PAGE_FILE     0x00002 /* S: when !present: nonlinear file mapping */
 #define _PAGE_RW       0x00004 /* S: Write permission (SW) */
 #define _PAGE_DIRTY    0x00008 /* S: Page dirty */
-#define _PAGE_HWEXEC   0x00010 /* H: SX permission */
+#define _PAGE_EXEC     0x00010 /* H: SX permission */
 #define _PAGE_ACCESSED 0x00020 /* S: Page referenced */
 
 #define _PAGE_ENDIAN   0x00040 /* H: E bit */
 #define _PAGE_WRITETHRU        0x00400 /* H: W bit */
 #define _PAGE_SPECIAL  0x00800 /* S: Special page */
 
-#ifdef CONFIG_PTE_64BIT
-/* ERPN in a PTE never gets cleared, ignore it */
-#define _PTE_NONE_MASK 0xffffffffffff0000ULL
-/* We extend the size of the PTE flags area when using 64-bit PTEs */
-#define PTE_RPN_SHIFT  (PAGE_SHIFT + 8)
-#endif
-
 #define _PMD_PRESENT   0
 #define _PMD_PRESENT_MASK (PAGE_MASK)
 #define _PMD_BAD       (~PAGE_MASK)
index 16e571c7f9efef1d00e6727e9c5ea7da1c1423f4..4aad4132d0a87fa3e677ebe00b05d0d317fe7292 100644 (file)
@@ -26,7 +26,6 @@
 #define _PAGE_WRITETHRU        0x040   /* W: cache write-through */
 #define _PAGE_DIRTY    0x080   /* C: page changed */
 #define _PAGE_ACCESSED 0x100   /* R: page referenced */
-#define _PAGE_EXEC     0x200   /* software: i-cache coherency required */
 #define _PAGE_RW       0x400   /* software: user write access allowed */
 #define _PAGE_SPECIAL  0x800   /* software: Special page */
 
index 1170267736d3adaf5c8f2d793b3cef4cba19c65c..6315edc205d8673e1db6702224b477cee0ea602e 100644 (file)
 #define MSR_RI         __MASK(MSR_RI_LG)       /* Recoverable Exception */
 #define MSR_LE         __MASK(MSR_LE_LG)       /* Little Endian */
 
-#ifdef CONFIG_PPC64
+#if defined(CONFIG_PPC_BOOK3S_64)
+/* Server variant */
 #define MSR_           MSR_ME | MSR_RI | MSR_IR | MSR_DR | MSR_ISF |MSR_HV
 #define MSR_KERNEL      MSR_ | MSR_SF
-
 #define MSR_USER32     MSR_ | MSR_PR | MSR_EE
 #define MSR_USER64     MSR_USER32 | MSR_SF
-
-#else /* 32-bit */
+#elif defined(CONFIG_PPC_BOOK3S_32) || defined(CONFIG_8xx)
 /* Default MSR for kernel mode. */
-#ifndef MSR_KERNEL     /* reg_booke.h also defines this */
 #define MSR_KERNEL     (MSR_ME|MSR_RI|MSR_IR|MSR_DR)
-#endif
-
 #define MSR_USER       (MSR_KERNEL|MSR_PR|MSR_EE)
 #endif
 
 #define MMCR0_PMC2_LOADMISSTIME        0x5
 #endif
 
+/*
+ * SPRG usage:
+ *
+ * All 64-bit:
+ *     - SPRG1 stores PACA pointer
+ *
+ * 64-bit server:
+ *     - SPRG0 unused (reserved for HV on Power4)
+ *     - SPRG2 scratch for exception vectors
+ *     - SPRG3 unused (user visible)
+ *
+ * 64-bit embedded
+ *     - SPRG0 generic exception scratch
+ *     - SPRG2 TLB exception stack
+ *     - SPRG3 unused (user visible)
+ *     - SPRG4 unused (user visible)
+ *     - SPRG6 TLB miss scratch (user visible, sorry !)
+ *     - SPRG7 critical exception scratch
+ *     - SPRG8 machine check exception scratch
+ *     - SPRG9 debug exception scratch
+ *
+ * All 32-bit:
+ *     - SPRG3 current thread_info pointer
+ *        (virtual on BookE, physical on others)
+ *
+ * 32-bit classic:
+ *     - SPRG0 scratch for exception vectors
+ *     - SPRG1 scratch for exception vectors
+ *     - SPRG2 indicator that we are in RTAS
+ *     - SPRG4 (603 only) pseudo TLB LRU data
+ *
+ * 32-bit 40x:
+ *     - SPRG0 scratch for exception vectors
+ *     - SPRG1 scratch for exception vectors
+ *     - SPRG2 scratch for exception vectors
+ *     - SPRG4 scratch for exception vectors (not 403)
+ *     - SPRG5 scratch for exception vectors (not 403)
+ *     - SPRG6 scratch for exception vectors (not 403)
+ *     - SPRG7 scratch for exception vectors (not 403)
+ *
+ * 32-bit 440 and FSL BookE:
+ *     - SPRG0 scratch for exception vectors
+ *     - SPRG1 scratch for exception vectors (*)
+ *     - SPRG2 scratch for crit interrupts handler
+ *     - SPRG4 scratch for exception vectors
+ *     - SPRG5 scratch for exception vectors
+ *     - SPRG6 scratch for machine check handler
+ *     - SPRG7 scratch for exception vectors
+ *     - SPRG9 scratch for debug vectors (e500 only)
+ *
+ *      Additionally, BookE separates "read" and "write"
+ *      of those registers. That allows to use the userspace
+ *      readable variant for reads, which can avoid a fault
+ *      with KVM type virtualization.
+ *
+ *      (*) Under KVM, the host SPRG1 is used to point to
+ *      the current VCPU data structure
+ *
+ * 32-bit 8xx:
+ *     - SPRG0 scratch for exception vectors
+ *     - SPRG1 scratch for exception vectors
+ *     - SPRG2 apparently unused but initialized
+ *
+ */
+#ifdef CONFIG_PPC64
+#define SPRN_SPRG_PACA                 SPRN_SPRG1
+#else
+#define SPRN_SPRG_THREAD       SPRN_SPRG3
+#endif
+
+#ifdef CONFIG_PPC_BOOK3S_64
+#define SPRN_SPRG_SCRATCH0     SPRN_SPRG2
+#endif
+
+#ifdef CONFIG_PPC_BOOK3E_64
+#define SPRN_SPRG_MC_SCRATCH   SPRN_SPRG8
+#define SPRN_SPRG_CRIT_SCRATCH SPRN_SPRG7
+#define SPRN_SPRG_DBG_SCRATCH  SPRN_SPRG9
+#define SPRN_SPRG_TLB_EXFRAME  SPRN_SPRG2
+#define SPRN_SPRG_TLB_SCRATCH  SPRN_SPRG6
+#define SPRN_SPRG_GEN_SCRATCH  SPRN_SPRG0
+#endif
+
+#ifdef CONFIG_PPC_BOOK3S_32
+#define SPRN_SPRG_SCRATCH0     SPRN_SPRG0
+#define SPRN_SPRG_SCRATCH1     SPRN_SPRG1
+#define SPRN_SPRG_RTAS         SPRN_SPRG2
+#define SPRN_SPRG_603_LRU      SPRN_SPRG4
+#endif
+
+#ifdef CONFIG_40x
+#define SPRN_SPRG_SCRATCH0     SPRN_SPRG0
+#define SPRN_SPRG_SCRATCH1     SPRN_SPRG1
+#define SPRN_SPRG_SCRATCH2     SPRN_SPRG2
+#define SPRN_SPRG_SCRATCH3     SPRN_SPRG4
+#define SPRN_SPRG_SCRATCH4     SPRN_SPRG5
+#define SPRN_SPRG_SCRATCH5     SPRN_SPRG6
+#define SPRN_SPRG_SCRATCH6     SPRN_SPRG7
+#endif
+
+#ifdef CONFIG_BOOKE
+#define SPRN_SPRG_RSCRATCH0    SPRN_SPRG0
+#define SPRN_SPRG_WSCRATCH0    SPRN_SPRG0
+#define SPRN_SPRG_RSCRATCH1    SPRN_SPRG1
+#define SPRN_SPRG_WSCRATCH1    SPRN_SPRG1
+#define SPRN_SPRG_RSCRATCH_CRIT        SPRN_SPRG2
+#define SPRN_SPRG_WSCRATCH_CRIT        SPRN_SPRG2
+#define SPRN_SPRG_RSCRATCH2    SPRN_SPRG4R
+#define SPRN_SPRG_WSCRATCH2    SPRN_SPRG4W
+#define SPRN_SPRG_RSCRATCH3    SPRN_SPRG5R
+#define SPRN_SPRG_WSCRATCH3    SPRN_SPRG5W
+#define SPRN_SPRG_RSCRATCH_MC  SPRN_SPRG6R
+#define SPRN_SPRG_WSCRATCH_MC  SPRN_SPRG6W
+#define SPRN_SPRG_RSCRATCH4    SPRN_SPRG7R
+#define SPRN_SPRG_WSCRATCH4    SPRN_SPRG7W
+#ifdef CONFIG_E200
+#define SPRN_SPRG_RSCRATCH_DBG SPRN_SPRG6R
+#define SPRN_SPRG_WSCRATCH_DBG SPRN_SPRG6W
+#else
+#define SPRN_SPRG_RSCRATCH_DBG SPRN_SPRG9
+#define SPRN_SPRG_WSCRATCH_DBG SPRN_SPRG9
+#endif
+#define SPRN_SPRG_RVCPU                SPRN_SPRG1
+#define SPRN_SPRG_WVCPU                SPRN_SPRG1
+#endif
+
+#ifdef CONFIG_8xx
+#define SPRN_SPRG_SCRATCH0     SPRN_SPRG0
+#define SPRN_SPRG_SCRATCH1     SPRN_SPRG1
+#endif
+
 /*
  * An mtfsf instruction with the L bit set. On CPUs that support this a
  * full 64bits of FPSCR is restored and on other CPUs the L bit is ignored.
index 6bcf364cbb2f7781fd9db556b8d073c14d1cbe32..3bf783505528ceb712c8858ac45252eaba65adcf 100644 (file)
 #define MSR_IS         MSR_IR  /* Instruction Space */
 #define MSR_DS         MSR_DR  /* Data Space */
 #define MSR_PMM                (1<<2)  /* Performance monitor mark bit */
+#define MSR_CM         (1<<31) /* Computation Mode (0=32-bit, 1=64-bit) */
 
-/* Default MSR for kernel mode. */
-#if defined (CONFIG_40x)
+#if defined(CONFIG_PPC_BOOK3E_64)
+#define MSR_           MSR_ME | MSR_CE
+#define MSR_KERNEL      MSR_ | MSR_CM
+#define MSR_USER32     MSR_ | MSR_PR | MSR_EE
+#define MSR_USER64     MSR_USER32 | MSR_CM
+#elif defined (CONFIG_40x)
 #define MSR_KERNEL     (MSR_ME|MSR_RI|MSR_IR|MSR_DR|MSR_CE)
-#elif defined(CONFIG_BOOKE)
+#define MSR_USER       (MSR_KERNEL|MSR_PR|MSR_EE)
+#else
 #define MSR_KERNEL     (MSR_ME|MSR_RI|MSR_CE)
+#define MSR_USER       (MSR_KERNEL|MSR_PR|MSR_EE)
 #endif
 
 /* Special Purpose Registers (SPRNs)*/
 #define SPRN_DECAR     0x036   /* Decrementer Auto Reload Register */
 #define SPRN_IVPR      0x03F   /* Interrupt Vector Prefix Register */
 #define SPRN_USPRG0    0x100   /* User Special Purpose Register General 0 */
+#define SPRN_SPRG3R    0x103   /* Special Purpose Register General 3 Read */
 #define SPRN_SPRG4R    0x104   /* Special Purpose Register General 4 Read */
 #define SPRN_SPRG5R    0x105   /* Special Purpose Register General 5 Read */
 #define SPRN_SPRG6R    0x106   /* Special Purpose Register General 6 Read */
 #define SPRN_SPRG5W    0x115   /* Special Purpose Register General 5 Write */
 #define SPRN_SPRG6W    0x116   /* Special Purpose Register General 6 Write */
 #define SPRN_SPRG7W    0x117   /* Special Purpose Register General 7 Write */
+#define SPRN_EPCR      0x133   /* Embedded Processor Control Register */
 #define SPRN_DBCR2     0x136   /* Debug Control Register 2 */
 #define SPRN_IAC3      0x13A   /* Instruction Address Compare 3 */
 #define SPRN_IAC4      0x13B   /* Instruction Address Compare 4 */
 #define SPRN_DVC1      0x13E   /* Data Value Compare Register 1 */
 #define SPRN_DVC2      0x13F   /* Data Value Compare Register 2 */
+#define SPRN_MAS8      0x155   /* MMU Assist Register 8 */
+#define SPRN_TLB0PS    0x158   /* TLB 0 Page Size Register */
+#define SPRN_MAS5_MAS6 0x15c   /* MMU Assist Register 5 || 6 */
+#define SPRN_MAS8_MAS1 0x15d   /* MMU Assist Register 8 || 1 */
+#define SPRN_MAS7_MAS3 0x174   /* MMU Assist Register 7 || 3 */
+#define SPRN_MAS0_MAS1 0x175   /* MMU Assist Register 0 || 1 */
 #define SPRN_IVOR0     0x190   /* Interrupt Vector Offset Register 0 */
 #define SPRN_IVOR1     0x191   /* Interrupt Vector Offset Register 1 */
 #define SPRN_IVOR2     0x192   /* Interrupt Vector Offset Register 2 */
 #define SPRN_PID2      0x27A   /* Process ID Register 2 */
 #define SPRN_TLB0CFG   0x2B0   /* TLB 0 Config Register */
 #define SPRN_TLB1CFG   0x2B1   /* TLB 1 Config Register */
+#define SPRN_TLB2CFG   0x2B2   /* TLB 2 Config Register */
+#define SPRN_TLB3CFG   0x2B3   /* TLB 3 Config Register */
 #define SPRN_EPR       0x2BE   /* External Proxy Register */
 #define SPRN_CCR1      0x378   /* Core Configuration Register 1 */
 #define SPRN_ZPR       0x3B0   /* Zone Protection Register (40x) */
 #define L2CSR0_L2LOA   0x00000080      /* L2 Cache Lock Overflow Allocate */
 #define L2CSR0_L2LO    0x00000020      /* L2 Cache Lock Overflow */
 
-/* Bit definitions for MMUCSR0 */
-#define MMUCSR0_TLB1FI 0x00000002      /* TLB1 Flash invalidate */
-#define MMUCSR0_TLB0FI 0x00000004      /* TLB0 Flash invalidate */
-#define MMUCSR0_TLB2FI 0x00000040      /* TLB2 Flash invalidate */
-#define MMUCSR0_TLB3FI 0x00000020      /* TLB3 Flash invalidate */
-
 /* Bit definitions for SGR. */
 #define SGR_NORMAL     0               /* Speculative fetching allowed. */
 #define SGR_GUARDED    1               /* Speculative fetching disallowed. */
 
+/* Bit definitions for EPCR */
+#define SPRN_EPCR_EXTGS                0x80000000      /* External Input interrupt
+                                                * directed to Guest state */
+#define SPRN_EPCR_DTLBGS       0x40000000      /* Data TLB Error interrupt
+                                                * directed to guest state */
+#define SPRN_EPCR_ITLBGS       0x20000000      /* Instr. TLB error interrupt
+                                                * directed to guest state */
+#define SPRN_EPCR_DSIGS                0x10000000      /* Data Storage interrupt
+                                                * directed to guest state */
+#define SPRN_EPCR_ISIGS                0x08000000      /* Instr. Storage interrupt
+                                                * directed to guest state */
+#define SPRN_EPCR_DUVD         0x04000000      /* Disable Hypervisor Debug */
+#define SPRN_EPCR_ICM          0x02000000      /* Interrupt computation mode
+                                                * (copied to MSR:CM on intr) */
+#define SPRN_EPCR_GICM         0x01000000      /* Guest Interrupt Comp. mode */
+#define SPRN_EPCR_DGTMI                0x00800000      /* Disable TLB Guest Management
+                                                * instructions */
+#define SPRN_EPCR_DMIUH                0x00400000      /* Disable MAS Interrupt updates
+                                                * for hypervisor */
+
+
 /*
  * The IBM-403 is an even more odd special case, as it is much
  * older than the IBM-405 series.  We put these down here incase someone
index 817fac0a0714a8705d6b6d8ce1bd85ef85523822..dae19342f0b90f3d2083d92f0834ce0053817118 100644 (file)
@@ -1,6 +1,6 @@
 #ifndef _ASM_POWERPC_SETUP_H
 #define _ASM_POWERPC_SETUP_H
 
-#define COMMAND_LINE_SIZE      512
+#include <asm-generic/setup.h>
 
 #endif /* _ASM_POWERPC_SETUP_H */
index c25f73d1d84203e0393d26d5da07e390c79417e5..c0d3b8af93190bc01f6e962dae3a0a76fb8a8179 100644 (file)
@@ -148,6 +148,16 @@ extern struct smp_ops_t *smp_ops;
 extern void arch_send_call_function_single_ipi(int cpu);
 extern void arch_send_call_function_ipi(cpumask_t mask);
 
+/* Definitions relative to the secondary CPU spin loop
+ * and entry point. Not all of them exist on both 32 and
+ * 64-bit but defining them all here doesn't harm
+ */
+extern void generic_secondary_smp_init(void);
+extern void generic_secondary_thread_init(void);
+extern unsigned long __secondary_hold_spinloop;
+extern unsigned long __secondary_hold_acknowledge;
+extern char __secondary_hold;
+
 #endif /* __ASSEMBLY__ */
 
 #endif /* __KERNEL__ */
index 30891d6e2bc1b89d7d7c40470fcfc7d5c94bee9b..8979d4cd3d70500fc1f0dbada65b9f834e020faa 100644 (file)
 
 #include <linux/swiotlb.h>
 
-extern struct dma_mapping_ops swiotlb_dma_ops;
-extern struct dma_mapping_ops swiotlb_pci_dma_ops;
-
-int swiotlb_arch_address_needs_mapping(struct device *, dma_addr_t,
-                                      size_t size);
+extern struct dma_map_ops swiotlb_dma_ops;
 
 static inline void dma_mark_clean(void *addr, size_t size) {}
 
 extern unsigned int ppc_swiotlb_enable;
 int __init swiotlb_setup_bus_notifier(void);
 
+extern void pci_dma_dev_setup_swiotlb(struct pci_dev *pdev);
+
 #endif /* __ASM_SWIOTLB_H */
index 370600ca2765332ec542ff0c269aa3d5b614c9f0..ed24bd92fe49fe2f9f64f350a74c8851261531b4 100644 (file)
@@ -95,8 +95,8 @@ SYSCALL(reboot)
 SYSX(sys_ni_syscall,compat_sys_old_readdir,sys_old_readdir)
 SYSCALL_SPU(mmap)
 SYSCALL_SPU(munmap)
-SYSCALL_SPU(truncate)
-SYSCALL_SPU(ftruncate)
+COMPAT_SYS_SPU(truncate)
+COMPAT_SYS_SPU(ftruncate)
 SYSCALL_SPU(fchmod)
 SYSCALL_SPU(fchown)
 COMPAT_SYS_SPU(getpriority)
index e20ff7541f364812bbe8259e73170ae603ea8abb..e2b428b0f7babd3626e880be36b45a682a95b1ab 100644 (file)
 
 #include <linux/pagemap.h>
 
-struct mmu_gather;
-
 #define tlb_start_vma(tlb, vma)        do { } while (0)
 #define tlb_end_vma(tlb, vma)  do { } while (0)
 
-#if !defined(CONFIG_PPC_STD_MMU)
-
-#define tlb_flush(tlb)                 flush_tlb_mm((tlb)->mm)
-
-#elif defined(__powerpc64__)
-
-extern void pte_free_finish(void);
-
-static inline void tlb_flush(struct mmu_gather *tlb)
-{
-       struct ppc64_tlb_batch *tlbbatch = &__get_cpu_var(ppc64_tlb_batch);
-
-       /* If there's a TLB batch pending, then we must flush it because the
-        * pages are going to be freed and we really don't want to have a CPU
-        * access a freed page because it has a stale TLB
-        */
-       if (tlbbatch->index)
-               __flush_tlb_pending(tlbbatch);
-
-       pte_free_finish();
-}
-
-#else
-
 extern void tlb_flush(struct mmu_gather *tlb);
 
-#endif
-
 /* Get the generic bits... */
 #include <asm-generic/tlb.h>
 
-#if !defined(CONFIG_PPC_STD_MMU) || defined(__powerpc64__)
-
-#define __tlb_remove_tlb_entry(tlb, pte, address) do { } while (0)
-
-#else
 extern void flush_hash_entry(struct mm_struct *mm, pte_t *ptep,
                             unsigned long address);
 
 static inline void __tlb_remove_tlb_entry(struct mmu_gather *tlb, pte_t *ptep,
-                                       unsigned long address)
+                                         unsigned long address)
 {
+#ifdef CONFIG_PPC_STD_MMU_32
        if (pte_val(*ptep) & _PAGE_HASHPTE)
                flush_hash_entry(tlb->mm, ptep, address);
+#endif
 }
 
-#endif
 #endif /* __KERNEL__ */
 #endif /* __ASM_POWERPC_TLB_H */
index abbe3419d1dd244e57d543a58f4a25bb55502da4..d50a380b2b6fd8604285264f0dc3054986e0c6bc 100644 (file)
@@ -6,7 +6,7 @@
  *
  *  - flush_tlb_mm(mm) flushes the specified mm context TLB's
  *  - flush_tlb_page(vma, vmaddr) flushes one page
- *  - local_flush_tlb_mm(mm) flushes the specified mm context on
+ *  - local_flush_tlb_mm(mm, full) flushes the specified mm context on
  *                           the local processor
  *  - local_flush_tlb_page(vma, vmaddr) flushes one page on the local processor
  *  - flush_tlb_page_nohash(vma, vmaddr) flushes one page if SW loaded TLB
@@ -29,7 +29,8 @@
  * specific tlbie's
  */
 
-#include <linux/mm.h>
+struct vm_area_struct;
+struct mm_struct;
 
 #define MMU_NO_CONTEXT         ((unsigned int)-1)
 
@@ -40,12 +41,18 @@ extern void flush_tlb_kernel_range(unsigned long start, unsigned long end);
 extern void local_flush_tlb_mm(struct mm_struct *mm);
 extern void local_flush_tlb_page(struct vm_area_struct *vma, unsigned long vmaddr);
 
+extern void __local_flush_tlb_page(struct mm_struct *mm, unsigned long vmaddr,
+                                  int tsize, int ind);
+
 #ifdef CONFIG_SMP
 extern void flush_tlb_mm(struct mm_struct *mm);
 extern void flush_tlb_page(struct vm_area_struct *vma, unsigned long vmaddr);
+extern void __flush_tlb_page(struct mm_struct *mm, unsigned long vmaddr,
+                            int tsize, int ind);
 #else
 #define flush_tlb_mm(mm)               local_flush_tlb_mm(mm)
 #define flush_tlb_page(vma,addr)       local_flush_tlb_page(vma,addr)
+#define __flush_tlb_page(mm,addr,p,i)  __local_flush_tlb_page(mm,addr,p,i)
 #endif
 #define flush_tlb_page_nohash(vma,addr)        flush_tlb_page(vma,addr)
 
index 26fc449bd9899cda5d760a0a5d63f8b112f7563b..dc0419b66f17ac1f676bf247f8706b0a1a08b9f2 100644 (file)
@@ -7,9 +7,8 @@
 #define VDSO32_LBASE   0x100000
 #define VDSO64_LBASE   0x100000
 
-/* Default map addresses */
+/* Default map addresses for 32bit vDSO */
 #define VDSO32_MBASE   VDSO32_LBASE
-#define VDSO64_MBASE   VDSO64_LBASE
 
 #define VDSO_VERSION_STRING    LINUX_2.6.15
 
index 9619285f64e84b3c6da0e542684c1d1386671271..569f79ccd31062de7054ec6872ac485d12320deb 100644 (file)
@@ -33,10 +33,10 @@ obj-y                               := cputable.o ptrace.o syscalls.o \
 obj-y                          += vdso32/
 obj-$(CONFIG_PPC64)            += setup_64.o sys_ppc32.o \
                                   signal_64.o ptrace32.o \
-                                  paca.o cpu_setup_ppc970.o \
-                                  cpu_setup_pa6t.o \
-                                  firmware.o nvram_64.o
+                                  paca.o nvram_64.o firmware.o
+obj-$(CONFIG_PPC_BOOK3S_64)    += cpu_setup_ppc970.o cpu_setup_pa6t.o
 obj64-$(CONFIG_RELOCATABLE)    += reloc_64.o
+obj-$(CONFIG_PPC_BOOK3E_64)    += exceptions-64e.o
 obj-$(CONFIG_PPC64)            += vdso64/
 obj-$(CONFIG_ALTIVEC)          += vecemu.o
 obj-$(CONFIG_PPC_970_NAP)      += idle_power4.o
@@ -63,8 +63,8 @@ obj-$(CONFIG_MODULES)         += module.o module_$(CONFIG_WORD_SIZE).o
 obj-$(CONFIG_44x)              += cpu_setup_44x.o
 obj-$(CONFIG_FSL_BOOKE)                += cpu_setup_fsl_booke.o dbell.o
 
-extra-$(CONFIG_PPC_STD_MMU)    := head_32.o
-extra-$(CONFIG_PPC64)          := head_64.o
+extra-y                                := head_$(CONFIG_WORD_SIZE).o
+extra-$(CONFIG_PPC_BOOK3E_32)  := head_new_booke.o
 extra-$(CONFIG_40x)            := head_40x.o
 extra-$(CONFIG_44x)            := head_44x.o
 extra-$(CONFIG_FSL_BOOKE)      := head_fsl_booke.o
@@ -88,7 +88,7 @@ obj-$(CONFIG_SWIOTLB)         += dma-swiotlb.o
 
 pci64-$(CONFIG_PPC64)          += pci_dn.o isa-bridge.o
 obj-$(CONFIG_PCI)              += pci_$(CONFIG_WORD_SIZE).o $(pci64-y) \
-                                  pci-common.o
+                                  pci-common.o pci_of_scan.o
 obj-$(CONFIG_PCI_MSI)          += msi.o
 obj-$(CONFIG_KEXEC)            += machine_kexec.o crash.o \
                                   machine_kexec_$(CONFIG_WORD_SIZE).o
@@ -115,6 +115,13 @@ ifneq ($(CONFIG_XMON)$(CONFIG_KEXEC),)
 obj-y                          += ppc_save_regs.o
 endif
 
+# Disable GCOV in odd or sensitive code
+GCOV_PROFILE_prom_init.o := n
+GCOV_PROFILE_ftrace.o := n
+GCOV_PROFILE_machine_kexec_64.o := n
+GCOV_PROFILE_machine_kexec_32.o := n
+GCOV_PROFILE_kprobes.o := n
+
 extra-$(CONFIG_PPC_FPU)                += fpu.o
 extra-$(CONFIG_ALTIVEC)                += vector.o
 extra-$(CONFIG_PPC64)          += entry_64.o
index 197b15646eeb9a999c80f5b22bf36aa500a42296..f0df285f0f87acd4804a542a0388ee393fe9e042 100644 (file)
 #include <linux/kvm_host.h>
 #endif
 
+#ifdef CONFIG_PPC32
 #if defined(CONFIG_BOOKE) || defined(CONFIG_40x)
 #include "head_booke.h"
 #endif
+#endif
 
 #if defined(CONFIG_FSL_BOOKE)
 #include "../mm/mmu_decl.h"
@@ -140,6 +142,20 @@ int main(void)
                                            context.high_slices_psize));
        DEFINE(MMUPSIZEDEFSIZE, sizeof(struct mmu_psize_def));
 #endif /* CONFIG_PPC_MM_SLICES */
+
+#ifdef CONFIG_PPC_BOOK3E
+       DEFINE(PACAPGD, offsetof(struct paca_struct, pgd));
+       DEFINE(PACA_KERNELPGD, offsetof(struct paca_struct, kernel_pgd));
+       DEFINE(PACA_EXGEN, offsetof(struct paca_struct, exgen));
+       DEFINE(PACA_EXTLB, offsetof(struct paca_struct, extlb));
+       DEFINE(PACA_EXMC, offsetof(struct paca_struct, exmc));
+       DEFINE(PACA_EXCRIT, offsetof(struct paca_struct, excrit));
+       DEFINE(PACA_EXDBG, offsetof(struct paca_struct, exdbg));
+       DEFINE(PACA_MC_STACK, offsetof(struct paca_struct, mc_kstack));
+       DEFINE(PACA_CRIT_STACK, offsetof(struct paca_struct, crit_kstack));
+       DEFINE(PACA_DBG_STACK, offsetof(struct paca_struct, dbg_kstack));
+#endif /* CONFIG_PPC_BOOK3E */
+
 #ifdef CONFIG_PPC_STD_MMU_64
        DEFINE(PACASTABREAL, offsetof(struct paca_struct, stab_real));
        DEFINE(PACASTABVIRT, offsetof(struct paca_struct, stab_addr));
@@ -262,6 +278,7 @@ int main(void)
        DEFINE(_SRR1, STACK_FRAME_OVERHEAD+sizeof(struct pt_regs)+8);
 #endif /* CONFIG_PPC64 */
 
+#if defined(CONFIG_PPC32)
 #if defined(CONFIG_BOOKE) || defined(CONFIG_40x)
        DEFINE(EXC_LVL_SIZE, STACK_EXC_LVL_FRAME_SIZE);
        DEFINE(MAS0, STACK_INT_FRAME_SIZE+offsetof(struct exception_regs, mas0));
@@ -280,7 +297,7 @@ int main(void)
        DEFINE(_DSRR1, STACK_INT_FRAME_SIZE+offsetof(struct exception_regs, dsrr1));
        DEFINE(SAVED_KSP_LIMIT, STACK_INT_FRAME_SIZE+offsetof(struct exception_regs, saved_ksp_limit));
 #endif
-
+#endif
        DEFINE(CLONE_VM, CLONE_VM);
        DEFINE(CLONE_UNTRACED, CLONE_UNTRACED);
 
index 1e9949e6885695f60aec86c6f7bd0b82302c753e..55cba4a8a9599031d4b81202a61de73b4cfa88ec 100644 (file)
@@ -21,7 +21,7 @@ _GLOBAL(__setup_cpu_603)
        mflr    r4
 BEGIN_MMU_FTR_SECTION
        li      r10,0
-       mtspr   SPRN_SPRG4,r10          /* init SW LRU tracking */
+       mtspr   SPRN_SPRG_603_LRU,r10           /* init SW LRU tracking */
 END_MMU_FTR_SECTION_IFSET(MMU_FTR_NEED_DTLB_SW_LRU)
 BEGIN_FTR_SECTION
        bl      __init_fpu_registers
index 4a24a2fc45740fc5b0622ec35c7550247be7f457..0b9c9135922e3980e1a547fb6a5778c5c9e8caba 100644 (file)
@@ -89,11 +89,15 @@ extern void __restore_cpu_power7(void);
 #define COMMON_USER_PA6T       (COMMON_USER_PPC64 | PPC_FEATURE_PA6T |\
                                 PPC_FEATURE_TRUE_LE | \
                                 PPC_FEATURE_HAS_ALTIVEC_COMP)
+#ifdef CONFIG_PPC_BOOK3E_64
+#define COMMON_USER_BOOKE      (COMMON_USER_PPC64 | PPC_FEATURE_BOOKE)
+#else
 #define COMMON_USER_BOOKE      (PPC_FEATURE_32 | PPC_FEATURE_HAS_MMU | \
                                 PPC_FEATURE_BOOKE)
+#endif
 
 static struct cpu_spec __initdata cpu_specs[] = {
-#ifdef CONFIG_PPC64
+#ifdef CONFIG_PPC_BOOK3S_64
        {       /* Power3 */
                .pvr_mask               = 0xffff0000,
                .pvr_value              = 0x00400000,
@@ -508,7 +512,8 @@ static struct cpu_spec __initdata cpu_specs[] = {
                .machine_check          = machine_check_generic,
                .platform               = "power4",
        }
-#endif /* CONFIG_PPC64 */
+#endif /* CONFIG_PPC_BOOK3S_64 */
+
 #ifdef CONFIG_PPC32
 #if CLASSIC_PPC
        {       /* 601 */
@@ -1630,7 +1635,7 @@ static struct cpu_spec __initdata cpu_specs[] = {
                .platform               = "ppc440",
        },
        { /* 460EX */
-               .pvr_mask               = 0xffff0002,
+               .pvr_mask               = 0xffff0006,
                .pvr_value              = 0x13020002,
                .cpu_name               = "460EX",
                .cpu_features           = CPU_FTRS_440x6,
@@ -1642,8 +1647,21 @@ static struct cpu_spec __initdata cpu_specs[] = {
                .machine_check          = machine_check_440A,
                .platform               = "ppc440",
        },
+       { /* 460EX Rev B */
+               .pvr_mask               = 0xffff0007,
+               .pvr_value              = 0x13020004,
+               .cpu_name               = "460EX Rev. B",
+               .cpu_features           = CPU_FTRS_440x6,
+               .cpu_user_features      = COMMON_USER_BOOKE | PPC_FEATURE_HAS_FPU,
+               .mmu_features           = MMU_FTR_TYPE_44x,
+               .icache_bsize           = 32,
+               .dcache_bsize           = 32,
+               .cpu_setup              = __setup_cpu_460ex,
+               .machine_check          = machine_check_440A,
+               .platform               = "ppc440",
+       },
        { /* 460GT */
-               .pvr_mask               = 0xffff0002,
+               .pvr_mask               = 0xffff0006,
                .pvr_value              = 0x13020000,
                .cpu_name               = "460GT",
                .cpu_features           = CPU_FTRS_440x6,
@@ -1655,6 +1673,19 @@ static struct cpu_spec __initdata cpu_specs[] = {
                .machine_check          = machine_check_440A,
                .platform               = "ppc440",
        },
+       { /* 460GT Rev B */
+               .pvr_mask               = 0xffff0007,
+               .pvr_value              = 0x13020005,
+               .cpu_name               = "460GT Rev. B",
+               .cpu_features           = CPU_FTRS_440x6,
+               .cpu_user_features      = COMMON_USER_BOOKE | PPC_FEATURE_HAS_FPU,
+               .mmu_features           = MMU_FTR_TYPE_44x,
+               .icache_bsize           = 32,
+               .dcache_bsize           = 32,
+               .cpu_setup              = __setup_cpu_460gt,
+               .machine_check          = machine_check_440A,
+               .platform               = "ppc440",
+       },
        { /* 460SX */
                .pvr_mask               = 0xffffff00,
                .pvr_value              = 0x13541800,
@@ -1797,6 +1828,29 @@ static struct cpu_spec __initdata cpu_specs[] = {
        }
 #endif /* CONFIG_E500 */
 #endif /* CONFIG_PPC32 */
+
+#ifdef CONFIG_PPC_BOOK3E_64
+       {       /* This is a default entry to get going, to be replaced by
+                * a real one at some stage
+                */
+#define CPU_FTRS_BASE_BOOK3E   (CPU_FTR_USE_TB | \
+           CPU_FTR_PPCAS_ARCH_V2 | CPU_FTR_SMT | \
+           CPU_FTR_NODSISRALIGN | CPU_FTR_NOEXECUTE)
+               .pvr_mask               = 0x00000000,
+               .pvr_value              = 0x00000000,
+               .cpu_name               = "Book3E",
+               .cpu_features           = CPU_FTRS_BASE_BOOK3E,
+               .cpu_user_features      = COMMON_USER_PPC64,
+               .mmu_features           = MMU_FTR_TYPE_3E | MMU_FTR_USE_TLBILX |
+                                         MMU_FTR_USE_TLBIVAX_BCAST |
+                                         MMU_FTR_LOCK_BCAST_INVAL,
+               .icache_bsize           = 64,
+               .dcache_bsize           = 64,
+               .num_pmcs               = 0,
+               .machine_check          = machine_check_generic,
+               .platform               = "power6",
+       },
+#endif
 };
 
 static struct cpu_spec the_cpu_spec;
index 2983adac8cc392d6788b23fdd19f2f16eda3e510..87ddb3fb948c52772abdd9331f96be68797dd277 100644 (file)
@@ -89,7 +89,7 @@ static int dma_iommu_dma_supported(struct device *dev, u64 mask)
                return 1;
 }
 
-struct dma_mapping_ops dma_iommu_ops = {
+struct dma_map_ops dma_iommu_ops = {
        .alloc_coherent = dma_iommu_alloc_coherent,
        .free_coherent  = dma_iommu_free_coherent,
        .map_sg         = dma_iommu_map_sg,
index e8a57de85bcfd0bd72160773d3977356685f94b0..e96cbbd9b449874e09dc38288abead50c8db1673 100644 (file)
 int swiotlb __read_mostly;
 unsigned int ppc_swiotlb_enable;
 
-/*
- * Determine if an address is reachable by a pci device, or if we must bounce.
- */
-static int
-swiotlb_pci_addr_needs_map(struct device *hwdev, dma_addr_t addr, size_t size)
-{
-       dma_addr_t max;
-       struct pci_controller *hose;
-       struct pci_dev *pdev = to_pci_dev(hwdev);
-
-       hose = pci_bus_to_host(pdev->bus);
-       max = hose->dma_window_base_cur + hose->dma_window_size;
-
-       /* check that we're within mapped pci window space */
-       if ((addr + size > max) | (addr < hose->dma_window_base_cur))
-               return 1;
-
-       return 0;
-}
-
 /*
  * At the moment, all platforms that use this code only require
  * swiotlb to be used if we're operating on HIGHMEM.  Since
@@ -51,7 +31,7 @@ swiotlb_pci_addr_needs_map(struct device *hwdev, dma_addr_t addr, size_t size)
  * map_page, and unmap_page on highmem, use normal dma_ops
  * for everything else.
  */
-struct dma_mapping_ops swiotlb_dma_ops = {
+struct dma_map_ops swiotlb_dma_ops = {
        .alloc_coherent = dma_direct_alloc_coherent,
        .free_coherent = dma_direct_free_coherent,
        .map_sg = swiotlb_map_sg_attrs,
@@ -62,33 +42,34 @@ struct dma_mapping_ops swiotlb_dma_ops = {
        .sync_single_range_for_cpu = swiotlb_sync_single_range_for_cpu,
        .sync_single_range_for_device = swiotlb_sync_single_range_for_device,
        .sync_sg_for_cpu = swiotlb_sync_sg_for_cpu,
-       .sync_sg_for_device = swiotlb_sync_sg_for_device
+       .sync_sg_for_device = swiotlb_sync_sg_for_device,
+       .mapping_error = swiotlb_dma_mapping_error,
 };
 
-struct dma_mapping_ops swiotlb_pci_dma_ops = {
-       .alloc_coherent = dma_direct_alloc_coherent,
-       .free_coherent = dma_direct_free_coherent,
-       .map_sg = swiotlb_map_sg_attrs,
-       .unmap_sg = swiotlb_unmap_sg_attrs,
-       .dma_supported = swiotlb_dma_supported,
-       .map_page = swiotlb_map_page,
-       .unmap_page = swiotlb_unmap_page,
-       .addr_needs_map = swiotlb_pci_addr_needs_map,
-       .sync_single_range_for_cpu = swiotlb_sync_single_range_for_cpu,
-       .sync_single_range_for_device = swiotlb_sync_single_range_for_device,
-       .sync_sg_for_cpu = swiotlb_sync_sg_for_cpu,
-       .sync_sg_for_device = swiotlb_sync_sg_for_device
-};
+void pci_dma_dev_setup_swiotlb(struct pci_dev *pdev)
+{
+       struct pci_controller *hose;
+       struct dev_archdata *sd;
+
+       hose = pci_bus_to_host(pdev->bus);
+       sd = &pdev->dev.archdata;
+       sd->max_direct_dma_addr =
+               hose->dma_window_base_cur + hose->dma_window_size;
+}
 
 static int ppc_swiotlb_bus_notify(struct notifier_block *nb,
                                  unsigned long action, void *data)
 {
        struct device *dev = data;
+       struct dev_archdata *sd;
 
        /* We are only intereted in device addition */
        if (action != BUS_NOTIFY_ADD_DEVICE)
                return 0;
 
+       sd = &dev->archdata;
+       sd->max_direct_dma_addr = 0;
+
        /* May need to bounce if the device can't address all of DRAM */
        if (dma_get_mask(dev) < lmb_end_of_DRAM())
                set_dma_ops(dev, &swiotlb_dma_ops);
index ccf129d47d84d26ff702bf7c5c507a2f206ea5a5..21b784d7e7d059f488b5685c052af8f7652696be 100644 (file)
@@ -7,6 +7,7 @@
 
 #include <linux/device.h>
 #include <linux/dma-mapping.h>
+#include <linux/dma-debug.h>
 #include <linux/lmb.h>
 #include <asm/bug.h>
 #include <asm/abs_addr.h>
@@ -140,7 +141,7 @@ static inline void dma_direct_sync_single_range(struct device *dev,
 }
 #endif
 
-struct dma_mapping_ops dma_direct_ops = {
+struct dma_map_ops dma_direct_ops = {
        .alloc_coherent = dma_direct_alloc_coherent,
        .free_coherent  = dma_direct_free_coherent,
        .map_sg         = dma_direct_map_sg,
@@ -156,3 +157,13 @@ struct dma_mapping_ops dma_direct_ops = {
 #endif
 };
 EXPORT_SYMBOL(dma_direct_ops);
+
+#define PREALLOC_DMA_DEBUG_ENTRIES (1 << 16)
+
+static int __init dma_init(void)
+{
+       dma_debug_init(PREALLOC_DMA_DEBUG_ENTRIES);
+
+       return 0;
+}
+fs_initcall(dma_init);
index 3cadba60a4b6c5ff88f964b32e1298e49c48b542..1175a8539e6cf4b0d0e623c7cccba5db9329d955 100644 (file)
@@ -88,7 +88,7 @@ crit_transfer_to_handler:
        mfspr   r0,SPRN_SRR1
        stw     r0,_SRR1(r11)
 
-       mfspr   r8,SPRN_SPRG3
+       mfspr   r8,SPRN_SPRG_THREAD
        lwz     r0,KSP_LIMIT(r8)
        stw     r0,SAVED_KSP_LIMIT(r11)
        rlwimi  r0,r1,0,0,(31-THREAD_SHIFT)
@@ -108,7 +108,7 @@ crit_transfer_to_handler:
        mfspr   r0,SPRN_SRR1
        stw     r0,crit_srr1@l(0)
 
-       mfspr   r8,SPRN_SPRG3
+       mfspr   r8,SPRN_SPRG_THREAD
        lwz     r0,KSP_LIMIT(r8)
        stw     r0,saved_ksp_limit@l(0)
        rlwimi  r0,r1,0,0,(31-THREAD_SHIFT)
@@ -138,7 +138,7 @@ transfer_to_handler:
        mfspr   r2,SPRN_XER
        stw     r12,_CTR(r11)
        stw     r2,_XER(r11)
-       mfspr   r12,SPRN_SPRG3
+       mfspr   r12,SPRN_SPRG_THREAD
        addi    r2,r12,-THREAD
        tovirt(r2,r2)                   /* set r2 to current */
        beq     2f                      /* if from user, fix up THREAD.regs */
@@ -680,7 +680,7 @@ END_FTR_SECTION_IFSET(CPU_FTR_SPE)
 
        tophys(r0,r4)
        CLR_TOP32(r0)
-       mtspr   SPRN_SPRG3,r0   /* Update current THREAD phys addr */
+       mtspr   SPRN_SPRG_THREAD,r0     /* Update current THREAD phys addr */
        lwz     r1,KSP(r4)      /* Load new stack pointer */
 
        /* save the old current 'last' for return value */
@@ -1057,7 +1057,7 @@ exc_exit_restart_end:
 #ifdef CONFIG_40x
        .globl  ret_from_crit_exc
 ret_from_crit_exc:
-       mfspr   r9,SPRN_SPRG3
+       mfspr   r9,SPRN_SPRG_THREAD
        lis     r10,saved_ksp_limit@ha;
        lwz     r10,saved_ksp_limit@l(r10);
        tovirt(r9,r9);
@@ -1074,7 +1074,7 @@ ret_from_crit_exc:
 #ifdef CONFIG_BOOKE
        .globl  ret_from_crit_exc
 ret_from_crit_exc:
-       mfspr   r9,SPRN_SPRG3
+       mfspr   r9,SPRN_SPRG_THREAD
        lwz     r10,SAVED_KSP_LIMIT(r1)
        stw     r10,KSP_LIMIT(r9)
        RESTORE_xSRR(SRR0,SRR1);
@@ -1083,7 +1083,7 @@ ret_from_crit_exc:
 
        .globl  ret_from_debug_exc
 ret_from_debug_exc:
-       mfspr   r9,SPRN_SPRG3
+       mfspr   r9,SPRN_SPRG_THREAD
        lwz     r10,SAVED_KSP_LIMIT(r1)
        stw     r10,KSP_LIMIT(r9)
        lwz     r9,THREAD_INFO-THREAD(r9)
@@ -1097,7 +1097,7 @@ ret_from_debug_exc:
 
        .globl  ret_from_mcheck_exc
 ret_from_mcheck_exc:
-       mfspr   r9,SPRN_SPRG3
+       mfspr   r9,SPRN_SPRG_THREAD
        lwz     r10,SAVED_KSP_LIMIT(r1)
        stw     r10,KSP_LIMIT(r9)
        RESTORE_xSRR(SRR0,SRR1);
@@ -1255,7 +1255,7 @@ _GLOBAL(enter_rtas)
        MTMSRD(r0)              /* don't get trashed */
        li      r9,MSR_KERNEL & ~(MSR_IR|MSR_DR)
        mtlr    r6
-       mtspr   SPRN_SPRG2,r7
+       mtspr   SPRN_SPRG_RTAS,r7
        mtspr   SPRN_SRR0,r8
        mtspr   SPRN_SRR1,r9
        RFI
@@ -1265,7 +1265,7 @@ _GLOBAL(enter_rtas)
        FIX_SRR1(r9,r0)
        addi    r1,r1,INT_FRAME_SIZE
        li      r0,0
-       mtspr   SPRN_SPRG2,r0
+       mtspr   SPRN_SPRG_RTAS,r0
        mtspr   SPRN_SRR0,r8
        mtspr   SPRN_SRR1,r9
        RFI                     /* return to caller */
index 43e073477c34adeac616067a62b4302dbc66d6d6..66bcda34a6bb7df7648e7735fcf4ff975ab83146 100644 (file)
@@ -120,9 +120,15 @@ BEGIN_FW_FTR_SECTION
 2:
 END_FW_FTR_SECTION_IFSET(FW_FEATURE_ISERIES)
 #endif /* CONFIG_PPC_ISERIES */
+
+       /* Hard enable interrupts */
+#ifdef CONFIG_PPC_BOOK3E
+       wrteei  1
+#else
        mfmsr   r11
        ori     r11,r11,MSR_EE
        mtmsrd  r11,1
+#endif /* CONFIG_PPC_BOOK3E */
 
 #ifdef SHOW_SYSCALLS
        bl      .do_show_syscall
@@ -168,15 +174,25 @@ syscall_exit:
 #endif
        clrrdi  r12,r1,THREAD_SHIFT
 
-       /* disable interrupts so current_thread_info()->flags can't change,
-          and so that we don't get interrupted after loading SRR0/1. */
        ld      r8,_MSR(r1)
+#ifdef CONFIG_PPC_BOOK3S
+       /* No MSR:RI on BookE */
        andi.   r10,r8,MSR_RI
        beq-    unrecov_restore
+#endif
+
+       /* Disable interrupts so current_thread_info()->flags can't change,
+        * and so that we don't get interrupted after loading SRR0/1.
+        */
+#ifdef CONFIG_PPC_BOOK3E
+       wrteei  0
+#else
        mfmsr   r10
        rldicl  r10,r10,48,1
        rotldi  r10,r10,16
        mtmsrd  r10,1
+#endif /* CONFIG_PPC_BOOK3E */
+
        ld      r9,TI_FLAGS(r12)
        li      r11,-_LAST_ERRNO
        andi.   r0,r9,(_TIF_SYSCALL_T_OR_A|_TIF_SINGLESTEP|_TIF_USER_WORK_MASK|_TIF_PERSYSCALL_MASK)
@@ -194,9 +210,13 @@ syscall_error_cont:
         * userspace and we take an exception after restoring r13,
         * we end up corrupting the userspace r13 value.
         */
+#ifdef CONFIG_PPC_BOOK3S
+       /* No MSR:RI on BookE */
        li      r12,MSR_RI
        andc    r11,r10,r12
        mtmsrd  r11,1                   /* clear MSR.RI */
+#endif /* CONFIG_PPC_BOOK3S */
+
        beq-    1f
        ACCOUNT_CPU_USER_EXIT(r11, r12)
        ld      r13,GPR13(r1)   /* only restore r13 if returning to usermode */
@@ -206,7 +226,7 @@ syscall_error_cont:
        mtcr    r5
        mtspr   SPRN_SRR0,r7
        mtspr   SPRN_SRR1,r8
-       rfid
+       RFI
        b       .       /* prevent speculative execution */
 
 syscall_error: 
@@ -276,9 +296,13 @@ syscall_exit_work:
        beq     .ret_from_except_lite
 
        /* Re-enable interrupts */
+#ifdef CONFIG_PPC_BOOK3E
+       wrteei  1
+#else
        mfmsr   r10
        ori     r10,r10,MSR_EE
        mtmsrd  r10,1
+#endif /* CONFIG_PPC_BOOK3E */
 
        bl      .save_nvgprs
        addi    r3,r1,STACK_FRAME_OVERHEAD
@@ -380,7 +404,7 @@ END_FTR_SECTION_IFSET(CPU_FTR_ALTIVEC)
        and.    r0,r0,r22
        beq+    1f
        andc    r22,r22,r0
-       mtmsrd  r22
+       MTMSRD(r22)
        isync
 1:     std     r20,_NIP(r1)
        mfcr    r23
@@ -399,6 +423,7 @@ END_FTR_SECTION_IFSET(CPU_FTR_ALTIVEC)
        std     r6,PACACURRENT(r13)     /* Set new 'current' */
 
        ld      r8,KSP(r4)      /* new stack pointer */
+#ifdef CONFIG_PPC_BOOK3S
 BEGIN_FTR_SECTION
   BEGIN_FTR_SECTION_NESTED(95)
        clrrdi  r6,r8,28        /* get its ESID */
@@ -445,8 +470,9 @@ END_FTR_SECTION_IFSET(CPU_FTR_1T_SEGMENT)
        slbie   r6              /* Workaround POWER5 < DD2.1 issue */
        slbmte  r7,r0
        isync
-
 2:
+#endif /* !CONFIG_PPC_BOOK3S */
+
        clrrdi  r7,r8,THREAD_SHIFT      /* base of new stack */
        /* Note: this uses SWITCH_FRAME_SIZE rather than INT_FRAME_SIZE
           because we don't need to leave the 288-byte ABI gap at the
@@ -490,10 +516,14 @@ _GLOBAL(ret_from_except_lite)
         * can't change between when we test it and when we return
         * from the interrupt.
         */
+#ifdef CONFIG_PPC_BOOK3E
+       wrteei  0
+#else
        mfmsr   r10             /* Get current interrupt state */
        rldicl  r9,r10,48,1     /* clear MSR_EE */
        rotldi  r9,r9,16
        mtmsrd  r9,1            /* Update machine state */
+#endif /* CONFIG_PPC_BOOK3E */
 
 #ifdef CONFIG_PREEMPT
        clrrdi  r9,r1,THREAD_SHIFT      /* current_thread_info() */
@@ -540,6 +570,9 @@ ALT_FW_FTR_SECTION_END_IFCLR(FW_FEATURE_ISERIES)
        rldicl  r4,r3,49,63             /* r0 = (r3 >> 15) & 1 */
        stb     r4,PACAHARDIRQEN(r13)
 
+#ifdef CONFIG_PPC_BOOK3E
+       b       .exception_return_book3e
+#else
        ld      r4,_CTR(r1)
        ld      r0,_LINK(r1)
        mtctr   r4
@@ -588,6 +621,8 @@ ALT_FW_FTR_SECTION_END_IFCLR(FW_FEATURE_ISERIES)
        rfid
        b       .       /* prevent speculative execution */
 
+#endif /* CONFIG_PPC_BOOK3E */
+
 iseries_check_pending_irqs:
 #ifdef CONFIG_PPC_ISERIES
        ld      r5,SOFTE(r1)
@@ -638,6 +673,11 @@ do_work:
        li      r0,1
        stb     r0,PACASOFTIRQEN(r13)
        stb     r0,PACAHARDIRQEN(r13)
+#ifdef CONFIG_PPC_BOOK3E
+       wrteei  1
+       bl      .preempt_schedule
+       wrteei  0
+#else
        ori     r10,r10,MSR_EE
        mtmsrd  r10,1           /* reenable interrupts */
        bl      .preempt_schedule
@@ -646,6 +686,7 @@ do_work:
        rldicl  r10,r10,48,1    /* disable interrupts again */
        rotldi  r10,r10,16
        mtmsrd  r10,1
+#endif /* CONFIG_PPC_BOOK3E */
        ld      r4,TI_FLAGS(r9)
        andi.   r0,r4,_TIF_NEED_RESCHED
        bne     1b
@@ -654,8 +695,12 @@ do_work:
 user_work:
 #endif
        /* Enable interrupts */
+#ifdef CONFIG_PPC_BOOK3E
+       wrteei  1
+#else
        ori     r10,r10,MSR_EE
        mtmsrd  r10,1
+#endif /* CONFIG_PPC_BOOK3E */
 
        andi.   r0,r4,_TIF_NEED_RESCHED
        beq     1f
@@ -762,7 +807,7 @@ _GLOBAL(enter_rtas)
 
 _STATIC(rtas_return_loc)
        /* relocation is off at this point */
-       mfspr   r4,SPRN_SPRG3           /* Get PACA */
+       mfspr   r4,SPRN_SPRG_PACA       /* Get PACA */
        clrldi  r4,r4,2                 /* convert to realmode address */
 
        bcl     20,31,$+4
@@ -793,7 +838,7 @@ _STATIC(rtas_restore_regs)
        REST_8GPRS(14, r1)              /* Restore the non-volatiles */
        REST_10GPRS(22, r1)             /* ditto */
 
-       mfspr   r13,SPRN_SPRG3
+       mfspr   r13,SPRN_SPRG_PACA
 
        ld      r4,_CCR(r1)
        mtcr    r4
@@ -823,33 +868,24 @@ _GLOBAL(enter_prom)
         * of all registers that it saves.  We therefore save those registers
         * PROM might touch to the stack.  (r0, r3-r13 are caller saved)
         */
-       SAVE_8GPRS(2, r1)
+       SAVE_GPR(2, r1)
        SAVE_GPR(13, r1)
        SAVE_8GPRS(14, r1)
        SAVE_10GPRS(22, r1)
-       mfcr    r4
-       std     r4,_CCR(r1)
-       mfctr   r5
-       std     r5,_CTR(r1)
-       mfspr   r6,SPRN_XER
-       std     r6,_XER(r1)
-       mfdar   r7
-       std     r7,_DAR(r1)
-       mfdsisr r8
-       std     r8,_DSISR(r1)
-       mfsrr0  r9
-       std     r9,_SRR0(r1)
-       mfsrr1  r10
-       std     r10,_SRR1(r1)
+       mfcr    r10
        mfmsr   r11
+       std     r10,_CCR(r1)
        std     r11,_MSR(r1)
 
        /* Get the PROM entrypoint */
-       ld      r0,GPR4(r1)
-       mtlr    r0
+       mtlr    r4
 
        /* Switch MSR to 32 bits mode
         */
+#ifdef CONFIG_PPC_BOOK3E
+       rlwinm  r11,r11,0,1,31
+       mtmsr   r11
+#else /* CONFIG_PPC_BOOK3E */
         mfmsr   r11
         li      r12,1
         rldicr  r12,r12,MSR_SF_LG,(63-MSR_SF_LG)
@@ -858,10 +894,10 @@ _GLOBAL(enter_prom)
         rldicr  r12,r12,MSR_ISF_LG,(63-MSR_ISF_LG)
         andc    r11,r11,r12
         mtmsrd  r11
+#endif /* CONFIG_PPC_BOOK3E */
         isync
 
-       /* Restore arguments & enter PROM here... */
-       ld      r3,GPR3(r1)
+       /* Enter PROM here... */
        blrl
 
        /* Just make sure that r1 top 32 bits didn't get
@@ -871,7 +907,7 @@ _GLOBAL(enter_prom)
 
        /* Restore the MSR (back to 64 bits) */
        ld      r0,_MSR(r1)
-       mtmsrd  r0
+       MTMSRD(r0)
         isync
 
        /* Restore other registers */
@@ -881,18 +917,6 @@ _GLOBAL(enter_prom)
        REST_10GPRS(22, r1)
        ld      r4,_CCR(r1)
        mtcr    r4
-       ld      r5,_CTR(r1)
-       mtctr   r5
-       ld      r6,_XER(r1)
-       mtspr   SPRN_XER,r6
-       ld      r7,_DAR(r1)
-       mtdar   r7
-       ld      r8,_DSISR(r1)
-       mtdsisr r8
-       ld      r9,_SRR0(r1)
-       mtsrr0  r9
-       ld      r10,_SRR1(r1)
-       mtsrr1  r10
        
         addi   r1,r1,PROM_FRAME_SIZE
        ld      r0,16(r1)
diff --git a/arch/powerpc/kernel/exceptions-64e.S b/arch/powerpc/kernel/exceptions-64e.S
new file mode 100644 (file)
index 0000000..9048f96
--- /dev/null
@@ -0,0 +1,1001 @@
+/*
+ *  Boot code and exception vectors for Book3E processors
+ *
+ *  Copyright (C) 2007 Ben. Herrenschmidt (benh@kernel.crashing.org), IBM Corp.
+ *
+ *  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/threads.h>
+#include <asm/reg.h>
+#include <asm/page.h>
+#include <asm/ppc_asm.h>
+#include <asm/asm-offsets.h>
+#include <asm/cputable.h>
+#include <asm/setup.h>
+#include <asm/thread_info.h>
+#include <asm/reg.h>
+#include <asm/exception-64e.h>
+#include <asm/bug.h>
+#include <asm/irqflags.h>
+#include <asm/ptrace.h>
+#include <asm/ppc-opcode.h>
+#include <asm/mmu.h>
+
+/* XXX This will ultimately add space for a special exception save
+ *     structure used to save things like SRR0/SRR1, SPRGs, MAS, etc...
+ *     when taking special interrupts. For now we don't support that,
+ *     special interrupts from within a non-standard level will probably
+ *     blow you up
+ */
+#define        SPECIAL_EXC_FRAME_SIZE  INT_FRAME_SIZE
+
+/* Exception prolog code for all exceptions */
+#define EXCEPTION_PROLOG(n, type, addition)                                \
+       mtspr   SPRN_SPRG_##type##_SCRATCH,r13; /* get spare registers */   \
+       mfspr   r13,SPRN_SPRG_PACA;     /* get PACA */                      \
+       std     r10,PACA_EX##type+EX_R10(r13);                              \
+       std     r11,PACA_EX##type+EX_R11(r13);                              \
+       mfcr    r10;                    /* save CR */                       \
+       addition;                       /* additional code for that exc. */ \
+       std     r1,PACA_EX##type+EX_R1(r13); /* save old r1 in the PACA */  \
+       stw     r10,PACA_EX##type+EX_CR(r13); /* save old CR in the PACA */ \
+       mfspr   r11,SPRN_##type##_SRR1;/* what are we coming from */        \
+       type##_SET_KSTACK;              /* get special stack if necessary */\
+       andi.   r10,r11,MSR_PR;         /* save stack pointer */            \
+       beq     1f;                     /* branch around if supervisor */   \
+       ld      r1,PACAKSAVE(r13);      /* get kernel stack coming from usr */\
+1:     cmpdi   cr1,r1,0;               /* check if SP makes sense */       \
+       bge-    cr1,exc_##n##_bad_stack;/* bad stack (TODO: out of line) */ \
+       mfspr   r10,SPRN_##type##_SRR0; /* read SRR0 before touching stack */
+
+/* Exception type-specific macros */
+#define        GEN_SET_KSTACK                                                      \
+       subi    r1,r1,INT_FRAME_SIZE;   /* alloc frame on kernel stack */
+#define SPRN_GEN_SRR0  SPRN_SRR0
+#define SPRN_GEN_SRR1  SPRN_SRR1
+
+#define CRIT_SET_KSTACK                                                            \
+       ld      r1,PACA_CRIT_STACK(r13);                                    \
+       subi    r1,r1,SPECIAL_EXC_FRAME_SIZE;
+#define SPRN_CRIT_SRR0 SPRN_CSRR0
+#define SPRN_CRIT_SRR1 SPRN_CSRR1
+
+#define DBG_SET_KSTACK                                                     \
+       ld      r1,PACA_DBG_STACK(r13);                                     \
+       subi    r1,r1,SPECIAL_EXC_FRAME_SIZE;
+#define SPRN_DBG_SRR0  SPRN_DSRR0
+#define SPRN_DBG_SRR1  SPRN_DSRR1
+
+#define MC_SET_KSTACK                                                      \
+       ld      r1,PACA_MC_STACK(r13);                                      \
+       subi    r1,r1,SPECIAL_EXC_FRAME_SIZE;
+#define SPRN_MC_SRR0   SPRN_MCSRR0
+#define SPRN_MC_SRR1   SPRN_MCSRR1
+
+#define NORMAL_EXCEPTION_PROLOG(n, addition)                               \
+       EXCEPTION_PROLOG(n, GEN, addition##_GEN)
+
+#define CRIT_EXCEPTION_PROLOG(n, addition)                                 \
+       EXCEPTION_PROLOG(n, CRIT, addition##_CRIT)
+
+#define DBG_EXCEPTION_PROLOG(n, addition)                                  \
+       EXCEPTION_PROLOG(n, DBG, addition##_DBG)
+
+#define MC_EXCEPTION_PROLOG(n, addition)                                   \
+       EXCEPTION_PROLOG(n, MC, addition##_MC)
+
+
+/* Variants of the "addition" argument for the prolog
+ */
+#define PROLOG_ADDITION_NONE_GEN
+#define PROLOG_ADDITION_NONE_CRIT
+#define PROLOG_ADDITION_NONE_DBG
+#define PROLOG_ADDITION_NONE_MC
+
+#define PROLOG_ADDITION_MASKABLE_GEN                                       \
+       lbz     r11,PACASOFTIRQEN(r13); /* are irqs soft-disabled ? */      \
+       cmpwi   cr0,r11,0;              /* yes -> go out of line */         \
+       beq     masked_interrupt_book3e;
+
+#define PROLOG_ADDITION_2REGS_GEN                                          \
+       std     r14,PACA_EXGEN+EX_R14(r13);                                 \
+       std     r15,PACA_EXGEN+EX_R15(r13)
+
+#define PROLOG_ADDITION_1REG_GEN                                           \
+       std     r14,PACA_EXGEN+EX_R14(r13);
+
+#define PROLOG_ADDITION_2REGS_CRIT                                         \
+       std     r14,PACA_EXCRIT+EX_R14(r13);                                \
+       std     r15,PACA_EXCRIT+EX_R15(r13)
+
+#define PROLOG_ADDITION_2REGS_DBG                                          \
+       std     r14,PACA_EXDBG+EX_R14(r13);                                 \
+       std     r15,PACA_EXDBG+EX_R15(r13)
+
+#define PROLOG_ADDITION_2REGS_MC                                           \
+       std     r14,PACA_EXMC+EX_R14(r13);                                  \
+       std     r15,PACA_EXMC+EX_R15(r13)
+
+/* Core exception code for all exceptions except TLB misses.
+ * XXX: Needs to make SPRN_SPRG_GEN depend on exception type
+ */
+#define EXCEPTION_COMMON(n, excf, ints)                                            \
+       std     r0,GPR0(r1);            /* save r0 in stackframe */         \
+       std     r2,GPR2(r1);            /* save r2 in stackframe */         \
+       SAVE_4GPRS(3, r1);              /* save r3 - r6 in stackframe */    \
+       SAVE_2GPRS(7, r1);              /* save r7, r8 in stackframe */     \
+       std     r9,GPR9(r1);            /* save r9 in stackframe */         \
+       std     r10,_NIP(r1);           /* save SRR0 to stackframe */       \
+       std     r11,_MSR(r1);           /* save SRR1 to stackframe */       \
+       ACCOUNT_CPU_USER_ENTRY(r10,r11);/* accounting (uses cr0+eq) */      \
+       ld      r3,excf+EX_R10(r13);    /* get back r10 */                  \
+       ld      r4,excf+EX_R11(r13);    /* get back r11 */                  \
+       mfspr   r5,SPRN_SPRG_GEN_SCRATCH;/* get back r13 */                 \
+       std     r12,GPR12(r1);          /* save r12 in stackframe */        \
+       ld      r2,PACATOC(r13);        /* get kernel TOC into r2 */        \
+       mflr    r6;                     /* save LR in stackframe */         \
+       mfctr   r7;                     /* save CTR in stackframe */        \
+       mfspr   r8,SPRN_XER;            /* save XER in stackframe */        \
+       ld      r9,excf+EX_R1(r13);     /* load orig r1 back from PACA */   \
+       lwz     r10,excf+EX_CR(r13);    /* load orig CR back from PACA  */  \
+       lbz     r11,PACASOFTIRQEN(r13); /* get current IRQ softe */         \
+       ld      r12,exception_marker@toc(r2);                               \
+       li      r0,0;                                                       \
+       std     r3,GPR10(r1);           /* save r10 to stackframe */        \
+       std     r4,GPR11(r1);           /* save r11 to stackframe */        \
+       std     r5,GPR13(r1);           /* save it to stackframe */         \
+       std     r6,_LINK(r1);                                               \
+       std     r7,_CTR(r1);                                                \
+       std     r8,_XER(r1);                                                \
+       li      r3,(n)+1;               /* indicate partial regs in trap */ \
+       std     r9,0(r1);               /* store stack frame back link */   \
+       std     r10,_CCR(r1);           /* store orig CR in stackframe */   \
+       std     r9,GPR1(r1);            /* store stack frame back link */   \
+       std     r11,SOFTE(r1);          /* and save it to stackframe */     \
+       std     r12,STACK_FRAME_OVERHEAD-16(r1); /* mark the frame */       \
+       std     r3,_TRAP(r1);           /* set trap number              */  \
+       std     r0,RESULT(r1);          /* clear regs->result */            \
+       ints;
+
+/* Variants for the "ints" argument */
+#define INTS_KEEP
+#define INTS_DISABLE_SOFT                                                  \
+       stb     r0,PACASOFTIRQEN(r13);  /* mark interrupts soft-disabled */ \
+       TRACE_DISABLE_INTS;
+#define INTS_DISABLE_HARD                                                  \
+       stb     r0,PACAHARDIRQEN(r13); /* and hard disabled */
+#define INTS_DISABLE_ALL                                                   \
+       INTS_DISABLE_SOFT                                                   \
+       INTS_DISABLE_HARD
+
+/* This is called by exceptions that used INTS_KEEP (that is did not clear
+ * neither soft nor hard IRQ indicators in the PACA. This will restore MSR:EE
+ * to it's previous value
+ *
+ * XXX In the long run, we may want to open-code it in order to separate the
+ *     load from the wrtee, thus limiting the latency caused by the dependency
+ *     but at this point, I'll favor code clarity until we have a near to final
+ *     implementation
+ */
+#define INTS_RESTORE_HARD                                                  \
+       ld      r11,_MSR(r1);                                               \
+       wrtee   r11;
+
+/* XXX FIXME: Restore r14/r15 when necessary */
+#define BAD_STACK_TRAMPOLINE(n)                                                    \
+exc_##n##_bad_stack:                                                       \
+       li      r1,(n);                 /* get exception number */          \
+       sth     r1,PACA_TRAP_SAVE(r13); /* store trap */                    \
+       b       bad_stack_book3e;       /* bad stack error */
+
+#define        EXCEPTION_STUB(loc, label)                                      \
+       . = interrupt_base_book3e + loc;                                \
+       nop;    /* To make debug interrupts happy */                    \
+       b       exc_##label##_book3e;
+
+#define ACK_NONE(r)
+#define ACK_DEC(r)                                                     \
+       lis     r,TSR_DIS@h;                                            \
+       mtspr   SPRN_TSR,r
+#define ACK_FIT(r)                                                     \
+       lis     r,TSR_FIS@h;                                            \
+       mtspr   SPRN_TSR,r
+
+#define MASKABLE_EXCEPTION(trapnum, label, hdlr, ack)                  \
+       START_EXCEPTION(label);                                         \
+       NORMAL_EXCEPTION_PROLOG(trapnum, PROLOG_ADDITION_MASKABLE)      \
+       EXCEPTION_COMMON(trapnum, PACA_EXGEN, INTS_DISABLE_ALL)         \
+       ack(r8);                                                        \
+       addi    r3,r1,STACK_FRAME_OVERHEAD;                             \
+       bl      hdlr;                                                   \
+       b       .ret_from_except_lite;
+
+/* This value is used to mark exception frames on the stack. */
+       .section        ".toc","aw"
+exception_marker:
+       .tc     ID_EXC_MARKER[TC],STACK_FRAME_REGS_MARKER
+
+
+/*
+ * And here we have the exception vectors !
+ */
+
+       .text
+       .balign 0x1000
+       .globl interrupt_base_book3e
+interrupt_base_book3e:                                 /* fake trap */
+       /* Note: If real debug exceptions are supported by the HW, the vector
+        * below will have to be patched up to point to an appropriate handler
+        */
+       EXCEPTION_STUB(0x000, machine_check)            /* 0x0200 */
+       EXCEPTION_STUB(0x020, critical_input)           /* 0x0580 */
+       EXCEPTION_STUB(0x040, debug_crit)               /* 0x0d00 */
+       EXCEPTION_STUB(0x060, data_storage)             /* 0x0300 */
+       EXCEPTION_STUB(0x080, instruction_storage)      /* 0x0400 */
+       EXCEPTION_STUB(0x0a0, external_input)           /* 0x0500 */
+       EXCEPTION_STUB(0x0c0, alignment)                /* 0x0600 */
+       EXCEPTION_STUB(0x0e0, program)                  /* 0x0700 */
+       EXCEPTION_STUB(0x100, fp_unavailable)           /* 0x0800 */
+       EXCEPTION_STUB(0x120, system_call)              /* 0x0c00 */
+       EXCEPTION_STUB(0x140, ap_unavailable)           /* 0x0f20 */
+       EXCEPTION_STUB(0x160, decrementer)              /* 0x0900 */
+       EXCEPTION_STUB(0x180, fixed_interval)           /* 0x0980 */
+       EXCEPTION_STUB(0x1a0, watchdog)                 /* 0x09f0 */
+       EXCEPTION_STUB(0x1c0, data_tlb_miss)
+       EXCEPTION_STUB(0x1e0, instruction_tlb_miss)
+
+#if 0
+       EXCEPTION_STUB(0x280, processor_doorbell)
+       EXCEPTION_STUB(0x220, processor_doorbell_crit)
+#endif
+       .globl interrupt_end_book3e
+interrupt_end_book3e:
+
+/* Critical Input Interrupt */
+       START_EXCEPTION(critical_input);
+       CRIT_EXCEPTION_PROLOG(0x100, PROLOG_ADDITION_NONE)
+//     EXCEPTION_COMMON(0x100, PACA_EXCRIT, INTS_DISABLE_ALL)
+//     bl      special_reg_save_crit
+//     addi    r3,r1,STACK_FRAME_OVERHEAD
+//     bl      .critical_exception
+//     b       ret_from_crit_except
+       b       .
+
+/* Machine Check Interrupt */
+       START_EXCEPTION(machine_check);
+       CRIT_EXCEPTION_PROLOG(0x200, PROLOG_ADDITION_NONE)
+//     EXCEPTION_COMMON(0x200, PACA_EXMC, INTS_DISABLE_ALL)
+//     bl      special_reg_save_mc
+//     addi    r3,r1,STACK_FRAME_OVERHEAD
+//     bl      .machine_check_exception
+//     b       ret_from_mc_except
+       b       .
+
+/* Data Storage Interrupt */
+       START_EXCEPTION(data_storage)
+       NORMAL_EXCEPTION_PROLOG(0x300, PROLOG_ADDITION_2REGS)
+       mfspr   r14,SPRN_DEAR
+       mfspr   r15,SPRN_ESR
+       EXCEPTION_COMMON(0x300, PACA_EXGEN, INTS_KEEP)
+       b       storage_fault_common
+
+/* Instruction Storage Interrupt */
+       START_EXCEPTION(instruction_storage);
+       NORMAL_EXCEPTION_PROLOG(0x400, PROLOG_ADDITION_2REGS)
+       li      r15,0
+       mr      r14,r10
+       EXCEPTION_COMMON(0x400, PACA_EXGEN, INTS_KEEP)
+       b       storage_fault_common
+
+/* External Input Interrupt */
+       MASKABLE_EXCEPTION(0x500, external_input, .do_IRQ, ACK_NONE)
+
+/* Alignment */
+       START_EXCEPTION(alignment);
+       NORMAL_EXCEPTION_PROLOG(0x600, PROLOG_ADDITION_2REGS)
+       mfspr   r14,SPRN_DEAR
+       mfspr   r15,SPRN_ESR
+       EXCEPTION_COMMON(0x600, PACA_EXGEN, INTS_KEEP)
+       b       alignment_more  /* no room, go out of line */
+
+/* Program Interrupt */
+       START_EXCEPTION(program);
+       NORMAL_EXCEPTION_PROLOG(0x700, PROLOG_ADDITION_1REG)
+       mfspr   r14,SPRN_ESR
+       EXCEPTION_COMMON(0x700, PACA_EXGEN, INTS_DISABLE_SOFT)
+       std     r14,_DSISR(r1)
+       addi    r3,r1,STACK_FRAME_OVERHEAD
+       ld      r14,PACA_EXGEN+EX_R14(r13)
+       bl      .save_nvgprs
+       INTS_RESTORE_HARD
+       bl      .program_check_exception
+       b       .ret_from_except
+
+/* Floating Point Unavailable Interrupt */
+       START_EXCEPTION(fp_unavailable);
+       NORMAL_EXCEPTION_PROLOG(0x800, PROLOG_ADDITION_NONE)
+       /* we can probably do a shorter exception entry for that one... */
+       EXCEPTION_COMMON(0x800, PACA_EXGEN, INTS_KEEP)
+       bne     1f                      /* if from user, just load it up */
+       bl      .save_nvgprs
+       addi    r3,r1,STACK_FRAME_OVERHEAD
+       INTS_RESTORE_HARD
+       bl      .kernel_fp_unavailable_exception
+       BUG_OPCODE
+1:     ld      r12,_MSR(r1)
+       bl      .load_up_fpu
+       b       fast_exception_return
+
+/* Decrementer Interrupt */
+       MASKABLE_EXCEPTION(0x900, decrementer, .timer_interrupt, ACK_DEC)
+
+/* Fixed Interval Timer Interrupt */
+       MASKABLE_EXCEPTION(0x980, fixed_interval, .unknown_exception, ACK_FIT)
+
+/* Watchdog Timer Interrupt */
+       START_EXCEPTION(watchdog);
+       CRIT_EXCEPTION_PROLOG(0x9f0, PROLOG_ADDITION_NONE)
+//     EXCEPTION_COMMON(0x9f0, PACA_EXCRIT, INTS_DISABLE_ALL)
+//     bl      special_reg_save_crit
+//     addi    r3,r1,STACK_FRAME_OVERHEAD
+//     bl      .unknown_exception
+//     b       ret_from_crit_except
+       b       .
+
+/* System Call Interrupt */
+       START_EXCEPTION(system_call)
+       mr      r9,r13                  /* keep a copy of userland r13 */
+       mfspr   r11,SPRN_SRR0           /* get return address */
+       mfspr   r12,SPRN_SRR1           /* get previous MSR */
+       mfspr   r13,SPRN_SPRG_PACA      /* get our PACA */
+       b       system_call_common
+
+/* Auxillary Processor Unavailable Interrupt */
+       START_EXCEPTION(ap_unavailable);
+       NORMAL_EXCEPTION_PROLOG(0xf20, PROLOG_ADDITION_NONE)
+       EXCEPTION_COMMON(0xf20, PACA_EXGEN, INTS_KEEP)
+       addi    r3,r1,STACK_FRAME_OVERHEAD
+       bl      .save_nvgprs
+       INTS_RESTORE_HARD
+       bl      .unknown_exception
+       b       .ret_from_except
+
+/* Debug exception as a critical interrupt*/
+       START_EXCEPTION(debug_crit);
+       CRIT_EXCEPTION_PROLOG(0xd00, PROLOG_ADDITION_2REGS)
+
+       /*
+        * If there is a single step or branch-taken exception in an
+        * exception entry sequence, it was probably meant to apply to
+        * the code where the exception occurred (since exception entry
+        * doesn't turn off DE automatically).  We simulate the effect
+        * of turning off DE on entry to an exception handler by turning
+        * off DE in the CSRR1 value and clearing the debug status.
+        */
+
+       mfspr   r14,SPRN_DBSR           /* check single-step/branch taken */
+       andis.  r15,r14,DBSR_IC@h
+       beq+    1f
+
+       LOAD_REG_IMMEDIATE(r14,interrupt_base_book3e)
+       LOAD_REG_IMMEDIATE(r15,interrupt_end_book3e)
+       cmpld   cr0,r10,r14
+       cmpld   cr1,r10,r15
+       blt+    cr0,1f
+       bge+    cr1,1f
+
+       /* here it looks like we got an inappropriate debug exception. */
+       lis     r14,DBSR_IC@h           /* clear the IC event */
+       rlwinm  r11,r11,0,~MSR_DE       /* clear DE in the CSRR1 value */
+       mtspr   SPRN_DBSR,r14
+       mtspr   SPRN_CSRR1,r11
+       lwz     r10,PACA_EXCRIT+EX_CR(r13)      /* restore registers */
+       ld      r1,PACA_EXCRIT+EX_R1(r13)
+       ld      r14,PACA_EXCRIT+EX_R14(r13)
+       ld      r15,PACA_EXCRIT+EX_R15(r13)
+       mtcr    r10
+       ld      r10,PACA_EXCRIT+EX_R10(r13)     /* restore registers */
+       ld      r11,PACA_EXCRIT+EX_R11(r13)
+       mfspr   r13,SPRN_SPRG_CRIT_SCRATCH
+       rfci
+
+       /* Normal debug exception */
+       /* XXX We only handle coming from userspace for now since we can't
+        *     quite save properly an interrupted kernel state yet
+        */
+1:     andi.   r14,r11,MSR_PR;         /* check for userspace again */
+       beq     kernel_dbg_exc;         /* if from kernel mode */
+
+       /* Now we mash up things to make it look like we are coming on a
+        * normal exception
+        */
+       mfspr   r15,SPRN_SPRG_CRIT_SCRATCH
+       mtspr   SPRN_SPRG_GEN_SCRATCH,r15
+       mfspr   r14,SPRN_DBSR
+       EXCEPTION_COMMON(0xd00, PACA_EXCRIT, INTS_DISABLE_ALL)
+       std     r14,_DSISR(r1)
+       addi    r3,r1,STACK_FRAME_OVERHEAD
+       mr      r4,r14
+       ld      r14,PACA_EXCRIT+EX_R14(r13)
+       ld      r15,PACA_EXCRIT+EX_R15(r13)
+       bl      .save_nvgprs
+       bl      .DebugException
+       b       .ret_from_except
+
+kernel_dbg_exc:
+       b       .       /* NYI */
+
+
+/*
+ * An interrupt came in while soft-disabled; clear EE in SRR1,
+ * clear paca->hard_enabled and return.
+ */
+masked_interrupt_book3e:
+       mtcr    r10
+       stb     r11,PACAHARDIRQEN(r13)
+       mfspr   r10,SPRN_SRR1
+       rldicl  r11,r10,48,1            /* clear MSR_EE */
+       rotldi  r10,r11,16
+       mtspr   SPRN_SRR1,r10
+       ld      r10,PACA_EXGEN+EX_R10(r13);     /* restore registers */
+       ld      r11,PACA_EXGEN+EX_R11(r13);
+       mfspr   r13,SPRN_SPRG_GEN_SCRATCH;
+       rfi
+       b       .
+
+/*
+ * This is called from 0x300 and 0x400 handlers after the prologs with
+ * r14 and r15 containing the fault address and error code, with the
+ * original values stashed away in the PACA
+ */
+storage_fault_common:
+       std     r14,_DAR(r1)
+       std     r15,_DSISR(r1)
+       addi    r3,r1,STACK_FRAME_OVERHEAD
+       mr      r4,r14
+       mr      r5,r15
+       ld      r14,PACA_EXGEN+EX_R14(r13)
+       ld      r15,PACA_EXGEN+EX_R15(r13)
+       INTS_RESTORE_HARD
+       bl      .do_page_fault
+       cmpdi   r3,0
+       bne-    1f
+       b       .ret_from_except_lite
+1:     bl      .save_nvgprs
+       mr      r5,r3
+       addi    r3,r1,STACK_FRAME_OVERHEAD
+       ld      r4,_DAR(r1)
+       bl      .bad_page_fault
+       b       .ret_from_except
+
+/*
+ * Alignment exception doesn't fit entirely in the 0x100 bytes so it
+ * continues here.
+ */
+alignment_more:
+       std     r14,_DAR(r1)
+       std     r15,_DSISR(r1)
+       addi    r3,r1,STACK_FRAME_OVERHEAD
+       ld      r14,PACA_EXGEN+EX_R14(r13)
+       ld      r15,PACA_EXGEN+EX_R15(r13)
+       bl      .save_nvgprs
+       INTS_RESTORE_HARD
+       bl      .alignment_exception
+       b       .ret_from_except
+
+/*
+ * We branch here from entry_64.S for the last stage of the exception
+ * return code path. MSR:EE is expected to be off at that point
+ */
+_GLOBAL(exception_return_book3e)
+       b       1f
+
+/* This is the return from load_up_fpu fast path which could do with
+ * less GPR restores in fact, but for now we have a single return path
+ */
+       .globl fast_exception_return
+fast_exception_return:
+       wrteei  0
+1:     mr      r0,r13
+       ld      r10,_MSR(r1)
+       REST_4GPRS(2, r1)
+       andi.   r6,r10,MSR_PR
+       REST_2GPRS(6, r1)
+       beq     1f
+       ACCOUNT_CPU_USER_EXIT(r10, r11)
+       ld      r0,GPR13(r1)
+
+1:     stdcx.  r0,0,r1         /* to clear the reservation */
+
+       ld      r8,_CCR(r1)
+       ld      r9,_LINK(r1)
+       ld      r10,_CTR(r1)
+       ld      r11,_XER(r1)
+       mtcr    r8
+       mtlr    r9
+       mtctr   r10
+       mtxer   r11
+       REST_2GPRS(8, r1)
+       ld      r10,GPR10(r1)
+       ld      r11,GPR11(r1)
+       ld      r12,GPR12(r1)
+       mtspr   SPRN_SPRG_GEN_SCRATCH,r0
+
+       std     r10,PACA_EXGEN+EX_R10(r13);
+       std     r11,PACA_EXGEN+EX_R11(r13);
+       ld      r10,_NIP(r1)
+       ld      r11,_MSR(r1)
+       ld      r0,GPR0(r1)
+       ld      r1,GPR1(r1)
+       mtspr   SPRN_SRR0,r10
+       mtspr   SPRN_SRR1,r11
+       ld      r10,PACA_EXGEN+EX_R10(r13)
+       ld      r11,PACA_EXGEN+EX_R11(r13)
+       mfspr   r13,SPRN_SPRG_GEN_SCRATCH
+       rfi
+
+/*
+ * Trampolines used when spotting a bad kernel stack pointer in
+ * the exception entry code.
+ *
+ * TODO: move some bits like SRR0 read to trampoline, pass PACA
+ * index around, etc... to handle crit & mcheck
+ */
+BAD_STACK_TRAMPOLINE(0x000)
+BAD_STACK_TRAMPOLINE(0x100)
+BAD_STACK_TRAMPOLINE(0x200)
+BAD_STACK_TRAMPOLINE(0x300)
+BAD_STACK_TRAMPOLINE(0x400)
+BAD_STACK_TRAMPOLINE(0x500)
+BAD_STACK_TRAMPOLINE(0x600)
+BAD_STACK_TRAMPOLINE(0x700)
+BAD_STACK_TRAMPOLINE(0x800)
+BAD_STACK_TRAMPOLINE(0x900)
+BAD_STACK_TRAMPOLINE(0x980)
+BAD_STACK_TRAMPOLINE(0x9f0)
+BAD_STACK_TRAMPOLINE(0xa00)
+BAD_STACK_TRAMPOLINE(0xb00)
+BAD_STACK_TRAMPOLINE(0xc00)
+BAD_STACK_TRAMPOLINE(0xd00)
+BAD_STACK_TRAMPOLINE(0xe00)
+BAD_STACK_TRAMPOLINE(0xf00)
+BAD_STACK_TRAMPOLINE(0xf20)
+
+       .globl  bad_stack_book3e
+bad_stack_book3e:
+       /* XXX: Needs to make SPRN_SPRG_GEN depend on exception type */
+       mfspr   r10,SPRN_SRR0;            /* read SRR0 before touching stack */
+       ld      r1,PACAEMERGSP(r13)
+       subi    r1,r1,64+INT_FRAME_SIZE
+       std     r10,_NIP(r1)
+       std     r11,_MSR(r1)
+       ld      r10,PACA_EXGEN+EX_R1(r13) /* FIXME for crit & mcheck */
+       lwz     r11,PACA_EXGEN+EX_CR(r13) /* FIXME for crit & mcheck */
+       std     r10,GPR1(r1)
+       std     r11,_CCR(r1)
+       mfspr   r10,SPRN_DEAR
+       mfspr   r11,SPRN_ESR
+       std     r10,_DAR(r1)
+       std     r11,_DSISR(r1)
+       std     r0,GPR0(r1);            /* save r0 in stackframe */         \
+       std     r2,GPR2(r1);            /* save r2 in stackframe */         \
+       SAVE_4GPRS(3, r1);              /* save r3 - r6 in stackframe */    \
+       SAVE_2GPRS(7, r1);              /* save r7, r8 in stackframe */     \
+       std     r9,GPR9(r1);            /* save r9 in stackframe */         \
+       ld      r3,PACA_EXGEN+EX_R10(r13);/* get back r10 */                \
+       ld      r4,PACA_EXGEN+EX_R11(r13);/* get back r11 */                \
+       mfspr   r5,SPRN_SPRG_GEN_SCRATCH;/* get back r13 XXX can be wrong */ \
+       std     r3,GPR10(r1);           /* save r10 to stackframe */        \
+       std     r4,GPR11(r1);           /* save r11 to stackframe */        \
+       std     r12,GPR12(r1);          /* save r12 in stackframe */        \
+       std     r5,GPR13(r1);           /* save it to stackframe */         \
+       mflr    r10
+       mfctr   r11
+       mfxer   r12
+       std     r10,_LINK(r1)
+       std     r11,_CTR(r1)
+       std     r12,_XER(r1)
+       SAVE_10GPRS(14,r1)
+       SAVE_8GPRS(24,r1)
+       lhz     r12,PACA_TRAP_SAVE(r13)
+       std     r12,_TRAP(r1)
+       addi    r11,r1,INT_FRAME_SIZE
+       std     r11,0(r1)
+       li      r12,0
+       std     r12,0(r11)
+       ld      r2,PACATOC(r13)
+1:     addi    r3,r1,STACK_FRAME_OVERHEAD
+       bl      .kernel_bad_stack
+       b       1b
+
+/*
+ * Setup the initial TLB for a core. This current implementation
+ * assume that whatever we are running off will not conflict with
+ * the new mapping at PAGE_OFFSET.
+ */
+_GLOBAL(initial_tlb_book3e)
+
+       /* Look for the first TLB with IPROT set */
+       mfspr   r4,SPRN_TLB0CFG
+       andi.   r3,r4,TLBnCFG_IPROT
+       lis     r3,MAS0_TLBSEL(0)@h
+       bne     found_iprot
+
+       mfspr   r4,SPRN_TLB1CFG
+       andi.   r3,r4,TLBnCFG_IPROT
+       lis     r3,MAS0_TLBSEL(1)@h
+       bne     found_iprot
+
+       mfspr   r4,SPRN_TLB2CFG
+       andi.   r3,r4,TLBnCFG_IPROT
+       lis     r3,MAS0_TLBSEL(2)@h
+       bne     found_iprot
+
+       lis     r3,MAS0_TLBSEL(3)@h
+       mfspr   r4,SPRN_TLB3CFG
+       /* fall through */
+
+found_iprot:
+       andi.   r5,r4,TLBnCFG_HES
+       bne     have_hes
+
+       mflr    r8                              /* save LR */
+/* 1. Find the index of the entry we're executing in
+ *
+ * r3 = MAS0_TLBSEL (for the iprot array)
+ * r4 = SPRN_TLBnCFG
+ */
+       bl      invstr                          /* Find our address */
+invstr:        mflr    r6                              /* Make it accessible */
+       mfmsr   r7
+       rlwinm  r5,r7,27,31,31                  /* extract MSR[IS] */
+       mfspr   r7,SPRN_PID
+       slwi    r7,r7,16
+       or      r7,r7,r5
+       mtspr   SPRN_MAS6,r7
+       tlbsx   0,r6                            /* search MSR[IS], SPID=PID */
+
+       mfspr   r3,SPRN_MAS0
+       rlwinm  r5,r3,16,20,31                  /* Extract MAS0(Entry) */
+
+       mfspr   r7,SPRN_MAS1                    /* Insure IPROT set */
+       oris    r7,r7,MAS1_IPROT@h
+       mtspr   SPRN_MAS1,r7
+       tlbwe
+
+/* 2. Invalidate all entries except the entry we're executing in
+ *
+ * r3 = MAS0 w/TLBSEL & ESEL for the entry we are running in
+ * r4 = SPRN_TLBnCFG
+ * r5 = ESEL of entry we are running in
+ */
+       andi.   r4,r4,TLBnCFG_N_ENTRY           /* Extract # entries */
+       li      r6,0                            /* Set Entry counter to 0 */
+1:     mr      r7,r3                           /* Set MAS0(TLBSEL) */
+       rlwimi  r7,r6,16,4,15                   /* Setup MAS0 = TLBSEL | ESEL(r6) */
+       mtspr   SPRN_MAS0,r7
+       tlbre
+       mfspr   r7,SPRN_MAS1
+       rlwinm  r7,r7,0,2,31                    /* Clear MAS1 Valid and IPROT */
+       cmpw    r5,r6
+       beq     skpinv                          /* Dont update the current execution TLB */
+       mtspr   SPRN_MAS1,r7
+       tlbwe
+       isync
+skpinv:        addi    r6,r6,1                         /* Increment */
+       cmpw    r6,r4                           /* Are we done? */
+       bne     1b                              /* If not, repeat */
+
+       /* Invalidate all TLBs */
+       PPC_TLBILX_ALL(0,0)
+       sync
+       isync
+
+/* 3. Setup a temp mapping and jump to it
+ *
+ * r3 = MAS0 w/TLBSEL & ESEL for the entry we are running in
+ * r5 = ESEL of entry we are running in
+ */
+       andi.   r7,r5,0x1       /* Find an entry not used and is non-zero */
+       addi    r7,r7,0x1
+       mr      r4,r3           /* Set MAS0(TLBSEL) = 1 */
+       mtspr   SPRN_MAS0,r4
+       tlbre
+
+       rlwimi  r4,r7,16,4,15   /* Setup MAS0 = TLBSEL | ESEL(r7) */
+       mtspr   SPRN_MAS0,r4
+
+       mfspr   r7,SPRN_MAS1
+       xori    r6,r7,MAS1_TS           /* Setup TMP mapping in the other Address space */
+       mtspr   SPRN_MAS1,r6
+
+       tlbwe
+
+       mfmsr   r6
+       xori    r6,r6,MSR_IS
+       mtspr   SPRN_SRR1,r6
+       bl      1f              /* Find our address */
+1:     mflr    r6
+       addi    r6,r6,(2f - 1b)
+       mtspr   SPRN_SRR0,r6
+       rfi
+2:
+
+/* 4. Clear out PIDs & Search info
+ *
+ * r3 = MAS0 w/TLBSEL & ESEL for the entry we started in
+ * r4 = MAS0 w/TLBSEL & ESEL for the temp mapping
+ * r5 = MAS3
+ */
+       li      r6,0
+       mtspr   SPRN_MAS6,r6
+       mtspr   SPRN_PID,r6
+
+/* 5. Invalidate mapping we started in
+ *
+ * r3 = MAS0 w/TLBSEL & ESEL for the entry we started in
+ * r4 = MAS0 w/TLBSEL & ESEL for the temp mapping
+ * r5 = MAS3
+ */
+       mtspr   SPRN_MAS0,r3
+       tlbre
+       mfspr   r6,SPRN_MAS1
+       rlwinm  r6,r6,0,2,0     /* clear IPROT */
+       mtspr   SPRN_MAS1,r6
+       tlbwe
+
+       /* Invalidate TLB1 */
+       PPC_TLBILX_ALL(0,0)
+       sync
+       isync
+
+/* The mapping only needs to be cache-coherent on SMP */
+#ifdef CONFIG_SMP
+#define M_IF_SMP       MAS2_M
+#else
+#define M_IF_SMP       0
+#endif
+
+/* 6. Setup KERNELBASE mapping in TLB[0]
+ *
+ * r3 = MAS0 w/TLBSEL & ESEL for the entry we started in
+ * r4 = MAS0 w/TLBSEL & ESEL for the temp mapping
+ * r5 = MAS3
+ */
+       rlwinm  r3,r3,0,16,3    /* clear ESEL */
+       mtspr   SPRN_MAS0,r3
+       lis     r6,(MAS1_VALID|MAS1_IPROT)@h
+       ori     r6,r6,(MAS1_TSIZE(BOOK3E_PAGESZ_1GB))@l
+       mtspr   SPRN_MAS1,r6
+
+       LOAD_REG_IMMEDIATE(r6, PAGE_OFFSET | M_IF_SMP)
+       mtspr   SPRN_MAS2,r6
+
+       rlwinm  r5,r5,0,0,25
+       ori     r5,r5,MAS3_SR | MAS3_SW | MAS3_SX
+       mtspr   SPRN_MAS3,r5
+       li      r5,-1
+       rlwinm  r5,r5,0,0,25
+
+       tlbwe
+
+/* 7. Jump to KERNELBASE mapping
+ *
+ * r4 = MAS0 w/TLBSEL & ESEL for the temp mapping
+ */
+       /* Now we branch the new virtual address mapped by this entry */
+       LOAD_REG_IMMEDIATE(r6,2f)
+       lis     r7,MSR_KERNEL@h
+       ori     r7,r7,MSR_KERNEL@l
+       mtspr   SPRN_SRR0,r6
+       mtspr   SPRN_SRR1,r7
+       rfi                             /* start execution out of TLB1[0] entry */
+2:
+
+/* 8. Clear out the temp mapping
+ *
+ * r4 = MAS0 w/TLBSEL & ESEL for the entry we are running in
+ */
+       mtspr   SPRN_MAS0,r4
+       tlbre
+       mfspr   r5,SPRN_MAS1
+       rlwinm  r5,r5,0,2,0     /* clear IPROT */
+       mtspr   SPRN_MAS1,r5
+       tlbwe
+
+       /* Invalidate TLB1 */
+       PPC_TLBILX_ALL(0,0)
+       sync
+       isync
+
+       /* We translate LR and return */
+       tovirt(r8,r8)
+       mtlr    r8
+       blr
+
+have_hes:
+       /* Setup MAS 0,1,2,3 and 7 for tlbwe of a 1G entry that maps the
+        * kernel linear mapping. We also set MAS8 once for all here though
+        * that will have to be made dependent on whether we are running under
+        * a hypervisor I suppose.
+        */
+       ori     r3,r3,MAS0_HES | MAS0_WQ_ALLWAYS
+       mtspr   SPRN_MAS0,r3
+       lis     r3,(MAS1_VALID | MAS1_IPROT)@h
+       ori     r3,r3,BOOK3E_PAGESZ_1GB << MAS1_TSIZE_SHIFT
+       mtspr   SPRN_MAS1,r3
+       LOAD_REG_IMMEDIATE(r3, PAGE_OFFSET | MAS2_M)
+       mtspr   SPRN_MAS2,r3
+       li      r3,MAS3_SR | MAS3_SW | MAS3_SX
+       mtspr   SPRN_MAS7_MAS3,r3
+       li      r3,0
+       mtspr   SPRN_MAS8,r3
+
+       /* Write the TLB entry */
+       tlbwe
+
+       /* Now we branch the new virtual address mapped by this entry */
+       LOAD_REG_IMMEDIATE(r3,1f)
+       mtctr   r3
+       bctr
+
+1:     /* We are now running at PAGE_OFFSET, clean the TLB of everything
+        * else (XXX we should scan for bolted crap from the firmware too)
+        */
+       PPC_TLBILX(0,0,0)
+       sync
+       isync
+
+       /* We translate LR and return */
+       mflr    r3
+       tovirt(r3,r3)
+       mtlr    r3
+       blr
+
+/*
+ * Main entry (boot CPU, thread 0)
+ *
+ * We enter here from head_64.S, possibly after the prom_init trampoline
+ * with r3 and r4 already saved to r31 and 30 respectively and in 64 bits
+ * mode. Anything else is as it was left by the bootloader
+ *
+ * Initial requirements of this port:
+ *
+ * - Kernel loaded at 0 physical
+ * - A good lump of memory mapped 0:0 by UTLB entry 0
+ * - MSR:IS & MSR:DS set to 0
+ *
+ * Note that some of the above requirements will be relaxed in the future
+ * as the kernel becomes smarter at dealing with different initial conditions
+ * but for now you have to be careful
+ */
+_GLOBAL(start_initialization_book3e)
+       mflr    r28
+
+       /* First, we need to setup some initial TLBs to map the kernel
+        * text, data and bss at PAGE_OFFSET. We don't have a real mode
+        * and always use AS 0, so we just set it up to match our link
+        * address and never use 0 based addresses.
+        */
+       bl      .initial_tlb_book3e
+
+       /* Init global core bits */
+       bl      .init_core_book3e
+
+       /* Init per-thread bits */
+       bl      .init_thread_book3e
+
+       /* Return to common init code */
+       tovirt(r28,r28)
+       mtlr    r28
+       blr
+
+
+/*
+ * Secondary core/processor entry
+ *
+ * This is entered for thread 0 of a secondary core, all other threads
+ * are expected to be stopped. It's similar to start_initialization_book3e
+ * except that it's generally entered from the holding loop in head_64.S
+ * after CPUs have been gathered by Open Firmware.
+ *
+ * We assume we are in 32 bits mode running with whatever TLB entry was
+ * set for us by the firmware or POR engine.
+ */
+_GLOBAL(book3e_secondary_core_init_tlb_set)
+       li      r4,1
+       b       .generic_secondary_smp_init
+
+_GLOBAL(book3e_secondary_core_init)
+       mflr    r28
+
+       /* Do we need to setup initial TLB entry ? */
+       cmplwi  r4,0
+       bne     2f
+
+       /* Setup TLB for this core */
+       bl      .initial_tlb_book3e
+
+       /* We can return from the above running at a different
+        * address, so recalculate r2 (TOC)
+        */
+       bl      .relative_toc
+
+       /* Init global core bits */
+2:     bl      .init_core_book3e
+
+       /* Init per-thread bits */
+3:     bl      .init_thread_book3e
+
+       /* Return to common init code at proper virtual address.
+        *
+        * Due to various previous assumptions, we know we entered this
+        * function at either the final PAGE_OFFSET mapping or using a
+        * 1:1 mapping at 0, so we don't bother doing a complicated check
+        * here, we just ensure the return address has the right top bits.
+        *
+        * Note that if we ever want to be smarter about where we can be
+        * started from, we have to be careful that by the time we reach
+        * the code below we may already be running at a different location
+        * than the one we were called from since initial_tlb_book3e can
+        * have moved us already.
+        */
+       cmpdi   cr0,r28,0
+       blt     1f
+       lis     r3,PAGE_OFFSET@highest
+       sldi    r3,r3,32
+       or      r28,r28,r3
+1:     mtlr    r28
+       blr
+
+_GLOBAL(book3e_secondary_thread_init)
+       mflr    r28
+       b       3b
+
+_STATIC(init_core_book3e)
+       /* Establish the interrupt vector base */
+       LOAD_REG_IMMEDIATE(r3, interrupt_base_book3e)
+       mtspr   SPRN_IVPR,r3
+       sync
+       blr
+
+_STATIC(init_thread_book3e)
+       lis     r3,(SPRN_EPCR_ICM | SPRN_EPCR_GICM)@h
+       mtspr   SPRN_EPCR,r3
+
+       /* Make sure interrupts are off */
+       wrteei  0
+
+       /* disable all timers and clear out status */
+       li      r3,0
+       mtspr   SPRN_TCR,r3
+       mfspr   r3,SPRN_TSR
+       mtspr   SPRN_TSR,r3
+
+       blr
+
+_GLOBAL(__setup_base_ivors)
+       SET_IVOR(0, 0x020) /* Critical Input */
+       SET_IVOR(1, 0x000) /* Machine Check */
+       SET_IVOR(2, 0x060) /* Data Storage */ 
+       SET_IVOR(3, 0x080) /* Instruction Storage */
+       SET_IVOR(4, 0x0a0) /* External Input */ 
+       SET_IVOR(5, 0x0c0) /* Alignment */ 
+       SET_IVOR(6, 0x0e0) /* Program */ 
+       SET_IVOR(7, 0x100) /* FP Unavailable */ 
+       SET_IVOR(8, 0x120) /* System Call */ 
+       SET_IVOR(9, 0x140) /* Auxiliary Processor Unavailable */ 
+       SET_IVOR(10, 0x160) /* Decrementer */ 
+       SET_IVOR(11, 0x180) /* Fixed Interval Timer */ 
+       SET_IVOR(12, 0x1a0) /* Watchdog Timer */ 
+       SET_IVOR(13, 0x1c0) /* Data TLB Error */ 
+       SET_IVOR(14, 0x1e0) /* Instruction TLB Error */
+       SET_IVOR(15, 0x040) /* Debug */
+
+       sync
+
+       blr
index 8ac85e08ffae04613ea8da1adfa57aeabc2e4035..1808876edcc91d4f43fdff8fde2c8e1770fc832f 100644 (file)
@@ -12,6 +12,8 @@
  *
  */
 
+#include <asm/exception-64s.h>
+
 /*
  * We layout physical memory as follows:
  * 0x0000 - 0x00ff : Secondary processor spin code
  * 0x8000 -        : Early init and support code
  */
 
-
-/*
- *   SPRG Usage
- *
- *   Register  Definition
- *
- *   SPRG0     reserved for hypervisor
- *   SPRG1     temp - used to save gpr
- *   SPRG2     temp - used to save gpr
- *   SPRG3     virt addr of paca
- */
-
 /*
  * This is the start of the interrupt handlers for pSeries
  * This code runs with relocation off.
@@ -51,34 +41,44 @@ __start_interrupts:
        . = 0x200
 _machine_check_pSeries:
        HMT_MEDIUM
-       mtspr   SPRN_SPRG1,r13          /* save r13 */
+       mtspr   SPRN_SPRG_SCRATCH0,r13          /* save r13 */
        EXCEPTION_PROLOG_PSERIES(PACA_EXMC, machine_check_common)
 
        . = 0x300
        .globl data_access_pSeries
 data_access_pSeries:
        HMT_MEDIUM
-       mtspr   SPRN_SPRG1,r13
+       mtspr   SPRN_SPRG_SCRATCH0,r13
 BEGIN_FTR_SECTION
-       mtspr   SPRN_SPRG2,r12
-       mfspr   r13,SPRN_DAR
-       mfspr   r12,SPRN_DSISR
-       srdi    r13,r13,60
-       rlwimi  r13,r12,16,0x20
-       mfcr    r12
-       cmpwi   r13,0x2c
+       mfspr   r13,SPRN_SPRG_PACA
+       std     r9,PACA_EXSLB+EX_R9(r13)
+       std     r10,PACA_EXSLB+EX_R10(r13)
+       mfspr   r10,SPRN_DAR
+       mfspr   r9,SPRN_DSISR
+       srdi    r10,r10,60
+       rlwimi  r10,r9,16,0x20
+       mfcr    r9
+       cmpwi   r10,0x2c
        beq     do_stab_bolted_pSeries
-       mtcrf   0x80,r12
-       mfspr   r12,SPRN_SPRG2
-END_FTR_SECTION_IFCLR(CPU_FTR_SLB)
+       ld      r10,PACA_EXSLB+EX_R10(r13)
+       std     r11,PACA_EXGEN+EX_R11(r13)
+       ld      r11,PACA_EXSLB+EX_R9(r13)
+       std     r12,PACA_EXGEN+EX_R12(r13)
+       mfspr   r12,SPRN_SPRG_SCRATCH0
+       std     r10,PACA_EXGEN+EX_R10(r13)
+       std     r11,PACA_EXGEN+EX_R9(r13)
+       std     r12,PACA_EXGEN+EX_R13(r13)
+       EXCEPTION_PROLOG_PSERIES_1(data_access_common)
+FTR_SECTION_ELSE
        EXCEPTION_PROLOG_PSERIES(PACA_EXGEN, data_access_common)
+ALT_FTR_SECTION_END_IFCLR(CPU_FTR_SLB)
 
        . = 0x380
        .globl data_access_slb_pSeries
 data_access_slb_pSeries:
        HMT_MEDIUM
-       mtspr   SPRN_SPRG1,r13
-       mfspr   r13,SPRN_SPRG3          /* get paca address into r13 */
+       mtspr   SPRN_SPRG_SCRATCH0,r13
+       mfspr   r13,SPRN_SPRG_PACA              /* get paca address into r13 */
        std     r3,PACA_EXSLB+EX_R3(r13)
        mfspr   r3,SPRN_DAR
        std     r9,PACA_EXSLB+EX_R9(r13)        /* save r9 - r12 */
@@ -91,7 +91,7 @@ data_access_slb_pSeries:
        std     r10,PACA_EXSLB+EX_R10(r13)
        std     r11,PACA_EXSLB+EX_R11(r13)
        std     r12,PACA_EXSLB+EX_R12(r13)
-       mfspr   r10,SPRN_SPRG1
+       mfspr   r10,SPRN_SPRG_SCRATCH0
        std     r10,PACA_EXSLB+EX_R13(r13)
        mfspr   r12,SPRN_SRR1           /* and SRR1 */
 #ifndef CONFIG_RELOCATABLE
@@ -115,8 +115,8 @@ data_access_slb_pSeries:
        .globl instruction_access_slb_pSeries
 instruction_access_slb_pSeries:
        HMT_MEDIUM
-       mtspr   SPRN_SPRG1,r13
-       mfspr   r13,SPRN_SPRG3          /* get paca address into r13 */
+       mtspr   SPRN_SPRG_SCRATCH0,r13
+       mfspr   r13,SPRN_SPRG_PACA              /* get paca address into r13 */
        std     r3,PACA_EXSLB+EX_R3(r13)
        mfspr   r3,SPRN_SRR0            /* SRR0 is faulting address */
        std     r9,PACA_EXSLB+EX_R9(r13)        /* save r9 - r12 */
@@ -129,7 +129,7 @@ instruction_access_slb_pSeries:
        std     r10,PACA_EXSLB+EX_R10(r13)
        std     r11,PACA_EXSLB+EX_R11(r13)
        std     r12,PACA_EXSLB+EX_R12(r13)
-       mfspr   r10,SPRN_SPRG1
+       mfspr   r10,SPRN_SPRG_SCRATCH0
        std     r10,PACA_EXSLB+EX_R13(r13)
        mfspr   r12,SPRN_SRR1           /* and SRR1 */
 #ifndef CONFIG_RELOCATABLE
@@ -159,7 +159,7 @@ BEGIN_FTR_SECTION
        beq-    1f
 END_FTR_SECTION_IFSET(CPU_FTR_REAL_LE)
        mr      r9,r13
-       mfspr   r13,SPRN_SPRG3
+       mfspr   r13,SPRN_SPRG_PACA
        mfspr   r11,SPRN_SRR0
        ld      r12,PACAKBASE(r13)
        ld      r10,PACAKMSR(r13)
@@ -228,15 +228,17 @@ masked_interrupt:
        rotldi  r10,r10,16
        mtspr   SPRN_SRR1,r10
        ld      r10,PACA_EXGEN+EX_R10(r13)
-       mfspr   r13,SPRN_SPRG1
+       mfspr   r13,SPRN_SPRG_SCRATCH0
        rfid
        b       .
 
        .align  7
 do_stab_bolted_pSeries:
-       mtcrf   0x80,r12
-       mfspr   r12,SPRN_SPRG2
-       EXCEPTION_PROLOG_PSERIES(PACA_EXSLB, .do_stab_bolted)
+       std     r11,PACA_EXSLB+EX_R11(r13)
+       std     r12,PACA_EXSLB+EX_R12(r13)
+       mfspr   r10,SPRN_SPRG_SCRATCH0
+       std     r10,PACA_EXSLB+EX_R13(r13)
+       EXCEPTION_PROLOG_PSERIES_1(.do_stab_bolted)
 
 #ifdef CONFIG_PPC_PSERIES
 /*
@@ -246,14 +248,14 @@ do_stab_bolted_pSeries:
       .align 7
 system_reset_fwnmi:
        HMT_MEDIUM
-       mtspr   SPRN_SPRG1,r13          /* save r13 */
+       mtspr   SPRN_SPRG_SCRATCH0,r13          /* save r13 */
        EXCEPTION_PROLOG_PSERIES(PACA_EXGEN, system_reset_common)
 
        .globl machine_check_fwnmi
       .align 7
 machine_check_fwnmi:
        HMT_MEDIUM
-       mtspr   SPRN_SPRG1,r13          /* save r13 */
+       mtspr   SPRN_SPRG_SCRATCH0,r13          /* save r13 */
        EXCEPTION_PROLOG_PSERIES(PACA_EXMC, machine_check_common)
 
 #endif /* CONFIG_PPC_PSERIES */
@@ -268,7 +270,7 @@ slb_miss_user_pseries:
        std     r10,PACA_EXGEN+EX_R10(r13)
        std     r11,PACA_EXGEN+EX_R11(r13)
        std     r12,PACA_EXGEN+EX_R12(r13)
-       mfspr   r10,SPRG1
+       mfspr   r10,SPRG_SCRATCH0
        ld      r11,PACA_EXSLB+EX_R9(r13)
        ld      r12,PACA_EXSLB+EX_R3(r13)
        std     r10,PACA_EXGEN+EX_R13(r13)
index 2436df33c6f4433d7e7f54b88caad6ba570cf3f6..fc8f5b14019c515ba870868b7789799ca9efd1a0 100644 (file)
@@ -91,7 +91,7 @@ END_FTR_SECTION_IFSET(CPU_FTR_VSX)
 #endif /* CONFIG_SMP */
        /* enable use of FP after return */
 #ifdef CONFIG_PPC32
-       mfspr   r5,SPRN_SPRG3           /* current task's THREAD (phys) */
+       mfspr   r5,SPRN_SPRG_THREAD             /* current task's THREAD (phys) */
        lwz     r4,THREAD_FPEXC_MODE(r5)
        ori     r9,r9,MSR_FP            /* enable FP for current */
        or      r9,r9,r4
index fc2132942754e06e09c5f6c169143da89b0b2761..829c3fe7c5a2384c6535cbc9a7da69b32ef76157 100644 (file)
@@ -244,8 +244,8 @@ __secondary_hold_acknowledge:
  * task's thread_struct.
  */
 #define EXCEPTION_PROLOG       \
-       mtspr   SPRN_SPRG0,r10; \
-       mtspr   SPRN_SPRG1,r11; \
+       mtspr   SPRN_SPRG_SCRATCH0,r10; \
+       mtspr   SPRN_SPRG_SCRATCH1,r11; \
        mfcr    r10;            \
        EXCEPTION_PROLOG_1;     \
        EXCEPTION_PROLOG_2
@@ -255,7 +255,7 @@ __secondary_hold_acknowledge:
        andi.   r11,r11,MSR_PR; \
        tophys(r11,r1);                 /* use tophys(r1) if kernel */ \
        beq     1f;             \
-       mfspr   r11,SPRN_SPRG3; \
+       mfspr   r11,SPRN_SPRG_THREAD;   \
        lwz     r11,THREAD_INFO-THREAD(r11);    \
        addi    r11,r11,THREAD_SIZE;    \
        tophys(r11,r11);        \
@@ -267,9 +267,9 @@ __secondary_hold_acknowledge:
        stw     r10,_CCR(r11);          /* save registers */ \
        stw     r12,GPR12(r11); \
        stw     r9,GPR9(r11);   \
-       mfspr   r10,SPRN_SPRG0; \
+       mfspr   r10,SPRN_SPRG_SCRATCH0; \
        stw     r10,GPR10(r11); \
-       mfspr   r12,SPRN_SPRG1; \
+       mfspr   r12,SPRN_SPRG_SCRATCH1; \
        stw     r12,GPR11(r11); \
        mflr    r10;            \
        stw     r10,_LINK(r11); \
@@ -355,11 +355,11 @@ i##n:                                                             \
  *     -- paulus.
  */
        . = 0x200
-       mtspr   SPRN_SPRG0,r10
-       mtspr   SPRN_SPRG1,r11
+       mtspr   SPRN_SPRG_SCRATCH0,r10
+       mtspr   SPRN_SPRG_SCRATCH1,r11
        mfcr    r10
 #ifdef CONFIG_PPC_CHRP
-       mfspr   r11,SPRN_SPRG2
+       mfspr   r11,SPRN_SPRG_RTAS
        cmpwi   0,r11,0
        bne     7f
 #endif /* CONFIG_PPC_CHRP */
@@ -367,7 +367,7 @@ i##n:                                                               \
 7:     EXCEPTION_PROLOG_2
        addi    r3,r1,STACK_FRAME_OVERHEAD
 #ifdef CONFIG_PPC_CHRP
-       mfspr   r4,SPRN_SPRG2
+       mfspr   r4,SPRN_SPRG_RTAS
        cmpwi   cr1,r4,0
        bne     cr1,1f
 #endif
@@ -485,7 +485,7 @@ InstructionTLBMiss:
        mfspr   r3,SPRN_IMISS
        lis     r1,PAGE_OFFSET@h                /* check if kernel address */
        cmplw   0,r1,r3
-       mfspr   r2,SPRN_SPRG3
+       mfspr   r2,SPRN_SPRG_THREAD
        li      r1,_PAGE_USER|_PAGE_PRESENT /* low addresses tested as user */
        lwz     r2,PGDIR(r2)
        bge-    112f
@@ -559,7 +559,7 @@ DataLoadTLBMiss:
        mfspr   r3,SPRN_DMISS
        lis     r1,PAGE_OFFSET@h                /* check if kernel address */
        cmplw   0,r1,r3
-       mfspr   r2,SPRN_SPRG3
+       mfspr   r2,SPRN_SPRG_THREAD
        li      r1,_PAGE_USER|_PAGE_PRESENT /* low addresses tested as user */
        lwz     r2,PGDIR(r2)
        bge-    112f
@@ -598,12 +598,12 @@ END_FTR_SECTION_IFCLR(CPU_FTR_NEED_COHERENT)
        mtcrf   0x80,r2
 BEGIN_MMU_FTR_SECTION
        li      r0,1
-       mfspr   r1,SPRN_SPRG4
+       mfspr   r1,SPRN_SPRG_603_LRU
        rlwinm  r2,r3,20,27,31          /* Get Address bits 15:19 */
        slw     r0,r0,r2
        xor     r1,r0,r1
        srw     r0,r1,r2
-       mtspr   SPRN_SPRG4,r1
+       mtspr   SPRN_SPRG_603_LRU,r1
        mfspr   r2,SPRN_SRR1
        rlwimi  r2,r0,31-14,14,14
        mtspr   SPRN_SRR1,r2
@@ -643,7 +643,7 @@ DataStoreTLBMiss:
        mfspr   r3,SPRN_DMISS
        lis     r1,PAGE_OFFSET@h                /* check if kernel address */
        cmplw   0,r1,r3
-       mfspr   r2,SPRN_SPRG3
+       mfspr   r2,SPRN_SPRG_THREAD
        li      r1,_PAGE_RW|_PAGE_USER|_PAGE_PRESENT /* access flags */
        lwz     r2,PGDIR(r2)
        bge-    112f
@@ -678,12 +678,12 @@ END_FTR_SECTION_IFCLR(CPU_FTR_NEED_COHERENT)
        mtcrf   0x80,r2
 BEGIN_MMU_FTR_SECTION
        li      r0,1
-       mfspr   r1,SPRN_SPRG4
+       mfspr   r1,SPRN_SPRG_603_LRU
        rlwinm  r2,r3,20,27,31          /* Get Address bits 15:19 */
        slw     r0,r0,r2
        xor     r1,r0,r1
        srw     r0,r1,r2
-       mtspr   SPRN_SPRG4,r1
+       mtspr   SPRN_SPRG_603_LRU,r1
        mfspr   r2,SPRN_SRR1
        rlwimi  r2,r0,31-14,14,14
        mtspr   SPRN_SRR1,r2
@@ -864,9 +864,9 @@ __secondary_start:
        tophys(r4,r2)
        addi    r4,r4,THREAD    /* phys address of our thread_struct */
        CLR_TOP32(r4)
-       mtspr   SPRN_SPRG3,r4
+       mtspr   SPRN_SPRG_THREAD,r4
        li      r3,0
-       mtspr   SPRN_SPRG2,r3   /* 0 => not in RTAS */
+       mtspr   SPRN_SPRG_RTAS,r3       /* 0 => not in RTAS */
 
        /* enable MMU and jump to start_secondary */
        li      r4,MSR_KERNEL
@@ -947,9 +947,9 @@ start_here:
        tophys(r4,r2)
        addi    r4,r4,THREAD    /* init task's THREAD */
        CLR_TOP32(r4)
-       mtspr   SPRN_SPRG3,r4
+       mtspr   SPRN_SPRG_THREAD,r4
        li      r3,0
-       mtspr   SPRN_SPRG2,r3   /* 0 => not in RTAS */
+       mtspr   SPRN_SPRG_RTAS,r3       /* 0 => not in RTAS */
 
        /* stack */
        lis     r1,init_thread_union@ha
index 0c96911d4299951181f5366a8023724ceb716f71..a90625f9b48517bdca205774dc71a962ec698d91 100644 (file)
@@ -103,21 +103,21 @@ _ENTRY(saved_ksp_limit)
 
 /*
  * Exception vector entry code. This code runs with address translation
- * turned off (i.e. using physical addresses). We assume SPRG3 has the
- * physical address of the current task thread_struct.
+ * turned off (i.e. using physical addresses). We assume SPRG_THREAD has
+ * the physical address of the current task thread_struct.
  * Note that we have to have decremented r1 before we write to any fields
  * of the exception frame, since a critical interrupt could occur at any
  * time, and it will write to the area immediately below the current r1.
  */
 #define NORMAL_EXCEPTION_PROLOG                                                     \
-       mtspr   SPRN_SPRG0,r10;         /* save two registers to work with */\
-       mtspr   SPRN_SPRG1,r11;                                              \
-       mtspr   SPRN_SPRG2,r1;                                               \
+       mtspr   SPRN_SPRG_SCRATCH0,r10; /* save two registers to work with */\
+       mtspr   SPRN_SPRG_SCRATCH1,r11;                                      \
+       mtspr   SPRN_SPRG_SCRATCH2,r1;                                       \
        mfcr    r10;                    /* save CR in r10 for now          */\
        mfspr   r11,SPRN_SRR1;          /* check whether user or kernel    */\
        andi.   r11,r11,MSR_PR;                                              \
        beq     1f;                                                          \
-       mfspr   r1,SPRN_SPRG3;          /* if from user, start at top of   */\
+       mfspr   r1,SPRN_SPRG_THREAD;    /* if from user, start at top of   */\
        lwz     r1,THREAD_INFO-THREAD(r1); /* this thread's kernel stack   */\
        addi    r1,r1,THREAD_SIZE;                                           \
 1:     subi    r1,r1,INT_FRAME_SIZE;   /* Allocate an exception frame     */\
@@ -125,13 +125,13 @@ _ENTRY(saved_ksp_limit)
        stw     r10,_CCR(r11);          /* save various registers          */\
        stw     r12,GPR12(r11);                                              \
        stw     r9,GPR9(r11);                                                \
-       mfspr   r10,SPRN_SPRG0;                                              \
+       mfspr   r10,SPRN_SPRG_SCRATCH0;                                      \
        stw     r10,GPR10(r11);                                              \
-       mfspr   r12,SPRN_SPRG1;                                              \
+       mfspr   r12,SPRN_SPRG_SCRATCH1;                                      \
        stw     r12,GPR11(r11);                                              \
        mflr    r10;                                                         \
        stw     r10,_LINK(r11);                                              \
-       mfspr   r10,SPRN_SPRG2;                                              \
+       mfspr   r10,SPRN_SPRG_SCRATCH2;                                      \
        mfspr   r12,SPRN_SRR0;                                               \
        stw     r10,GPR1(r11);                                               \
        mfspr   r9,SPRN_SRR1;                                                \
@@ -160,7 +160,7 @@ _ENTRY(saved_ksp_limit)
        lwz     r11,critirq_ctx@l(r11);                                      \
        beq     1f;                                                          \
        /* COMING FROM USER MODE */                                          \
-       mfspr   r11,SPRN_SPRG3;         /* if from user, start at top of   */\
+       mfspr   r11,SPRN_SPRG_THREAD;   /* if from user, start at top of   */\
        lwz     r11,THREAD_INFO-THREAD(r11); /* this thread's kernel stack */\
 1:     addi    r11,r11,THREAD_SIZE-INT_FRAME_SIZE; /* Alloc an excpt frm  */\
        tophys(r11,r11);                                                     \
@@ -265,8 +265,8 @@ label:
  * and exit.  Otherwise, we call heavywight functions to do the work.
  */
        START_EXCEPTION(0x0300, DataStorage)
-       mtspr   SPRN_SPRG0, r10         /* Save some working registers */
-       mtspr   SPRN_SPRG1, r11
+       mtspr   SPRN_SPRG_SCRATCH0, r10 /* Save some working registers */
+       mtspr   SPRN_SPRG_SCRATCH1, r11
 #ifdef CONFIG_403GCX
        stw     r12, 0(r0)
        stw     r9, 4(r0)
@@ -275,12 +275,12 @@ label:
        stw     r11, 8(r0)
        stw     r12, 12(r0)
 #else
-       mtspr   SPRN_SPRG4, r12
-       mtspr   SPRN_SPRG5, r9
+       mtspr   SPRN_SPRG_SCRATCH3, r12
+       mtspr   SPRN_SPRG_SCRATCH4, r9
        mfcr    r11
        mfspr   r12, SPRN_PID
-       mtspr   SPRN_SPRG7, r11
-       mtspr   SPRN_SPRG6, r12
+       mtspr   SPRN_SPRG_SCRATCH6, r11
+       mtspr   SPRN_SPRG_SCRATCH5, r12
 #endif
 
        /* First, check if it was a zone fault (which means a user
@@ -308,7 +308,7 @@ label:
        /* Get the PGD for the current thread.
         */
 3:
-       mfspr   r11,SPRN_SPRG3
+       mfspr   r11,SPRN_SPRG_THREAD
        lwz     r11,PGDIR(r11)
 4:
        tophys(r11, r11)
@@ -355,15 +355,15 @@ label:
        lwz     r9, 4(r0)
        lwz     r12, 0(r0)
 #else
-       mfspr   r12, SPRN_SPRG6
-       mfspr   r11, SPRN_SPRG7
+       mfspr   r12, SPRN_SPRG_SCRATCH5
+       mfspr   r11, SPRN_SPRG_SCRATCH6
        mtspr   SPRN_PID, r12
        mtcr    r11
-       mfspr   r9, SPRN_SPRG5
-       mfspr   r12, SPRN_SPRG4
+       mfspr   r9, SPRN_SPRG_SCRATCH4
+       mfspr   r12, SPRN_SPRG_SCRATCH3
 #endif
-       mfspr   r11, SPRN_SPRG1
-       mfspr   r10, SPRN_SPRG0
+       mfspr   r11, SPRN_SPRG_SCRATCH1
+       mfspr   r10, SPRN_SPRG_SCRATCH0
        PPC405_ERR77_SYNC
        rfi                     /* Should sync shadow TLBs */
        b       .               /* prevent prefetch past rfi */
@@ -380,15 +380,15 @@ label:
        lwz     r9, 4(r0)
        lwz     r12, 0(r0)
 #else
-       mfspr   r12, SPRN_SPRG6
-       mfspr   r11, SPRN_SPRG7
+       mfspr   r12, SPRN_SPRG_SCRATCH5
+       mfspr   r11, SPRN_SPRG_SCRATCH6
        mtspr   SPRN_PID, r12
        mtcr    r11
-       mfspr   r9, SPRN_SPRG5
-       mfspr   r12, SPRN_SPRG4
+       mfspr   r9, SPRN_SPRG_SCRATCH4
+       mfspr   r12, SPRN_SPRG_SCRATCH3
 #endif
-       mfspr   r11, SPRN_SPRG1
-       mfspr   r10, SPRN_SPRG0
+       mfspr   r11, SPRN_SPRG_SCRATCH1
+       mfspr   r10, SPRN_SPRG_SCRATCH0
        b       DataAccess
 
 /*
@@ -466,8 +466,8 @@ label:
  * load TLB entries from the page table if they exist.
  */
        START_EXCEPTION(0x1100, DTLBMiss)
-       mtspr   SPRN_SPRG0, r10         /* Save some working registers */
-       mtspr   SPRN_SPRG1, r11
+       mtspr   SPRN_SPRG_SCRATCH0, r10 /* Save some working registers */
+       mtspr   SPRN_SPRG_SCRATCH1, r11
 #ifdef CONFIG_403GCX
        stw     r12, 0(r0)
        stw     r9, 4(r0)
@@ -476,12 +476,12 @@ label:
        stw     r11, 8(r0)
        stw     r12, 12(r0)
 #else
-       mtspr   SPRN_SPRG4, r12
-       mtspr   SPRN_SPRG5, r9
+       mtspr   SPRN_SPRG_SCRATCH3, r12
+       mtspr   SPRN_SPRG_SCRATCH4, r9
        mfcr    r11
        mfspr   r12, SPRN_PID
-       mtspr   SPRN_SPRG7, r11
-       mtspr   SPRN_SPRG6, r12
+       mtspr   SPRN_SPRG_SCRATCH6, r11
+       mtspr   SPRN_SPRG_SCRATCH5, r12
 #endif
        mfspr   r10, SPRN_DEAR          /* Get faulting address */
 
@@ -500,7 +500,7 @@ label:
        /* Get the PGD for the current thread.
         */
 3:
-       mfspr   r11,SPRN_SPRG3
+       mfspr   r11,SPRN_SPRG_THREAD
        lwz     r11,PGDIR(r11)
 4:
        tophys(r11, r11)
@@ -550,15 +550,15 @@ label:
        lwz     r9, 4(r0)
        lwz     r12, 0(r0)
 #else
-       mfspr   r12, SPRN_SPRG6
-       mfspr   r11, SPRN_SPRG7
+       mfspr   r12, SPRN_SPRG_SCRATCH5
+       mfspr   r11, SPRN_SPRG_SCRATCH6
        mtspr   SPRN_PID, r12
        mtcr    r11
-       mfspr   r9, SPRN_SPRG5
-       mfspr   r12, SPRN_SPRG4
+       mfspr   r9, SPRN_SPRG_SCRATCH4
+       mfspr   r12, SPRN_SPRG_SCRATCH3
 #endif
-       mfspr   r11, SPRN_SPRG1
-       mfspr   r10, SPRN_SPRG0
+       mfspr   r11, SPRN_SPRG_SCRATCH1
+       mfspr   r10, SPRN_SPRG_SCRATCH0
        b       DataAccess
 
 /* 0x1200 - Instruction TLB Miss Exception
@@ -566,8 +566,8 @@ label:
  * registers and bailout to a different point.
  */
        START_EXCEPTION(0x1200, ITLBMiss)
-       mtspr   SPRN_SPRG0, r10         /* Save some working registers */
-       mtspr   SPRN_SPRG1, r11
+       mtspr   SPRN_SPRG_SCRATCH0, r10  /* Save some working registers */
+       mtspr   SPRN_SPRG_SCRATCH1, r11
 #ifdef CONFIG_403GCX
        stw     r12, 0(r0)
        stw     r9, 4(r0)
@@ -576,12 +576,12 @@ label:
        stw     r11, 8(r0)
        stw     r12, 12(r0)
 #else
-       mtspr   SPRN_SPRG4, r12
-       mtspr   SPRN_SPRG5, r9
+       mtspr   SPRN_SPRG_SCRATCH3, r12
+       mtspr   SPRN_SPRG_SCRATCH4, r9
        mfcr    r11
        mfspr   r12, SPRN_PID
-       mtspr   SPRN_SPRG7, r11
-       mtspr   SPRN_SPRG6, r12
+       mtspr   SPRN_SPRG_SCRATCH6, r11
+       mtspr   SPRN_SPRG_SCRATCH5, r12
 #endif
        mfspr   r10, SPRN_SRR0          /* Get faulting address */
 
@@ -600,7 +600,7 @@ label:
        /* Get the PGD for the current thread.
         */
 3:
-       mfspr   r11,SPRN_SPRG3
+       mfspr   r11,SPRN_SPRG_THREAD
        lwz     r11,PGDIR(r11)
 4:
        tophys(r11, r11)
@@ -650,15 +650,15 @@ label:
        lwz     r9, 4(r0)
        lwz     r12, 0(r0)
 #else
-       mfspr   r12, SPRN_SPRG6
-       mfspr   r11, SPRN_SPRG7
+       mfspr   r12, SPRN_SPRG_SCRATCH5
+       mfspr   r11, SPRN_SPRG_SCRATCH6
        mtspr   SPRN_PID, r12
        mtcr    r11
-       mfspr   r9, SPRN_SPRG5
-       mfspr   r12, SPRN_SPRG4
+       mfspr   r9, SPRN_SPRG_SCRATCH4
+       mfspr   r12, SPRN_SPRG_SCRATCH3
 #endif
-       mfspr   r11, SPRN_SPRG1
-       mfspr   r10, SPRN_SPRG0
+       mfspr   r11, SPRN_SPRG_SCRATCH1
+       mfspr   r10, SPRN_SPRG_SCRATCH0
        b       InstructionAccess
 
        EXCEPTION(0x1300, Trap_13, unknown_exception, EXC_XFER_EE)
@@ -803,15 +803,15 @@ finish_tlb_load:
        lwz     r9, 4(r0)
        lwz     r12, 0(r0)
 #else
-       mfspr   r12, SPRN_SPRG6
-       mfspr   r11, SPRN_SPRG7
+       mfspr   r12, SPRN_SPRG_SCRATCH5
+       mfspr   r11, SPRN_SPRG_SCRATCH6
        mtspr   SPRN_PID, r12
        mtcr    r11
-       mfspr   r9, SPRN_SPRG5
-       mfspr   r12, SPRN_SPRG4
+       mfspr   r9, SPRN_SPRG_SCRATCH4
+       mfspr   r12, SPRN_SPRG_SCRATCH3
 #endif
-       mfspr   r11, SPRN_SPRG1
-       mfspr   r10, SPRN_SPRG0
+       mfspr   r11, SPRN_SPRG_SCRATCH1
+       mfspr   r10, SPRN_SPRG_SCRATCH0
        PPC405_ERR77_SYNC
        rfi                     /* Should sync shadow TLBs */
        b       .               /* prevent prefetch past rfi */
@@ -835,7 +835,7 @@ start_here:
        /* ptr to phys current thread */
        tophys(r4,r2)
        addi    r4,r4,THREAD    /* init task's THREAD */
-       mtspr   SPRN_SPRG3,r4
+       mtspr   SPRN_SPRG_THREAD,r4
 
        /* stack */
        lis     r1,init_thread_union@ha
index 18d8a1677c4d76c2a5d411606fab5e9b8603f4dd..711368b993f2caabafdc972a299739ab13588933 100644 (file)
@@ -239,7 +239,7 @@ skpinv:     addi    r4,r4,1                         /* Increment */
 
        /* ptr to current thread */
        addi    r4,r2,THREAD    /* init task's THREAD */
-       mtspr   SPRN_SPRG3,r4
+       mtspr   SPRN_SPRG_THREAD,r4
 
        /* stack */
        lis     r1,init_thread_union@h
@@ -350,12 +350,12 @@ interrupt_base:
 
        /* Data TLB Error Interrupt */
        START_EXCEPTION(DataTLBError)
-       mtspr   SPRN_SPRG0, r10         /* Save some working registers */
-       mtspr   SPRN_SPRG1, r11
-       mtspr   SPRN_SPRG4W, r12
-       mtspr   SPRN_SPRG5W, r13
+       mtspr   SPRN_SPRG_WSCRATCH0, r10                /* Save some working registers */
+       mtspr   SPRN_SPRG_WSCRATCH1, r11
+       mtspr   SPRN_SPRG_WSCRATCH2, r12
+       mtspr   SPRN_SPRG_WSCRATCH3, r13
        mfcr    r11
-       mtspr   SPRN_SPRG7W, r11
+       mtspr   SPRN_SPRG_WSCRATCH4, r11
        mfspr   r10, SPRN_DEAR          /* Get faulting address */
 
        /* If we are faulting a kernel address, we have to use the
@@ -374,7 +374,7 @@ interrupt_base:
 
        /* Get the PGD for the current thread */
 3:
-       mfspr   r11,SPRN_SPRG3
+       mfspr   r11,SPRN_SPRG_THREAD
        lwz     r11,PGDIR(r11)
 
        /* Load PID into MMUCR TID */
@@ -446,12 +446,12 @@ tlb_44x_patch_hwater_D:
        /* The bailout.  Restore registers to pre-exception conditions
         * and call the heavyweights to help us out.
         */
-       mfspr   r11, SPRN_SPRG7R
+       mfspr   r11, SPRN_SPRG_RSCRATCH4
        mtcr    r11
-       mfspr   r13, SPRN_SPRG5R
-       mfspr   r12, SPRN_SPRG4R
-       mfspr   r11, SPRN_SPRG1
-       mfspr   r10, SPRN_SPRG0
+       mfspr   r13, SPRN_SPRG_RSCRATCH3
+       mfspr   r12, SPRN_SPRG_RSCRATCH2
+       mfspr   r11, SPRN_SPRG_RSCRATCH1
+       mfspr   r10, SPRN_SPRG_RSCRATCH0
        b       DataStorage
 
        /* Instruction TLB Error Interrupt */
@@ -461,12 +461,12 @@ tlb_44x_patch_hwater_D:
         * to a different point.
         */
        START_EXCEPTION(InstructionTLBError)
-       mtspr   SPRN_SPRG0, r10         /* Save some working registers */
-       mtspr   SPRN_SPRG1, r11
-       mtspr   SPRN_SPRG4W, r12
-       mtspr   SPRN_SPRG5W, r13
+       mtspr   SPRN_SPRG_WSCRATCH0, r10 /* Save some working registers */
+       mtspr   SPRN_SPRG_WSCRATCH1, r11
+       mtspr   SPRN_SPRG_WSCRATCH2, r12
+       mtspr   SPRN_SPRG_WSCRATCH3, r13
        mfcr    r11
-       mtspr   SPRN_SPRG7W, r11
+       mtspr   SPRN_SPRG_WSCRATCH4, r11
        mfspr   r10, SPRN_SRR0          /* Get faulting address */
 
        /* If we are faulting a kernel address, we have to use the
@@ -485,7 +485,7 @@ tlb_44x_patch_hwater_D:
 
        /* Get the PGD for the current thread */
 3:
-       mfspr   r11,SPRN_SPRG3
+       mfspr   r11,SPRN_SPRG_THREAD
        lwz     r11,PGDIR(r11)
 
        /* Load PID into MMUCR TID */
@@ -497,7 +497,7 @@ tlb_44x_patch_hwater_D:
        mtspr   SPRN_MMUCR,r12
 
        /* Make up the required permissions */
-       li      r13,_PAGE_PRESENT | _PAGE_ACCESSED | _PAGE_HWEXEC
+       li      r13,_PAGE_PRESENT | _PAGE_ACCESSED | _PAGE_EXEC
 
        /* Compute pgdir/pmd offset */
        rlwinm  r12, r10, PPC44x_PGD_OFF_SHIFT, PPC44x_PGD_OFF_MASK_BIT, 29
@@ -542,12 +542,12 @@ tlb_44x_patch_hwater_I:
        /* The bailout.  Restore registers to pre-exception conditions
         * and call the heavyweights to help us out.
         */
-       mfspr   r11, SPRN_SPRG7R
+       mfspr   r11, SPRN_SPRG_RSCRATCH4
        mtcr    r11
-       mfspr   r13, SPRN_SPRG5R
-       mfspr   r12, SPRN_SPRG4R
-       mfspr   r11, SPRN_SPRG1
-       mfspr   r10, SPRN_SPRG0
+       mfspr   r13, SPRN_SPRG_RSCRATCH3
+       mfspr   r12, SPRN_SPRG_RSCRATCH2
+       mfspr   r11, SPRN_SPRG_RSCRATCH1
+       mfspr   r10, SPRN_SPRG_RSCRATCH0
        b       InstructionStorage
 
        /* Debug Interrupt */
@@ -593,12 +593,12 @@ finish_tlb_load:
 
        /* Done...restore registers and get out of here.
        */
-       mfspr   r11, SPRN_SPRG7R
+       mfspr   r11, SPRN_SPRG_RSCRATCH4
        mtcr    r11
-       mfspr   r13, SPRN_SPRG5R
-       mfspr   r12, SPRN_SPRG4R
-       mfspr   r11, SPRN_SPRG1
-       mfspr   r10, SPRN_SPRG0
+       mfspr   r13, SPRN_SPRG_RSCRATCH3
+       mfspr   r12, SPRN_SPRG_RSCRATCH2
+       mfspr   r11, SPRN_SPRG_RSCRATCH1
+       mfspr   r10, SPRN_SPRG_RSCRATCH0
        rfi                                     /* Force context change */
 
 /*
index 012505ebd9f9223a7d6510c054ab02d769362c82..c38afdb45d7b066d2720d69a484f4c5a38ed71c0 100644 (file)
@@ -36,7 +36,6 @@
 #include <asm/thread_info.h>
 #include <asm/firmware.h>
 #include <asm/page_64.h>
-#include <asm/exception.h>
 #include <asm/irqflags.h>
 
 /* The physical memory is layed out such that the secondary processor
@@ -122,10 +121,11 @@ __run_at_load:
  */
        .globl  __secondary_hold
 __secondary_hold:
+#ifndef CONFIG_PPC_BOOK3E
        mfmsr   r24
        ori     r24,r24,MSR_RI
        mtmsrd  r24                     /* RI on */
-
+#endif
        /* Grab our physical cpu number */
        mr      r24,r3
 
@@ -144,6 +144,7 @@ __secondary_hold:
        ld      r4,0(r4)                /* deref function descriptor */
        mtctr   r4
        mr      r3,r24
+       li      r4,0
        bctr
 #else
        BUG_OPCODE
@@ -164,21 +165,49 @@ exception_marker:
 #include "exceptions-64s.S"
 #endif
 
+_GLOBAL(generic_secondary_thread_init)
+       mr      r24,r3
+
+       /* turn on 64-bit mode */
+       bl      .enable_64b_mode
+
+       /* get a valid TOC pointer, wherever we're mapped at */
+       bl      .relative_toc
+
+#ifdef CONFIG_PPC_BOOK3E
+       /* Book3E initialization */
+       mr      r3,r24
+       bl      .book3e_secondary_thread_init
+#endif
+       b       generic_secondary_common_init
 
 /*
  * On pSeries and most other platforms, secondary processors spin
  * in the following code.
  * At entry, r3 = this processor's number (physical cpu id)
+ *
+ * On Book3E, r4 = 1 to indicate that the initial TLB entry for
+ * this core already exists (setup via some other mechanism such
+ * as SCOM before entry).
  */
 _GLOBAL(generic_secondary_smp_init)
        mr      r24,r3
-       
+       mr      r25,r4
+
        /* turn on 64-bit mode */
        bl      .enable_64b_mode
 
-       /* get the TOC pointer (real address) */
+       /* get a valid TOC pointer, wherever we're mapped at */
        bl      .relative_toc
 
+#ifdef CONFIG_PPC_BOOK3E
+       /* Book3E initialization */
+       mr      r3,r24
+       mr      r4,r25
+       bl      .book3e_secondary_core_init
+#endif
+
+generic_secondary_common_init:
        /* Set up a paca value for this processor. Since we have the
         * physical cpu id in r24, we need to search the pacas to find
         * which logical id maps to our physical one.
@@ -196,7 +225,12 @@ _GLOBAL(generic_secondary_smp_init)
        mr      r3,r24                  /* not found, copy phys to r3    */
        b       .kexec_wait             /* next kernel might do better   */
 
-2:     mtspr   SPRN_SPRG3,r13          /* Save vaddr of paca in SPRG3   */
+2:     mtspr   SPRN_SPRG_PACA,r13      /* Save vaddr of paca in an SPRG */
+#ifdef CONFIG_PPC_BOOK3E
+       addi    r12,r13,PACA_EXTLB      /* and TLB exc frame in another  */
+       mtspr   SPRN_SPRG_TLB_EXFRAME,r12
+#endif
+
        /* From now on, r24 is expected to be logical cpuid */
        mr      r24,r5
 3:     HMT_LOW
@@ -232,6 +266,7 @@ _GLOBAL(generic_secondary_smp_init)
  * Turn the MMU off.
  * Assumes we're mapped EA == RA if the MMU is on.
  */
+#ifdef CONFIG_PPC_BOOK3S
 _STATIC(__mmu_off)
        mfmsr   r3
        andi.   r0,r3,MSR_IR|MSR_DR
@@ -243,6 +278,7 @@ _STATIC(__mmu_off)
        sync
        rfid
        b       .       /* prevent speculative execution */
+#endif
 
 
 /*
@@ -280,6 +316,10 @@ _GLOBAL(__start_initialization_multiplatform)
        mr      r31,r3
        mr      r30,r4
 
+#ifdef CONFIG_PPC_BOOK3E
+       bl      .start_initialization_book3e
+       b       .__after_prom_start
+#else
        /* Setup some critical 970 SPRs before switching MMU off */
        mfspr   r0,SPRN_PVR
        srwi    r0,r0,16
@@ -297,6 +337,7 @@ _GLOBAL(__start_initialization_multiplatform)
        /* Switch off MMU if not already off */
        bl      .__mmu_off
        b       .__after_prom_start
+#endif /* CONFIG_PPC_BOOK3E */
 
 _INIT_STATIC(__boot_from_prom)
 #ifdef CONFIG_PPC_OF_BOOT_TRAMPOLINE
@@ -359,10 +400,16 @@ _STATIC(__after_prom_start)
  * Note: This process overwrites the OF exception vectors.
  */
        li      r3,0                    /* target addr */
+#ifdef CONFIG_PPC_BOOK3E
+       tovirt(r3,r3)                   /* on booke, we already run at PAGE_OFFSET */
+#endif
        mr.     r4,r26                  /* In some cases the loader may  */
        beq     9f                      /* have already put us at zero */
        li      r6,0x100                /* Start offset, the first 0x100 */
                                        /* bytes were copied earlier.    */
+#ifdef CONFIG_PPC_BOOK3E
+       tovirt(r6,r6)                   /* on booke, we already run at PAGE_OFFSET */
+#endif
 
 #ifdef CONFIG_CRASH_DUMP
 /*
@@ -485,7 +532,7 @@ _GLOBAL(pmac_secondary_start)
        LOAD_REG_ADDR(r4,paca)          /* Get base vaddr of paca array */
        mulli   r13,r24,PACA_SIZE       /* Calculate vaddr of right paca */
        add     r13,r13,r4              /* for this processor.          */
-       mtspr   SPRN_SPRG3,r13          /* Save vaddr of paca in SPRG3  */
+       mtspr   SPRN_SPRG_PACA,r13      /* Save vaddr of paca in an SPRG*/
 
        /* Create a temp kernel stack for use before relocation is on.  */
        ld      r1,PACAEMERGSP(r13)
@@ -503,11 +550,14 @@ _GLOBAL(pmac_secondary_start)
  *   1. Processor number
  *   2. Segment table pointer (virtual address)
  * On entry the following are set:
- *   r1        = stack pointer.  vaddr for iSeries, raddr (temp stack) for pSeries
- *   r24   = cpu# (in Linux terms)
- *   r13   = paca virtual address
- *   SPRG3 = paca virtual address
+ *   r1               = stack pointer.  vaddr for iSeries, raddr (temp stack) for pSeries
+ *   r24       = cpu# (in Linux terms)
+ *   r13       = paca virtual address
+ *   SPRG_PACA = paca virtual address
  */
+       .section ".text";
+       .align 2 ;
+
        .globl  __secondary_start
 __secondary_start:
        /* Set thread priority to MEDIUM */
@@ -544,7 +594,7 @@ END_FW_FTR_SECTION_IFCLR(FW_FEATURE_ISERIES)
 
        mtspr   SPRN_SRR0,r3
        mtspr   SPRN_SRR1,r4
-       rfid
+       RFI
        b       .       /* prevent speculative execution */
 
 /* 
@@ -565,11 +615,16 @@ _GLOBAL(start_secondary_prolog)
  */
 _GLOBAL(enable_64b_mode)
        mfmsr   r11                     /* grab the current MSR */
+#ifdef CONFIG_PPC_BOOK3E
+       oris    r11,r11,0x8000          /* CM bit set, we'll set ICM later */
+       mtmsr   r11
+#else /* CONFIG_PPC_BOOK3E */
        li      r12,(MSR_SF | MSR_ISF)@highest
        sldi    r12,r12,48
        or      r11,r11,r12
        mtmsrd  r11
        isync
+#endif
        blr
 
 /*
@@ -613,9 +668,11 @@ _INIT_STATIC(start_here_multiplatform)
        bdnz    3b
 4:
 
+#ifndef CONFIG_PPC_BOOK3E
        mfmsr   r6
        ori     r6,r6,MSR_RI
        mtmsrd  r6                      /* RI on */
+#endif
 
 #ifdef CONFIG_RELOCATABLE
        /* Save the physical address we're running at in kernstart_addr */
@@ -642,13 +699,13 @@ _INIT_STATIC(start_here_multiplatform)
 
        /* Restore parameters passed from prom_init/kexec */
        mr      r3,r31
-       bl      .early_setup            /* also sets r13 and SPRG3 */
+       bl      .early_setup            /* also sets r13 and SPRG_PACA */
 
        LOAD_REG_ADDR(r3, .start_here_common)
        ld      r4,PACAKMSR(r13)
        mtspr   SPRN_SRR0,r3
        mtspr   SPRN_SRR1,r4
-       rfid
+       RFI
        b       .       /* prevent speculative execution */
        
        /* This is where all platforms converge execution */
index 52ff8c53b93c0da349fb3f126e61a39fdfa8eec6..6ded19d01891704ce0e49310812f5111afeb135c 100644 (file)
@@ -110,8 +110,8 @@ turn_on_mmu:
  * task's thread_struct.
  */
 #define EXCEPTION_PROLOG       \
-       mtspr   SPRN_SPRG0,r10; \
-       mtspr   SPRN_SPRG1,r11; \
+       mtspr   SPRN_SPRG_SCRATCH0,r10; \
+       mtspr   SPRN_SPRG_SCRATCH1,r11; \
        mfcr    r10;            \
        EXCEPTION_PROLOG_1;     \
        EXCEPTION_PROLOG_2
@@ -121,7 +121,7 @@ turn_on_mmu:
        andi.   r11,r11,MSR_PR; \
        tophys(r11,r1);                 /* use tophys(r1) if kernel */ \
        beq     1f;             \
-       mfspr   r11,SPRN_SPRG3; \
+       mfspr   r11,SPRN_SPRG_THREAD;   \
        lwz     r11,THREAD_INFO-THREAD(r11);    \
        addi    r11,r11,THREAD_SIZE;    \
        tophys(r11,r11);        \
@@ -133,9 +133,9 @@ turn_on_mmu:
        stw     r10,_CCR(r11);          /* save registers */ \
        stw     r12,GPR12(r11); \
        stw     r9,GPR9(r11);   \
-       mfspr   r10,SPRN_SPRG0; \
+       mfspr   r10,SPRN_SPRG_SCRATCH0; \
        stw     r10,GPR10(r11); \
-       mfspr   r12,SPRN_SPRG1; \
+       mfspr   r12,SPRN_SPRG_SCRATCH1; \
        stw     r12,GPR11(r11); \
        mflr    r10;            \
        stw     r10,_LINK(r11); \
@@ -603,8 +603,9 @@ start_here:
        /* ptr to phys current thread */
        tophys(r4,r2)
        addi    r4,r4,THREAD    /* init task's THREAD */
-       mtspr   SPRN_SPRG3,r4
+       mtspr   SPRN_SPRG_THREAD,r4
        li      r3,0
+       /* XXX What is that for ? SPRG2 appears otherwise unused on 8xx */
        mtspr   SPRN_SPRG2,r3   /* 0 => r1 has kernel sp */
 
        /* stack */
index 5f9febc8d1431c4daebb711f1496f9e1069a1b7e..50504ae39cb71400d9e84c7688edbe83ab5e4c74 100644 (file)
 #endif
 
 #define NORMAL_EXCEPTION_PROLOG                                                     \
-       mtspr   SPRN_SPRG0,r10;         /* save two registers to work with */\
-       mtspr   SPRN_SPRG1,r11;                                              \
-       mtspr   SPRN_SPRG4W,r1;                                              \
+       mtspr   SPRN_SPRG_WSCRATCH0,r10;/* save two registers to work with */\
+       mtspr   SPRN_SPRG_WSCRATCH1,r11;                                     \
+       mtspr   SPRN_SPRG_WSCRATCH2,r1;                                      \
        mfcr    r10;                    /* save CR in r10 for now          */\
        mfspr   r11,SPRN_SRR1;          /* check whether user or kernel    */\
        andi.   r11,r11,MSR_PR;                                              \
        beq     1f;                                                          \
-       mfspr   r1,SPRN_SPRG3;          /* if from user, start at top of   */\
+       mfspr   r1,SPRN_SPRG_THREAD;    /* if from user, start at top of   */\
        lwz     r1,THREAD_INFO-THREAD(r1); /* this thread's kernel stack   */\
        ALLOC_STACK_FRAME(r1, THREAD_SIZE);                                  \
 1:     subi    r1,r1,INT_FRAME_SIZE;   /* Allocate an exception frame     */\
        stw     r10,_CCR(r11);          /* save various registers          */\
        stw     r12,GPR12(r11);                                              \
        stw     r9,GPR9(r11);                                                \
-       mfspr   r10,SPRN_SPRG0;                                              \
+       mfspr   r10,SPRN_SPRG_RSCRATCH0;                                        \
        stw     r10,GPR10(r11);                                              \
-       mfspr   r12,SPRN_SPRG1;                                              \
+       mfspr   r12,SPRN_SPRG_RSCRATCH1;                                     \
        stw     r12,GPR11(r11);                                              \
        mflr    r10;                                                         \
        stw     r10,_LINK(r11);                                              \
-       mfspr   r10,SPRN_SPRG4R;                                             \
+       mfspr   r10,SPRN_SPRG_RSCRATCH2;                                     \
        mfspr   r12,SPRN_SRR0;                                               \
        stw     r10,GPR1(r11);                                               \
        mfspr   r9,SPRN_SRR1;                                                \
  * providing configurations that micro-optimize space usage.
  */
 
-/* CRIT_SPRG only used in critical exception handling */
-#define CRIT_SPRG      SPRN_SPRG2
-/* MCHECK_SPRG only used in machine check exception handling */
-#define MCHECK_SPRG    SPRN_SPRG6W
-
-#define MCHECK_STACK_BASE      mcheckirq_ctx
+#define MC_STACK_BASE          mcheckirq_ctx
 #define CRIT_STACK_BASE                critirq_ctx
 
 /* only on e500mc/e200 */
-#define DEBUG_STACK_BASE       dbgirq_ctx
-#ifdef CONFIG_E200
-#define DEBUG_SPRG             SPRN_SPRG6W
-#else
-#define DEBUG_SPRG             SPRN_SPRG9
-#endif
+#define DBG_STACK_BASE         dbgirq_ctx
 
 #define EXC_LVL_FRAME_OVERHEAD (THREAD_SIZE - INT_FRAME_SIZE - EXC_LVL_SIZE)
 
  * critical/machine check exception stack at low physical addresses.
  */
 #define EXC_LEVEL_EXCEPTION_PROLOG(exc_level, exc_level_srr0, exc_level_srr1) \
-       mtspr   exc_level##_SPRG,r8;                                         \
+       mtspr   SPRN_SPRG_WSCRATCH_##exc_level,r8;                           \
        BOOKE_LOAD_EXC_LEVEL_STACK(exc_level);/* r8 points to the exc_level stack*/ \
        stw     r9,GPR9(r8);            /* save various registers          */\
        mfcr    r9;                     /* save CR in r9 for now           */\
        stw     r9,_CCR(r8);            /* save CR on stack                */\
        mfspr   r10,exc_level_srr1;     /* check whether user or kernel    */\
        andi.   r10,r10,MSR_PR;                                              \
-       mfspr   r11,SPRN_SPRG3;         /* if from user, start at top of   */\
+       mfspr   r11,SPRN_SPRG_THREAD;   /* if from user, start at top of   */\
        lwz     r11,THREAD_INFO-THREAD(r11); /* this thread's kernel stack */\
        addi    r11,r11,EXC_LVL_FRAME_OVERHEAD; /* allocate stack frame    */\
        beq     1f;                                                          \
        lwz     r9,TI_TASK-EXC_LVL_FRAME_OVERHEAD(r11);                      \
        stw     r9,TI_TASK-EXC_LVL_FRAME_OVERHEAD(r8);                       \
        mr      r11,r8;                                                      \
-2:     mfspr   r8,exc_level##_SPRG;                                         \
+2:     mfspr   r8,SPRN_SPRG_RSCRATCH_##exc_level;                           \
        stw     r12,GPR12(r11);         /* save various registers          */\
        mflr    r10;                                                         \
        stw     r10,_LINK(r11);                                              \
 #define CRITICAL_EXCEPTION_PROLOG \
                EXC_LEVEL_EXCEPTION_PROLOG(CRIT, SPRN_CSRR0, SPRN_CSRR1)
 #define DEBUG_EXCEPTION_PROLOG \
-               EXC_LEVEL_EXCEPTION_PROLOG(DEBUG, SPRN_DSRR0, SPRN_DSRR1)
+               EXC_LEVEL_EXCEPTION_PROLOG(DBG, SPRN_DSRR0, SPRN_DSRR1)
 #define MCHECK_EXCEPTION_PROLOG \
-               EXC_LEVEL_EXCEPTION_PROLOG(MCHECK, SPRN_MCSRR0, SPRN_MCSRR1)
+               EXC_LEVEL_EXCEPTION_PROLOG(MC, SPRN_MCSRR0, SPRN_MCSRR1)
 
 /*
  * Exception vectors.
@@ -282,13 +272,13 @@ label:
        mtspr   SPRN_DSRR1,r9;                                                \
        lwz     r9,GPR9(r11);                                                 \
        lwz     r12,GPR12(r11);                                               \
-       mtspr   DEBUG_SPRG,r8;                                                \
-       BOOKE_LOAD_EXC_LEVEL_STACK(DEBUG); /* r8 points to the debug stack */ \
+       mtspr   SPRN_SPRG_WSCRATCH_DBG,r8;                                    \
+       BOOKE_LOAD_EXC_LEVEL_STACK(DBG); /* r8 points to the debug stack */ \
        lwz     r10,GPR10(r8);                                                \
        lwz     r11,GPR11(r8);                                                \
-       mfspr   r8,DEBUG_SPRG;                                                \
+       mfspr   r8,SPRN_SPRG_RSCRATCH_DBG;                                    \
                                                                              \
-       PPC_RFDI;                                                                     \
+       PPC_RFDI;                                                             \
        b       .;                                                            \
                                                                              \
        /* continue normal handling for a debug exception... */               \
@@ -335,11 +325,11 @@ label:
        mtspr   SPRN_CSRR1,r9;                                                \
        lwz     r9,GPR9(r11);                                                 \
        lwz     r12,GPR12(r11);                                               \
-       mtspr   CRIT_SPRG,r8;                                                 \
+       mtspr   SPRN_SPRG_WSCRATCH_CRIT,r8;                                   \
        BOOKE_LOAD_EXC_LEVEL_STACK(CRIT); /* r8 points to the debug stack */  \
        lwz     r10,GPR10(r8);                                                \
        lwz     r11,GPR11(r8);                                                \
-       mfspr   r8,CRIT_SPRG;                                                 \
+       mfspr   r8,SPRN_SPRG_RSCRATCH_CRIT;                                   \
                                                                              \
        rfci;                                                                 \
        b       .;                                                            \
index 5bdcc06d294c846d416c76dbb4eca8e7aa37fecd..975788ca05d203eb1b24712ce3a640790cbf715f 100644 (file)
@@ -361,7 +361,7 @@ skpinv:     addi    r6,r6,1                         /* Increment */
 
        /* ptr to current thread */
        addi    r4,r2,THREAD    /* init task's THREAD */
-       mtspr   SPRN_SPRG3,r4
+       mtspr   SPRN_SPRG_THREAD,r4
 
        /* stack */
        lis     r1,init_thread_union@h
@@ -532,12 +532,12 @@ interrupt_base:
 
        /* Data TLB Error Interrupt */
        START_EXCEPTION(DataTLBError)
-       mtspr   SPRN_SPRG0, r10         /* Save some working registers */
-       mtspr   SPRN_SPRG1, r11
-       mtspr   SPRN_SPRG4W, r12
-       mtspr   SPRN_SPRG5W, r13
+       mtspr   SPRN_SPRG_WSCRATCH0, r10 /* Save some working registers */
+       mtspr   SPRN_SPRG_WSCRATCH1, r11
+       mtspr   SPRN_SPRG_WSCRATCH2, r12
+       mtspr   SPRN_SPRG_WSCRATCH3, r13
        mfcr    r11
-       mtspr   SPRN_SPRG7W, r11
+       mtspr   SPRN_SPRG_WSCRATCH4, r11
        mfspr   r10, SPRN_DEAR          /* Get faulting address */
 
        /* If we are faulting a kernel address, we have to use the
@@ -557,7 +557,7 @@ interrupt_base:
 
        /* Get the PGD for the current thread */
 3:
-       mfspr   r11,SPRN_SPRG3
+       mfspr   r11,SPRN_SPRG_THREAD
        lwz     r11,PGDIR(r11)
 
 4:
@@ -575,7 +575,12 @@ interrupt_base:
         *       place or can we save a couple of instructions here ?
         */
        mfspr   r12,SPRN_ESR
+#ifdef CONFIG_PTE_64BIT
+       li      r13,_PAGE_PRESENT
+       oris    r13,r13,_PAGE_ACCESSED@h
+#else
        li      r13,_PAGE_PRESENT|_PAGE_ACCESSED
+#endif
        rlwimi  r13,r12,11,29,29
 
        FIND_PTE
@@ -598,12 +603,12 @@ interrupt_base:
        /* The bailout.  Restore registers to pre-exception conditions
         * and call the heavyweights to help us out.
         */
-       mfspr   r11, SPRN_SPRG7R
+       mfspr   r11, SPRN_SPRG_RSCRATCH4
        mtcr    r11
-       mfspr   r13, SPRN_SPRG5R
-       mfspr   r12, SPRN_SPRG4R
-       mfspr   r11, SPRN_SPRG1
-       mfspr   r10, SPRN_SPRG0
+       mfspr   r13, SPRN_SPRG_RSCRATCH3
+       mfspr   r12, SPRN_SPRG_RSCRATCH2
+       mfspr   r11, SPRN_SPRG_RSCRATCH1
+       mfspr   r10, SPRN_SPRG_RSCRATCH0
        b       DataStorage
 
        /* Instruction TLB Error Interrupt */
@@ -613,12 +618,12 @@ interrupt_base:
         * to a different point.
         */
        START_EXCEPTION(InstructionTLBError)
-       mtspr   SPRN_SPRG0, r10         /* Save some working registers */
-       mtspr   SPRN_SPRG1, r11
-       mtspr   SPRN_SPRG4W, r12
-       mtspr   SPRN_SPRG5W, r13
+       mtspr   SPRN_SPRG_WSCRATCH0, r10 /* Save some working registers */
+       mtspr   SPRN_SPRG_WSCRATCH1, r11
+       mtspr   SPRN_SPRG_WSCRATCH2, r12
+       mtspr   SPRN_SPRG_WSCRATCH3, r13
        mfcr    r11
-       mtspr   SPRN_SPRG7W, r11
+       mtspr   SPRN_SPRG_WSCRATCH4, r11
        mfspr   r10, SPRN_SRR0          /* Get faulting address */
 
        /* If we are faulting a kernel address, we have to use the
@@ -638,12 +643,17 @@ interrupt_base:
 
        /* Get the PGD for the current thread */
 3:
-       mfspr   r11,SPRN_SPRG3
+       mfspr   r11,SPRN_SPRG_THREAD
        lwz     r11,PGDIR(r11)
 
 4:
        /* Make up the required permissions */
-       li      r13,_PAGE_PRESENT | _PAGE_ACCESSED | _PAGE_HWEXEC
+#ifdef CONFIG_PTE_64BIT
+       li      r13,_PAGE_PRESENT | _PAGE_EXEC
+       oris    r13,r13,_PAGE_ACCESSED@h
+#else
+       li      r13,_PAGE_PRESENT | _PAGE_ACCESSED | _PAGE_EXEC
+#endif
 
        FIND_PTE
        andc.   r13,r13,r11             /* Check permission */
@@ -666,12 +676,12 @@ interrupt_base:
        /* The bailout.  Restore registers to pre-exception conditions
         * and call the heavyweights to help us out.
         */
-       mfspr   r11, SPRN_SPRG7R
+       mfspr   r11, SPRN_SPRG_RSCRATCH4
        mtcr    r11
-       mfspr   r13, SPRN_SPRG5R
-       mfspr   r12, SPRN_SPRG4R
-       mfspr   r11, SPRN_SPRG1
-       mfspr   r10, SPRN_SPRG0
+       mfspr   r13, SPRN_SPRG_RSCRATCH3
+       mfspr   r12, SPRN_SPRG_RSCRATCH2
+       mfspr   r11, SPRN_SPRG_RSCRATCH1
+       mfspr   r10, SPRN_SPRG_RSCRATCH0
        b       InstructionStorage
 
 #ifdef CONFIG_SPE
@@ -733,7 +743,7 @@ finish_tlb_load:
 
        mfspr   r12, SPRN_MAS2
 #ifdef CONFIG_PTE_64BIT
-       rlwimi  r12, r11, 26, 24, 31    /* extract ...WIMGE from pte */
+       rlwimi  r12, r11, 32-19, 27, 31 /* extract WIMGE from pte */
 #else
        rlwimi  r12, r11, 26, 27, 31    /* extract WIMGE from pte */
 #endif
@@ -742,23 +752,27 @@ finish_tlb_load:
 #endif
        mtspr   SPRN_MAS2, r12
 
-       li      r10, (_PAGE_HWEXEC | _PAGE_PRESENT)
-       rlwimi  r10, r11, 31, 29, 29    /* extract _PAGE_DIRTY into SW */
-       and     r12, r11, r10
-       andi.   r10, r11, _PAGE_USER    /* Test for _PAGE_USER */
-       slwi    r10, r12, 1
-       or      r10, r10, r12
-       iseleq  r12, r12, r10
-       
 #ifdef CONFIG_PTE_64BIT
-       rlwimi  r12, r13, 24, 0, 7      /* grab RPN[32:39] */
-       rlwimi  r12, r11, 24, 8, 19     /* grab RPN[40:51] */
+       rlwinm  r12, r11, 32-2, 26, 31  /* Move in perm bits */
+       andi.   r10, r11, _PAGE_DIRTY
+       bne     1f
+       li      r10, MAS3_SW | MAS3_UW
+       andc    r12, r12, r10
+1:     rlwimi  r12, r13, 20, 0, 11     /* grab RPN[32:43] */
+       rlwimi  r12, r11, 20, 12, 19    /* grab RPN[44:51] */
        mtspr   SPRN_MAS3, r12
 BEGIN_MMU_FTR_SECTION
-       srwi    r10, r13, 8             /* grab RPN[8:31] */
+       srwi    r10, r13, 12            /* grab RPN[12:31] */
        mtspr   SPRN_MAS7, r10
 END_MMU_FTR_SECTION_IFSET(MMU_FTR_BIG_PHYS)
 #else
+       li      r10, (_PAGE_EXEC | _PAGE_PRESENT)
+       rlwimi  r10, r11, 31, 29, 29    /* extract _PAGE_DIRTY into SW */
+       and     r12, r11, r10
+       andi.   r10, r11, _PAGE_USER    /* Test for _PAGE_USER */
+       slwi    r10, r12, 1
+       or      r10, r10, r12
+       iseleq  r12, r12, r10
        rlwimi  r11, r12, 0, 20, 31     /* Extract RPN from PTE and merge with perms */
        mtspr   SPRN_MAS3, r11
 #endif
@@ -790,12 +804,12 @@ END_MMU_FTR_SECTION_IFSET(MMU_FTR_BIG_PHYS)
        tlbwe
 
        /* Done...restore registers and get out of here.  */
-       mfspr   r11, SPRN_SPRG7R
+       mfspr   r11, SPRN_SPRG_RSCRATCH4
        mtcr    r11
-       mfspr   r13, SPRN_SPRG5R
-       mfspr   r12, SPRN_SPRG4R
-       mfspr   r11, SPRN_SPRG1
-       mfspr   r10, SPRN_SPRG0
+       mfspr   r13, SPRN_SPRG_RSCRATCH3
+       mfspr   r12, SPRN_SPRG_RSCRATCH2
+       mfspr   r11, SPRN_SPRG_RSCRATCH1
+       mfspr   r10, SPRN_SPRG_RSCRATCH0
        rfi                                     /* Force context change */
 
 #ifdef CONFIG_SPE
@@ -839,7 +853,7 @@ load_up_spe:
 #endif /* !CONFIG_SMP */
        /* enable use of SPE after return */
        oris    r9,r9,MSR_SPE@h
-       mfspr   r5,SPRN_SPRG3           /* current task's THREAD (phys) */
+       mfspr   r5,SPRN_SPRG_THREAD     /* current task's THREAD (phys) */
        li      r4,1
        li      r10,THREAD_ACC
        stw     r4,THREAD_USED_SPE(r5)
@@ -1118,7 +1132,7 @@ __secondary_start:
 
        /* ptr to current thread */
        addi    r4,r2,THREAD    /* address of our thread_struct */
-       mtspr   SPRN_SPRG3,r4
+       mtspr   SPRN_SPRG_THREAD,r4
 
        /* Setup the defaults for TLB entries */
        li      r4,(MAS4_TSIZED(BOOK3E_PAGESZ_4K))@l
index 6e3f62493659abc79e68f6795f14dd3d52d8cab1..a4c8b38b0ba1f7bed97d9788e80a78f9447a3cc2 100644 (file)
@@ -127,7 +127,7 @@ static int ibmebus_dma_supported(struct device *dev, u64 mask)
        return 1;
 }
 
-static struct dma_mapping_ops ibmebus_dma_ops = {
+static struct dma_map_ops ibmebus_dma_ops = {
        .alloc_coherent = ibmebus_alloc_coherent,
        .free_coherent  = ibmebus_free_coherent,
        .map_sg         = ibmebus_map_sg,
index 2419cc706ff1cc798ac9898f0bb68ae0a2140857..ed0ac4e4b8d8c82639625d67c8619d495bd9c9d2 100644 (file)
@@ -35,6 +35,7 @@
 #include <asm/prom.h>
 #include <asm/vdso_datapage.h>
 #include <asm/vio.h>
+#include <asm/mmu.h>
 
 #define MODULE_VERS "1.8"
 #define MODULE_NAME "lparcfg"
@@ -537,6 +538,8 @@ static int pseries_lparcfg_data(struct seq_file *m, void *v)
 
        seq_printf(m, "shared_processor_mode=%d\n", lppaca[0].shared_proc);
 
+       seq_printf(m, "slb_size=%d\n", mmu_slb_size);
+
        return 0;
 }
 
index 15f28e0de78dae1919c3cf55f6ec77f15f71d9b5..da9c0c4c10f3be383810f74ef01f55f5eced50b2 100644 (file)
@@ -342,10 +342,17 @@ END_FTR_SECTION_IFSET(CPU_FTR_COHERENT_ICACHE)
        addi    r3,r3,L1_CACHE_BYTES
        bdnz    1b
        sync                            /* wait for dcbst's to get to ram */
+#ifndef CONFIG_44x
        mtctr   r4
 2:     icbi    0,r6
        addi    r6,r6,L1_CACHE_BYTES
        bdnz    2b
+#else
+       /* Flash invalidate on 44x because we are passed kmapped addresses and
+          this doesn't work for userspace pages due to the virtually tagged
+          icache.  Sigh. */
+       iccci   0, r0
+#endif
        sync                            /* additional sync needed on g4 */
        isync
        blr
index 87df428e35880f1da99b2a40e6a3276e1f0a4f70..1a4fc0d11a031706ab19018959074ea6fbbfc4f7 100644 (file)
@@ -276,7 +276,7 @@ static int __devinit of_pci_phb_probe(struct of_device *dev,
 #endif /* CONFIG_EEH */
 
        /* Scan the bus */
-       scan_phb(phb);
+       pcibios_scan_phb(phb, dev->node);
        if (phb->bus == NULL)
                return -ENXIO;
 
index e9962c7f8a0999a8ff2662c17daa1d9b92b8891f..d16b1ea55d44767fba93edcff66c2813a4c8826a 100644 (file)
@@ -13,6 +13,7 @@
 #include <asm/lppaca.h>
 #include <asm/paca.h>
 #include <asm/sections.h>
+#include <asm/pgtable.h>
 
 /* This symbol is provided by the linker - let it fill in the paca
  * field correctly */
@@ -87,6 +88,8 @@ void __init initialise_pacas(void)
 
 #ifdef CONFIG_PPC_BOOK3S
                new_paca->lppaca_ptr = &lppaca[cpu];
+#else
+               new_paca->kernel_pgd = swapper_pg_dir;
 #endif
                new_paca->lock_token = 0x8000;
                new_paca->paca_index = cpu;
index 5a56e97c5ac00270d7481d88dade90e768b3d695..e9f4840096b381e500dd171500c4257b44a02e7a 100644 (file)
@@ -50,14 +50,14 @@ resource_size_t isa_mem_base;
 unsigned int ppc_pci_flags = 0;
 
 
-static struct dma_mapping_ops *pci_dma_ops = &dma_direct_ops;
+static struct dma_map_ops *pci_dma_ops = &dma_direct_ops;
 
-void set_pci_dma_ops(struct dma_mapping_ops *dma_ops)
+void set_pci_dma_ops(struct dma_map_ops *dma_ops)
 {
        pci_dma_ops = dma_ops;
 }
 
-struct dma_mapping_ops *get_pci_dma_ops(void)
+struct dma_map_ops *get_pci_dma_ops(void)
 {
        return pci_dma_ops;
 }
@@ -176,8 +176,6 @@ int pci_domain_nr(struct pci_bus *bus)
 }
 EXPORT_SYMBOL(pci_domain_nr);
 
-#ifdef CONFIG_PPC_OF
-
 /* This routine is meant to be used early during boot, when the
  * PCI bus numbers have not yet been assigned, and you need to
  * issue PCI config cycles to an OF device.
@@ -210,17 +208,11 @@ static ssize_t pci_show_devspec(struct device *dev,
        return sprintf(buf, "%s", np->full_name);
 }
 static DEVICE_ATTR(devspec, S_IRUGO, pci_show_devspec, NULL);
-#endif /* CONFIG_PPC_OF */
 
 /* Add sysfs properties */
 int pcibios_add_platform_entries(struct pci_dev *pdev)
 {
-#ifdef CONFIG_PPC_OF
        return device_create_file(&pdev->dev, &dev_attr_devspec);
-#else
-       return 0;
-#endif /* CONFIG_PPC_OF */
-
 }
 
 char __devinit *pcibios_setup(char *str)
@@ -1626,3 +1618,122 @@ void __devinit pcibios_setup_phb_resources(struct pci_controller *hose)
 
 }
 
+/*
+ * Null PCI config access functions, for the case when we can't
+ * find a hose.
+ */
+#define NULL_PCI_OP(rw, size, type)                                    \
+static int                                                             \
+null_##rw##_config_##size(struct pci_dev *dev, int offset, type val)   \
+{                                                                      \
+       return PCIBIOS_DEVICE_NOT_FOUND;                                \
+}
+
+static int
+null_read_config(struct pci_bus *bus, unsigned int devfn, int offset,
+                int len, u32 *val)
+{
+       return PCIBIOS_DEVICE_NOT_FOUND;
+}
+
+static int
+null_write_config(struct pci_bus *bus, unsigned int devfn, int offset,
+                 int len, u32 val)
+{
+       return PCIBIOS_DEVICE_NOT_FOUND;
+}
+
+static struct pci_ops null_pci_ops =
+{
+       .read = null_read_config,
+       .write = null_write_config,
+};
+
+/*
+ * These functions are used early on before PCI scanning is done
+ * and all of the pci_dev and pci_bus structures have been created.
+ */
+static struct pci_bus *
+fake_pci_bus(struct pci_controller *hose, int busnr)
+{
+       static struct pci_bus bus;
+
+       if (hose == 0) {
+               printk(KERN_ERR "Can't find hose for PCI bus %d!\n", busnr);
+       }
+       bus.number = busnr;
+       bus.sysdata = hose;
+       bus.ops = hose? hose->ops: &null_pci_ops;
+       return &bus;
+}
+
+#define EARLY_PCI_OP(rw, size, type)                                   \
+int early_##rw##_config_##size(struct pci_controller *hose, int bus,   \
+                              int devfn, int offset, type value)       \
+{                                                                      \
+       return pci_bus_##rw##_config_##size(fake_pci_bus(hose, bus),    \
+                                           devfn, offset, value);      \
+}
+
+EARLY_PCI_OP(read, byte, u8 *)
+EARLY_PCI_OP(read, word, u16 *)
+EARLY_PCI_OP(read, dword, u32 *)
+EARLY_PCI_OP(write, byte, u8)
+EARLY_PCI_OP(write, word, u16)
+EARLY_PCI_OP(write, dword, u32)
+
+extern int pci_bus_find_capability (struct pci_bus *bus, unsigned int devfn, int cap);
+int early_find_capability(struct pci_controller *hose, int bus, int devfn,
+                         int cap)
+{
+       return pci_bus_find_capability(fake_pci_bus(hose, bus), devfn, cap);
+}
+
+/**
+ * pci_scan_phb - Given a pci_controller, setup and scan the PCI bus
+ * @hose: Pointer to the PCI host controller instance structure
+ * @sysdata: value to use for sysdata pointer.  ppc32 and ppc64 differ here
+ *
+ * Note: the 'data' pointer is a temporary measure.  As 32 and 64 bit
+ * pci code gets merged, this parameter should become unnecessary because
+ * both will use the same value.
+ */
+void __devinit pcibios_scan_phb(struct pci_controller *hose, void *sysdata)
+{
+       struct pci_bus *bus;
+       struct device_node *node = hose->dn;
+       int mode;
+
+       pr_debug("PCI: Scanning PHB %s\n",
+                node ? node->full_name : "<NO NAME>");
+
+       /* Create an empty bus for the toplevel */
+       bus = pci_create_bus(hose->parent, hose->first_busno, hose->ops,
+                            sysdata);
+       if (bus == NULL) {
+               pr_err("Failed to create bus for PCI domain %04x\n",
+                       hose->global_number);
+               return;
+       }
+       bus->secondary = hose->first_busno;
+       hose->bus = bus;
+
+       /* Get some IO space for the new PHB */
+       pcibios_setup_phb_io_space(hose);
+
+       /* Wire up PHB bus resources */
+       pcibios_setup_phb_resources(hose);
+
+       /* Get probe mode and perform scan */
+       mode = PCI_PROBE_NORMAL;
+       if (node && ppc_md.pci_probe_mode)
+               mode = ppc_md.pci_probe_mode(bus);
+       pr_debug("    probe mode: %d\n", mode);
+       if (mode == PCI_PROBE_DEVTREE) {
+               bus->subordinate = hose->last_busno;
+               of_scan_bus(node, bus);
+       }
+
+       if (mode == PCI_PROBE_NORMAL)
+               hose->last_busno = bus->subordinate = pci_scan_child_bus(bus);
+}
index 3ae1c666ff9276c3a26ed90ce7c406f4717ab2d1..c13668cf36d940473519e9dc3723e9fc0bd37710 100644 (file)
@@ -34,9 +34,7 @@ int pcibios_assign_bus_offset = 1;
 void pcibios_make_OF_bus_map(void);
 
 static void fixup_cpc710_pci64(struct pci_dev* dev);
-#ifdef CONFIG_PPC_OF
 static u8* pci_to_OF_bus_map;
-#endif
 
 /* By default, we don't re-assign bus numbers. We do this only on
  * some pmacs
@@ -83,7 +81,6 @@ fixup_cpc710_pci64(struct pci_dev* dev)
 }
 DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_IBM,    PCI_DEVICE_ID_IBM_CPC710_PCI64, fixup_cpc710_pci64);
 
-#ifdef CONFIG_PPC_OF
 /*
  * Functions below are used on OpenFirmware machines.
  */
@@ -357,42 +354,15 @@ pci_create_OF_bus_map(void)
        }
 }
 
-#else /* CONFIG_PPC_OF */
-void pcibios_make_OF_bus_map(void)
+void __devinit pcibios_setup_phb_io_space(struct pci_controller *hose)
 {
-}
-#endif /* CONFIG_PPC_OF */
-
-static void __devinit pcibios_scan_phb(struct pci_controller *hose)
-{
-       struct pci_bus *bus;
-       struct device_node *node = hose->dn;
        unsigned long io_offset;
        struct resource *res = &hose->io_resource;
 
-       pr_debug("PCI: Scanning PHB %s\n",
-                node ? node->full_name : "<NO NAME>");
-
-       /* Create an empty bus for the toplevel */
-       bus = pci_create_bus(hose->parent, hose->first_busno, hose->ops, hose);
-       if (bus == NULL) {
-               printk(KERN_ERR "Failed to create bus for PCI domain %04x\n",
-                      hose->global_number);
-               return;
-       }
-       bus->secondary = hose->first_busno;
-       hose->bus = bus;
-
        /* Fixup IO space offset */
        io_offset = (unsigned long)hose->io_base_virt - isa_io_base;
        res->start = (res->start + io_offset) & 0xffffffffu;
        res->end = (res->end + io_offset) & 0xffffffffu;
-
-       /* Wire up PHB bus resources */
-       pcibios_setup_phb_resources(hose);
-
-       /* Scan children */
-       hose->last_busno = bus->subordinate = pci_scan_child_bus(bus);
 }
 
 static int __init pcibios_init(void)
@@ -410,7 +380,7 @@ static int __init pcibios_init(void)
                if (pci_assign_all_buses)
                        hose->first_busno = next_busno;
                hose->last_busno = 0xff;
-               pcibios_scan_phb(hose);
+               pcibios_scan_phb(hose, hose);
                pci_bus_add_devices(hose->bus);
                if (pci_assign_all_buses || next_busno <= hose->last_busno)
                        next_busno = hose->last_busno + pcibios_assign_bus_offset;
@@ -478,75 +448,4 @@ long sys_pciconfig_iobase(long which, unsigned long bus, unsigned long devfn)
        return result;
 }
 
-/*
- * Null PCI config access functions, for the case when we can't
- * find a hose.
- */
-#define NULL_PCI_OP(rw, size, type)                                    \
-static int                                                             \
-null_##rw##_config_##size(struct pci_dev *dev, int offset, type val)   \
-{                                                                      \
-       return PCIBIOS_DEVICE_NOT_FOUND;                                \
-}
 
-static int
-null_read_config(struct pci_bus *bus, unsigned int devfn, int offset,
-                int len, u32 *val)
-{
-       return PCIBIOS_DEVICE_NOT_FOUND;
-}
-
-static int
-null_write_config(struct pci_bus *bus, unsigned int devfn, int offset,
-                 int len, u32 val)
-{
-       return PCIBIOS_DEVICE_NOT_FOUND;
-}
-
-static struct pci_ops null_pci_ops =
-{
-       .read = null_read_config,
-       .write = null_write_config,
-};
-
-/*
- * These functions are used early on before PCI scanning is done
- * and all of the pci_dev and pci_bus structures have been created.
- */
-static struct pci_bus *
-fake_pci_bus(struct pci_controller *hose, int busnr)
-{
-       static struct pci_bus bus;
-
-       if (hose == 0) {
-               hose = pci_bus_to_hose(busnr);
-               if (hose == 0)
-                       printk(KERN_ERR "Can't find hose for PCI bus %d!\n", busnr);
-       }
-       bus.number = busnr;
-       bus.sysdata = hose;
-       bus.ops = hose? hose->ops: &null_pci_ops;
-       return &bus;
-}
-
-#define EARLY_PCI_OP(rw, size, type)                                   \
-int early_##rw##_config_##size(struct pci_controller *hose, int bus,   \
-                              int devfn, int offset, type value)       \
-{                                                                      \
-       return pci_bus_##rw##_config_##size(fake_pci_bus(hose, bus),    \
-                                           devfn, offset, value);      \
-}
-
-EARLY_PCI_OP(read, byte, u8 *)
-EARLY_PCI_OP(read, word, u16 *)
-EARLY_PCI_OP(read, dword, u32 *)
-EARLY_PCI_OP(write, byte, u8)
-EARLY_PCI_OP(write, word, u16)
-EARLY_PCI_OP(write, dword, u32)
-
-extern int pci_bus_find_capability (struct pci_bus *bus, unsigned int devfn, int cap);
-int early_find_capability(struct pci_controller *hose, int bus, int devfn,
-                         int cap)
-{
-       return pci_bus_find_capability(fake_pci_bus(hose, bus), devfn, cap);
-}
index 9e8902fa14c701a8ca21b6cc2434bb20a12a4dce..ba949a2c93ac457afed39f2f390f9b72cff57dca 100644 (file)
@@ -43,334 +43,6 @@ unsigned long pci_probe_only = 1;
 unsigned long pci_io_base = ISA_IO_BASE;
 EXPORT_SYMBOL(pci_io_base);
 
-static u32 get_int_prop(struct device_node *np, const char *name, u32 def)
-{
-       const u32 *prop;
-       int len;
-
-       prop = of_get_property(np, name, &len);
-       if (prop && len >= 4)
-               return *prop;
-       return def;
-}
-
-static unsigned int pci_parse_of_flags(u32 addr0, int bridge)
-{
-       unsigned int flags = 0;
-
-       if (addr0 & 0x02000000) {
-               flags = IORESOURCE_MEM | PCI_BASE_ADDRESS_SPACE_MEMORY;
-               flags |= (addr0 >> 22) & PCI_BASE_ADDRESS_MEM_TYPE_64;
-               flags |= (addr0 >> 28) & PCI_BASE_ADDRESS_MEM_TYPE_1M;
-               if (addr0 & 0x40000000)
-                       flags |= IORESOURCE_PREFETCH
-                                | PCI_BASE_ADDRESS_MEM_PREFETCH;
-               /* Note: We don't know whether the ROM has been left enabled
-                * by the firmware or not. We mark it as disabled (ie, we do
-                * not set the IORESOURCE_ROM_ENABLE flag) for now rather than
-                * do a config space read, it will be force-enabled if needed
-                */
-               if (!bridge && (addr0 & 0xff) == 0x30)
-                       flags |= IORESOURCE_READONLY;
-       } else if (addr0 & 0x01000000)
-               flags = IORESOURCE_IO | PCI_BASE_ADDRESS_SPACE_IO;
-       if (flags)
-               flags |= IORESOURCE_SIZEALIGN;
-       return flags;
-}
-
-
-static void pci_parse_of_addrs(struct device_node *node, struct pci_dev *dev)
-{
-       u64 base, size;
-       unsigned int flags;
-       struct resource *res;
-       const u32 *addrs;
-       u32 i;
-       int proplen;
-
-       addrs = of_get_property(node, "assigned-addresses", &proplen);
-       if (!addrs)
-               return;
-       pr_debug("    parse addresses (%d bytes) @ %p\n", proplen, addrs);
-       for (; proplen >= 20; proplen -= 20, addrs += 5) {
-               flags = pci_parse_of_flags(addrs[0], 0);
-               if (!flags)
-                       continue;
-               base = of_read_number(&addrs[1], 2);
-               size = of_read_number(&addrs[3], 2);
-               if (!size)
-                       continue;
-               i = addrs[0] & 0xff;
-               pr_debug("  base: %llx, size: %llx, i: %x\n",
-                        (unsigned long long)base,
-                        (unsigned long long)size, i);
-
-               if (PCI_BASE_ADDRESS_0 <= i && i <= PCI_BASE_ADDRESS_5) {
-                       res = &dev->resource[(i - PCI_BASE_ADDRESS_0) >> 2];
-               } else if (i == dev->rom_base_reg) {
-                       res = &dev->resource[PCI_ROM_RESOURCE];
-                       flags |= IORESOURCE_READONLY | IORESOURCE_CACHEABLE;
-               } else {
-                       printk(KERN_ERR "PCI: bad cfg reg num 0x%x\n", i);
-                       continue;
-               }
-               res->start = base;
-               res->end = base + size - 1;
-               res->flags = flags;
-               res->name = pci_name(dev);
-       }
-}
-
-struct pci_dev *of_create_pci_dev(struct device_node *node,
-                                struct pci_bus *bus, int devfn)
-{
-       struct pci_dev *dev;
-       const char *type;
-
-       dev = alloc_pci_dev();
-       if (!dev)
-               return NULL;
-       type = of_get_property(node, "device_type", NULL);
-       if (type == NULL)
-               type = "";
-
-       pr_debug("    create device, devfn: %x, type: %s\n", devfn, type);
-
-       dev->bus = bus;
-       dev->sysdata = node;
-       dev->dev.parent = bus->bridge;
-       dev->dev.bus = &pci_bus_type;
-       dev->devfn = devfn;
-       dev->multifunction = 0;         /* maybe a lie? */
-
-       dev->vendor = get_int_prop(node, "vendor-id", 0xffff);
-       dev->device = get_int_prop(node, "device-id", 0xffff);
-       dev->subsystem_vendor = get_int_prop(node, "subsystem-vendor-id", 0);
-       dev->subsystem_device = get_int_prop(node, "subsystem-id", 0);
-
-       dev->cfg_size = pci_cfg_space_size(dev);
-
-       dev_set_name(&dev->dev, "%04x:%02x:%02x.%d", pci_domain_nr(bus),
-               dev->bus->number, PCI_SLOT(devfn), PCI_FUNC(devfn));
-       dev->class = get_int_prop(node, "class-code", 0);
-       dev->revision = get_int_prop(node, "revision-id", 0);
-
-       pr_debug("    class: 0x%x\n", dev->class);
-       pr_debug("    revision: 0x%x\n", dev->revision);
-
-       dev->current_state = 4;         /* unknown power state */
-       dev->error_state = pci_channel_io_normal;
-       dev->dma_mask = 0xffffffff;
-
-       if (!strcmp(type, "pci") || !strcmp(type, "pciex")) {
-               /* a PCI-PCI bridge */
-               dev->hdr_type = PCI_HEADER_TYPE_BRIDGE;
-               dev->rom_base_reg = PCI_ROM_ADDRESS1;
-       } else if (!strcmp(type, "cardbus")) {
-               dev->hdr_type = PCI_HEADER_TYPE_CARDBUS;
-       } else {
-               dev->hdr_type = PCI_HEADER_TYPE_NORMAL;
-               dev->rom_base_reg = PCI_ROM_ADDRESS;
-               /* Maybe do a default OF mapping here */
-               dev->irq = NO_IRQ;
-       }
-
-       pci_parse_of_addrs(node, dev);
-
-       pr_debug("    adding to system ...\n");
-
-       pci_device_add(dev, bus);
-
-       return dev;
-}
-EXPORT_SYMBOL(of_create_pci_dev);
-
-static void __devinit __of_scan_bus(struct device_node *node,
-                                   struct pci_bus *bus, int rescan_existing)
-{
-       struct device_node *child;
-       const u32 *reg;
-       int reglen, devfn;
-       struct pci_dev *dev;
-
-       pr_debug("of_scan_bus(%s) bus no %d... \n",
-                node->full_name, bus->number);
-
-       /* Scan direct children */
-       for_each_child_of_node(node, child) {
-               pr_debug("  * %s\n", child->full_name);
-               reg = of_get_property(child, "reg", &reglen);
-               if (reg == NULL || reglen < 20)
-                       continue;
-               devfn = (reg[0] >> 8) & 0xff;
-
-               /* create a new pci_dev for this device */
-               dev = of_create_pci_dev(child, bus, devfn);
-               if (!dev)
-                       continue;
-               pr_debug("    dev header type: %x\n", dev->hdr_type);
-       }
-
-       /* Apply all fixups necessary. We don't fixup the bus "self"
-        * for an existing bridge that is being rescanned
-        */
-       if (!rescan_existing)
-               pcibios_setup_bus_self(bus);
-       pcibios_setup_bus_devices(bus);
-
-       /* Now scan child busses */
-       list_for_each_entry(dev, &bus->devices, bus_list) {
-               if (dev->hdr_type == PCI_HEADER_TYPE_BRIDGE ||
-                   dev->hdr_type == PCI_HEADER_TYPE_CARDBUS) {
-                       struct device_node *child = pci_device_to_OF_node(dev);
-                       if (dev)
-                               of_scan_pci_bridge(child, dev);
-               }
-       }
-}
-
-void __devinit of_scan_bus(struct device_node *node,
-                          struct pci_bus *bus)
-{
-       __of_scan_bus(node, bus, 0);
-}
-EXPORT_SYMBOL_GPL(of_scan_bus);
-
-void __devinit of_rescan_bus(struct device_node *node,
-                            struct pci_bus *bus)
-{
-       __of_scan_bus(node, bus, 1);
-}
-EXPORT_SYMBOL_GPL(of_rescan_bus);
-
-void __devinit of_scan_pci_bridge(struct device_node *node,
-                                 struct pci_dev *dev)
-{
-       struct pci_bus *bus;
-       const u32 *busrange, *ranges;
-       int len, i, mode;
-       struct resource *res;
-       unsigned int flags;
-       u64 size;
-
-       pr_debug("of_scan_pci_bridge(%s)\n", node->full_name);
-
-       /* parse bus-range property */
-       busrange = of_get_property(node, "bus-range", &len);
-       if (busrange == NULL || len != 8) {
-               printk(KERN_DEBUG "Can't get bus-range for PCI-PCI bridge %s\n",
-                      node->full_name);
-               return;
-       }
-       ranges = of_get_property(node, "ranges", &len);
-       if (ranges == NULL) {
-               printk(KERN_DEBUG "Can't get ranges for PCI-PCI bridge %s\n",
-                      node->full_name);
-               return;
-       }
-
-       bus = pci_add_new_bus(dev->bus, dev, busrange[0]);
-       if (!bus) {
-               printk(KERN_ERR "Failed to create pci bus for %s\n",
-                      node->full_name);
-               return;
-       }
-
-       bus->primary = dev->bus->number;
-       bus->subordinate = busrange[1];
-       bus->bridge_ctl = 0;
-       bus->sysdata = node;
-
-       /* parse ranges property */
-       /* PCI #address-cells == 3 and #size-cells == 2 always */
-       res = &dev->resource[PCI_BRIDGE_RESOURCES];
-       for (i = 0; i < PCI_NUM_RESOURCES - PCI_BRIDGE_RESOURCES; ++i) {
-               res->flags = 0;
-               bus->resource[i] = res;
-               ++res;
-       }
-       i = 1;
-       for (; len >= 32; len -= 32, ranges += 8) {
-               flags = pci_parse_of_flags(ranges[0], 1);
-               size = of_read_number(&ranges[6], 2);
-               if (flags == 0 || size == 0)
-                       continue;
-               if (flags & IORESOURCE_IO) {
-                       res = bus->resource[0];
-                       if (res->flags) {
-                               printk(KERN_ERR "PCI: ignoring extra I/O range"
-                                      " for bridge %s\n", node->full_name);
-                               continue;
-                       }
-               } else {
-                       if (i >= PCI_NUM_RESOURCES - PCI_BRIDGE_RESOURCES) {
-                               printk(KERN_ERR "PCI: too many memory ranges"
-                                      " for bridge %s\n", node->full_name);
-                               continue;
-                       }
-                       res = bus->resource[i];
-                       ++i;
-               }
-               res->start = of_read_number(&ranges[1], 2);
-               res->end = res->start + size - 1;
-               res->flags = flags;
-       }
-       sprintf(bus->name, "PCI Bus %04x:%02x", pci_domain_nr(bus),
-               bus->number);
-       pr_debug("    bus name: %s\n", bus->name);
-
-       mode = PCI_PROBE_NORMAL;
-       if (ppc_md.pci_probe_mode)
-               mode = ppc_md.pci_probe_mode(bus);
-       pr_debug("    probe mode: %d\n", mode);
-
-       if (mode == PCI_PROBE_DEVTREE)
-               of_scan_bus(node, bus);
-       else if (mode == PCI_PROBE_NORMAL)
-               pci_scan_child_bus(bus);
-}
-EXPORT_SYMBOL(of_scan_pci_bridge);
-
-void __devinit scan_phb(struct pci_controller *hose)
-{
-       struct pci_bus *bus;
-       struct device_node *node = hose->dn;
-       int mode;
-
-       pr_debug("PCI: Scanning PHB %s\n",
-                node ? node->full_name : "<NO NAME>");
-
-       /* Create an empty bus for the toplevel */
-       bus = pci_create_bus(hose->parent, hose->first_busno, hose->ops, node);
-       if (bus == NULL) {
-               printk(KERN_ERR "Failed to create bus for PCI domain %04x\n",
-                      hose->global_number);
-               return;
-       }
-       bus->secondary = hose->first_busno;
-       hose->bus = bus;
-
-       /* Get some IO space for the new PHB */
-       pcibios_map_io_space(bus);
-
-       /* Wire up PHB bus resources */
-       pcibios_setup_phb_resources(hose);
-
-       /* Get probe mode and perform scan */
-       mode = PCI_PROBE_NORMAL;
-       if (node && ppc_md.pci_probe_mode)
-               mode = ppc_md.pci_probe_mode(bus);
-       pr_debug("    probe mode: %d\n", mode);
-       if (mode == PCI_PROBE_DEVTREE) {
-               bus->subordinate = hose->last_busno;
-               of_scan_bus(node, bus);
-       }
-
-       if (mode == PCI_PROBE_NORMAL)
-               hose->last_busno = bus->subordinate = pci_scan_child_bus(bus);
-}
-
 static int __init pcibios_init(void)
 {
        struct pci_controller *hose, *tmp;
@@ -392,7 +64,7 @@ static int __init pcibios_init(void)
 
        /* Scan all of the recorded PCI controllers.  */
        list_for_each_entry_safe(hose, tmp, &hose_list, list_node) {
-               scan_phb(hose);
+               pcibios_scan_phb(hose, hose->dn);
                pci_bus_add_devices(hose->bus);
        }
 
@@ -526,6 +198,11 @@ int __devinit pcibios_map_io_space(struct pci_bus *bus)
 }
 EXPORT_SYMBOL_GPL(pcibios_map_io_space);
 
+void __devinit pcibios_setup_phb_io_space(struct pci_controller *hose)
+{
+       pcibios_map_io_space(hose->bus);
+}
+
 #define IOBASE_BRIDGE_NUMBER   0
 #define IOBASE_MEMORY          1
 #define IOBASE_IO              2
diff --git a/arch/powerpc/kernel/pci_of_scan.c b/arch/powerpc/kernel/pci_of_scan.c
new file mode 100644 (file)
index 0000000..72c31bc
--- /dev/null
@@ -0,0 +1,358 @@
+/*
+ * Helper routines to scan the device tree for PCI devices and busses
+ *
+ * Migrated out of PowerPC architecture pci_64.c file by Grant Likely
+ * <grant.likely@secretlab.ca> so that these routines are available for
+ * 32 bit also.
+ *
+ * Copyright (C) 2003 Anton Blanchard <anton@au.ibm.com>, IBM
+ *   Rework, based on alpha PCI code.
+ * Copyright (c) 2009 Secret Lab Technologies Ltd.
+ *
+ * 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.
+ */
+
+#include <linux/pci.h>
+#include <asm/pci-bridge.h>
+#include <asm/prom.h>
+
+/**
+ * get_int_prop - Decode a u32 from a device tree property
+ */
+static u32 get_int_prop(struct device_node *np, const char *name, u32 def)
+{
+       const u32 *prop;
+       int len;
+
+       prop = of_get_property(np, name, &len);
+       if (prop && len >= 4)
+               return *prop;
+       return def;
+}
+
+/**
+ * pci_parse_of_flags - Parse the flags cell of a device tree PCI address
+ * @addr0: value of 1st cell of a device tree PCI address.
+ * @bridge: Set this flag if the address is from a bridge 'ranges' property
+ */
+unsigned int pci_parse_of_flags(u32 addr0, int bridge)
+{
+       unsigned int flags = 0;
+
+       if (addr0 & 0x02000000) {
+               flags = IORESOURCE_MEM | PCI_BASE_ADDRESS_SPACE_MEMORY;
+               flags |= (addr0 >> 22) & PCI_BASE_ADDRESS_MEM_TYPE_64;
+               flags |= (addr0 >> 28) & PCI_BASE_ADDRESS_MEM_TYPE_1M;
+               if (addr0 & 0x40000000)
+                       flags |= IORESOURCE_PREFETCH
+                                | PCI_BASE_ADDRESS_MEM_PREFETCH;
+               /* Note: We don't know whether the ROM has been left enabled
+                * by the firmware or not. We mark it as disabled (ie, we do
+                * not set the IORESOURCE_ROM_ENABLE flag) for now rather than
+                * do a config space read, it will be force-enabled if needed
+                */
+               if (!bridge && (addr0 & 0xff) == 0x30)
+                       flags |= IORESOURCE_READONLY;
+       } else if (addr0 & 0x01000000)
+               flags = IORESOURCE_IO | PCI_BASE_ADDRESS_SPACE_IO;
+       if (flags)
+               flags |= IORESOURCE_SIZEALIGN;
+       return flags;
+}
+
+/**
+ * of_pci_parse_addrs - Parse PCI addresses assigned in the device tree node
+ * @node: device tree node for the PCI device
+ * @dev: pci_dev structure for the device
+ *
+ * This function parses the 'assigned-addresses' property of a PCI devices'
+ * device tree node and writes them into the associated pci_dev structure.
+ */
+static void of_pci_parse_addrs(struct device_node *node, struct pci_dev *dev)
+{
+       u64 base, size;
+       unsigned int flags;
+       struct resource *res;
+       const u32 *addrs;
+       u32 i;
+       int proplen;
+
+       addrs = of_get_property(node, "assigned-addresses", &proplen);
+       if (!addrs)
+               return;
+       pr_debug("    parse addresses (%d bytes) @ %p\n", proplen, addrs);
+       for (; proplen >= 20; proplen -= 20, addrs += 5) {
+               flags = pci_parse_of_flags(addrs[0], 0);
+               if (!flags)
+                       continue;
+               base = of_read_number(&addrs[1], 2);
+               size = of_read_number(&addrs[3], 2);
+               if (!size)
+                       continue;
+               i = addrs[0] & 0xff;
+               pr_debug("  base: %llx, size: %llx, i: %x\n",
+                        (unsigned long long)base,
+                        (unsigned long long)size, i);
+
+               if (PCI_BASE_ADDRESS_0 <= i && i <= PCI_BASE_ADDRESS_5) {
+                       res = &dev->resource[(i - PCI_BASE_ADDRESS_0) >> 2];
+               } else if (i == dev->rom_base_reg) {
+                       res = &dev->resource[PCI_ROM_RESOURCE];
+                       flags |= IORESOURCE_READONLY | IORESOURCE_CACHEABLE;
+               } else {
+                       printk(KERN_ERR "PCI: bad cfg reg num 0x%x\n", i);
+                       continue;
+               }
+               res->start = base;
+               res->end = base + size - 1;
+               res->flags = flags;
+               res->name = pci_name(dev);
+       }
+}
+
+/**
+ * of_create_pci_dev - Given a device tree node on a pci bus, create a pci_dev
+ * @node: device tree node pointer
+ * @bus: bus the device is sitting on
+ * @devfn: PCI function number, extracted from device tree by caller.
+ */
+struct pci_dev *of_create_pci_dev(struct device_node *node,
+                                struct pci_bus *bus, int devfn)
+{
+       struct pci_dev *dev;
+       const char *type;
+
+       dev = alloc_pci_dev();
+       if (!dev)
+               return NULL;
+       type = of_get_property(node, "device_type", NULL);
+       if (type == NULL)
+               type = "";
+
+       pr_debug("    create device, devfn: %x, type: %s\n", devfn, type);
+
+       dev->bus = bus;
+       dev->sysdata = node;
+       dev->dev.parent = bus->bridge;
+       dev->dev.bus = &pci_bus_type;
+       dev->devfn = devfn;
+       dev->multifunction = 0;         /* maybe a lie? */
+
+       dev->vendor = get_int_prop(node, "vendor-id", 0xffff);
+       dev->device = get_int_prop(node, "device-id", 0xffff);
+       dev->subsystem_vendor = get_int_prop(node, "subsystem-vendor-id", 0);
+       dev->subsystem_device = get_int_prop(node, "subsystem-id", 0);
+
+       dev->cfg_size = pci_cfg_space_size(dev);
+
+       dev_set_name(&dev->dev, "%04x:%02x:%02x.%d", pci_domain_nr(bus),
+               dev->bus->number, PCI_SLOT(devfn), PCI_FUNC(devfn));
+       dev->class = get_int_prop(node, "class-code", 0);
+       dev->revision = get_int_prop(node, "revision-id", 0);
+
+       pr_debug("    class: 0x%x\n", dev->class);
+       pr_debug("    revision: 0x%x\n", dev->revision);
+
+       dev->current_state = 4;         /* unknown power state */
+       dev->error_state = pci_channel_io_normal;
+       dev->dma_mask = 0xffffffff;
+
+       if (!strcmp(type, "pci") || !strcmp(type, "pciex")) {
+               /* a PCI-PCI bridge */
+               dev->hdr_type = PCI_HEADER_TYPE_BRIDGE;
+               dev->rom_base_reg = PCI_ROM_ADDRESS1;
+       } else if (!strcmp(type, "cardbus")) {
+               dev->hdr_type = PCI_HEADER_TYPE_CARDBUS;
+       } else {
+               dev->hdr_type = PCI_HEADER_TYPE_NORMAL;
+               dev->rom_base_reg = PCI_ROM_ADDRESS;
+               /* Maybe do a default OF mapping here */
+               dev->irq = NO_IRQ;
+       }
+
+       of_pci_parse_addrs(node, dev);
+
+       pr_debug("    adding to system ...\n");
+
+       pci_device_add(dev, bus);
+
+       return dev;
+}
+EXPORT_SYMBOL(of_create_pci_dev);
+
+/**
+ * of_scan_pci_bridge - Set up a PCI bridge and scan for child nodes
+ * @node: device tree node of bridge
+ * @dev: pci_dev structure for the bridge
+ *
+ * of_scan_bus() calls this routine for each PCI bridge that it finds, and
+ * this routine in turn call of_scan_bus() recusively to scan for more child
+ * devices.
+ */
+void __devinit of_scan_pci_bridge(struct device_node *node,
+                                 struct pci_dev *dev)
+{
+       struct pci_bus *bus;
+       const u32 *busrange, *ranges;
+       int len, i, mode;
+       struct resource *res;
+       unsigned int flags;
+       u64 size;
+
+       pr_debug("of_scan_pci_bridge(%s)\n", node->full_name);
+
+       /* parse bus-range property */
+       busrange = of_get_property(node, "bus-range", &len);
+       if (busrange == NULL || len != 8) {
+               printk(KERN_DEBUG "Can't get bus-range for PCI-PCI bridge %s\n",
+                      node->full_name);
+               return;
+       }
+       ranges = of_get_property(node, "ranges", &len);
+       if (ranges == NULL) {
+               printk(KERN_DEBUG "Can't get ranges for PCI-PCI bridge %s\n",
+                      node->full_name);
+               return;
+       }
+
+       bus = pci_add_new_bus(dev->bus, dev, busrange[0]);
+       if (!bus) {
+               printk(KERN_ERR "Failed to create pci bus for %s\n",
+                      node->full_name);
+               return;
+       }
+
+       bus->primary = dev->bus->number;
+       bus->subordinate = busrange[1];
+       bus->bridge_ctl = 0;
+       bus->sysdata = node;
+
+       /* parse ranges property */
+       /* PCI #address-cells == 3 and #size-cells == 2 always */
+       res = &dev->resource[PCI_BRIDGE_RESOURCES];
+       for (i = 0; i < PCI_NUM_RESOURCES - PCI_BRIDGE_RESOURCES; ++i) {
+               res->flags = 0;
+               bus->resource[i] = res;
+               ++res;
+       }
+       i = 1;
+       for (; len >= 32; len -= 32, ranges += 8) {
+               flags = pci_parse_of_flags(ranges[0], 1);
+               size = of_read_number(&ranges[6], 2);
+               if (flags == 0 || size == 0)
+                       continue;
+               if (flags & IORESOURCE_IO) {
+                       res = bus->resource[0];
+                       if (res->flags) {
+                               printk(KERN_ERR "PCI: ignoring extra I/O range"
+                                      " for bridge %s\n", node->full_name);
+                               continue;
+                       }
+               } else {
+                       if (i >= PCI_NUM_RESOURCES - PCI_BRIDGE_RESOURCES) {
+                               printk(KERN_ERR "PCI: too many memory ranges"
+                                      " for bridge %s\n", node->full_name);
+                               continue;
+                       }
+                       res = bus->resource[i];
+                       ++i;
+               }
+               res->start = of_read_number(&ranges[1], 2);
+               res->end = res->start + size - 1;
+               res->flags = flags;
+       }
+       sprintf(bus->name, "PCI Bus %04x:%02x", pci_domain_nr(bus),
+               bus->number);
+       pr_debug("    bus name: %s\n", bus->name);
+
+       mode = PCI_PROBE_NORMAL;
+       if (ppc_md.pci_probe_mode)
+               mode = ppc_md.pci_probe_mode(bus);
+       pr_debug("    probe mode: %d\n", mode);
+
+       if (mode == PCI_PROBE_DEVTREE)
+               of_scan_bus(node, bus);
+       else if (mode == PCI_PROBE_NORMAL)
+               pci_scan_child_bus(bus);
+}
+EXPORT_SYMBOL(of_scan_pci_bridge);
+
+/**
+ * __of_scan_bus - given a PCI bus node, setup bus and scan for child devices
+ * @node: device tree node for the PCI bus
+ * @bus: pci_bus structure for the PCI bus
+ * @rescan_existing: Flag indicating bus has already been set up
+ */
+static void __devinit __of_scan_bus(struct device_node *node,
+                                   struct pci_bus *bus, int rescan_existing)
+{
+       struct device_node *child;
+       const u32 *reg;
+       int reglen, devfn;
+       struct pci_dev *dev;
+
+       pr_debug("of_scan_bus(%s) bus no %d... \n",
+                node->full_name, bus->number);
+
+       /* Scan direct children */
+       for_each_child_of_node(node, child) {
+               pr_debug("  * %s\n", child->full_name);
+               reg = of_get_property(child, "reg", &reglen);
+               if (reg == NULL || reglen < 20)
+                       continue;
+               devfn = (reg[0] >> 8) & 0xff;
+
+               /* create a new pci_dev for this device */
+               dev = of_create_pci_dev(child, bus, devfn);
+               if (!dev)
+                       continue;
+               pr_debug("    dev header type: %x\n", dev->hdr_type);
+       }
+
+       /* Apply all fixups necessary. We don't fixup the bus "self"
+        * for an existing bridge that is being rescanned
+        */
+       if (!rescan_existing)
+               pcibios_setup_bus_self(bus);
+       pcibios_setup_bus_devices(bus);
+
+       /* Now scan child busses */
+       list_for_each_entry(dev, &bus->devices, bus_list) {
+               if (dev->hdr_type == PCI_HEADER_TYPE_BRIDGE ||
+                   dev->hdr_type == PCI_HEADER_TYPE_CARDBUS) {
+                       struct device_node *child = pci_device_to_OF_node(dev);
+                       if (dev)
+                               of_scan_pci_bridge(child, dev);
+               }
+       }
+}
+
+/**
+ * of_scan_bus - given a PCI bus node, setup bus and scan for child devices
+ * @node: device tree node for the PCI bus
+ * @bus: pci_bus structure for the PCI bus
+ */
+void __devinit of_scan_bus(struct device_node *node,
+                          struct pci_bus *bus)
+{
+       __of_scan_bus(node, bus, 0);
+}
+EXPORT_SYMBOL_GPL(of_scan_bus);
+
+/**
+ * of_rescan_bus - given a PCI bus node, scan for child devices
+ * @node: device tree node for the PCI bus
+ * @bus: pci_bus structure for the PCI bus
+ *
+ * Same as of_scan_bus, but for a pci_bus structure that has already been
+ * setup.
+ */
+void __devinit of_rescan_bus(struct device_node *node,
+                            struct pci_bus *bus)
+{
+       __of_scan_bus(node, bus, 1);
+}
+EXPORT_SYMBOL_GPL(of_rescan_bus);
+
index 70e1f57f7dd864bb2ec9d2f2e5e16c301e647a19..7ceefaf3a7f5e51af1fb44dff457117d7034f4f4 100644 (file)
@@ -32,6 +32,9 @@ struct cpu_hw_counters {
        unsigned long mmcr[3];
        struct perf_counter *limited_counter[MAX_LIMITED_HWCOUNTERS];
        u8  limited_hwidx[MAX_LIMITED_HWCOUNTERS];
+       u64 alternatives[MAX_HWCOUNTERS][MAX_EVENT_ALTERNATIVES];
+       unsigned long amasks[MAX_HWCOUNTERS][MAX_EVENT_ALTERNATIVES];
+       unsigned long avalues[MAX_HWCOUNTERS][MAX_EVENT_ALTERNATIVES];
 };
 DEFINE_PER_CPU(struct cpu_hw_counters, cpu_hw_counters);
 
@@ -62,7 +65,6 @@ static inline unsigned long perf_ip_adjust(struct pt_regs *regs)
 {
        return 0;
 }
-static inline void perf_set_pmu_inuse(int inuse) { }
 static inline void perf_get_data_addr(struct pt_regs *regs, u64 *addrp) { }
 static inline u32 perf_get_misc_flags(struct pt_regs *regs)
 {
@@ -93,11 +95,6 @@ static inline unsigned long perf_ip_adjust(struct pt_regs *regs)
        return 0;
 }
 
-static inline void perf_set_pmu_inuse(int inuse)
-{
-       get_lppaca()->pmcregs_in_use = inuse;
-}
-
 /*
  * The user wants a data address recorded.
  * If we're not doing instruction sampling, give them the SDAR
@@ -245,13 +242,11 @@ static void write_pmc(int idx, unsigned long val)
  * and see if any combination of alternative codes is feasible.
  * The feasible set is returned in event[].
  */
-static int power_check_constraints(u64 event[], unsigned int cflags[],
+static int power_check_constraints(struct cpu_hw_counters *cpuhw,
+                                  u64 event[], unsigned int cflags[],
                                   int n_ev)
 {
        unsigned long mask, value, nv;
-       u64 alternatives[MAX_HWCOUNTERS][MAX_EVENT_ALTERNATIVES];
-       unsigned long amasks[MAX_HWCOUNTERS][MAX_EVENT_ALTERNATIVES];
-       unsigned long avalues[MAX_HWCOUNTERS][MAX_EVENT_ALTERNATIVES];
        unsigned long smasks[MAX_HWCOUNTERS], svalues[MAX_HWCOUNTERS];
        int n_alt[MAX_HWCOUNTERS], choice[MAX_HWCOUNTERS];
        int i, j;
@@ -266,21 +261,23 @@ static int power_check_constraints(u64 event[], unsigned int cflags[],
                if ((cflags[i] & PPMU_LIMITED_PMC_REQD)
                    && !ppmu->limited_pmc_event(event[i])) {
                        ppmu->get_alternatives(event[i], cflags[i],
-                                              alternatives[i]);
-                       event[i] = alternatives[i][0];
+                                              cpuhw->alternatives[i]);
+                       event[i] = cpuhw->alternatives[i][0];
                }
-               if (ppmu->get_constraint(event[i], &amasks[i][0],
-                                        &avalues[i][0]))
+               if (ppmu->get_constraint(event[i], &cpuhw->amasks[i][0],
+                                        &cpuhw->avalues[i][0]))
                        return -1;
        }
        value = mask = 0;
        for (i = 0; i < n_ev; ++i) {
-               nv = (value | avalues[i][0]) + (value & avalues[i][0] & addf);
+               nv = (value | cpuhw->avalues[i][0]) +
+                       (value & cpuhw->avalues[i][0] & addf);
                if ((((nv + tadd) ^ value) & mask) != 0 ||
-                   (((nv + tadd) ^ avalues[i][0]) & amasks[i][0]) != 0)
+                   (((nv + tadd) ^ cpuhw->avalues[i][0]) &
+                    cpuhw->amasks[i][0]) != 0)
                        break;
                value = nv;
-               mask |= amasks[i][0];
+               mask |= cpuhw->amasks[i][0];
        }
        if (i == n_ev)
                return 0;       /* all OK */
@@ -291,10 +288,11 @@ static int power_check_constraints(u64 event[], unsigned int cflags[],
        for (i = 0; i < n_ev; ++i) {
                choice[i] = 0;
                n_alt[i] = ppmu->get_alternatives(event[i], cflags[i],
-                                                 alternatives[i]);
+                                                 cpuhw->alternatives[i]);
                for (j = 1; j < n_alt[i]; ++j)
-                       ppmu->get_constraint(alternatives[i][j],
-                                            &amasks[i][j], &avalues[i][j]);
+                       ppmu->get_constraint(cpuhw->alternatives[i][j],
+                                            &cpuhw->amasks[i][j],
+                                            &cpuhw->avalues[i][j]);
        }
 
        /* enumerate all possibilities and see if any will work */
@@ -313,11 +311,11 @@ static int power_check_constraints(u64 event[], unsigned int cflags[],
                 * where k > j, will satisfy the constraints.
                 */
                while (++j < n_alt[i]) {
-                       nv = (value | avalues[i][j]) +
-                               (value & avalues[i][j] & addf);
+                       nv = (value | cpuhw->avalues[i][j]) +
+                               (value & cpuhw->avalues[i][j] & addf);
                        if ((((nv + tadd) ^ value) & mask) == 0 &&
-                           (((nv + tadd) ^ avalues[i][j])
-                            & amasks[i][j]) == 0)
+                           (((nv + tadd) ^ cpuhw->avalues[i][j])
+                            & cpuhw->amasks[i][j]) == 0)
                                break;
                }
                if (j >= n_alt[i]) {
@@ -339,7 +337,7 @@ static int power_check_constraints(u64 event[], unsigned int cflags[],
                        svalues[i] = value;
                        smasks[i] = mask;
                        value = nv;
-                       mask |= amasks[i][j];
+                       mask |= cpuhw->amasks[i][j];
                        ++i;
                        j = -1;
                }
@@ -347,7 +345,7 @@ static int power_check_constraints(u64 event[], unsigned int cflags[],
 
        /* OK, we have a feasible combination, tell the caller the solution */
        for (i = 0; i < n_ev; ++i)
-               event[i] = alternatives[i][choice[i]];
+               event[i] = cpuhw->alternatives[i][choice[i]];
        return 0;
 }
 
@@ -531,8 +529,7 @@ void hw_perf_disable(void)
                 * Check if we ever enabled the PMU on this cpu.
                 */
                if (!cpuhw->pmcs_enabled) {
-                       if (ppc_md.enable_pmcs)
-                               ppc_md.enable_pmcs();
+                       ppc_enable_pmcs();
                        cpuhw->pmcs_enabled = 1;
                }
 
@@ -594,7 +591,7 @@ void hw_perf_enable(void)
                mtspr(SPRN_MMCRA, cpuhw->mmcr[2] & ~MMCRA_SAMPLE_ENABLE);
                mtspr(SPRN_MMCR1, cpuhw->mmcr[1]);
                if (cpuhw->n_counters == 0)
-                       perf_set_pmu_inuse(0);
+                       ppc_set_pmu_inuse(0);
                goto out_enable;
        }
 
@@ -627,7 +624,7 @@ void hw_perf_enable(void)
         * bit set and set the hardware counters to their initial values.
         * Then unfreeze the counters.
         */
-       perf_set_pmu_inuse(1);
+       ppc_set_pmu_inuse(1);
        mtspr(SPRN_MMCRA, cpuhw->mmcr[2] & ~MMCRA_SAMPLE_ENABLE);
        mtspr(SPRN_MMCR1, cpuhw->mmcr[1]);
        mtspr(SPRN_MMCR0, (cpuhw->mmcr[0] & ~(MMCR0_PMC1CE | MMCR0_PMCjCE))
@@ -752,7 +749,7 @@ int hw_perf_group_sched_in(struct perf_counter *group_leader,
                return -EAGAIN;
        if (check_excludes(cpuhw->counter, cpuhw->flags, n0, n))
                return -EAGAIN;
-       i = power_check_constraints(cpuhw->events, cpuhw->flags, n + n0);
+       i = power_check_constraints(cpuhw, cpuhw->events, cpuhw->flags, n + n0);
        if (i < 0)
                return -EAGAIN;
        cpuhw->n_counters = n0 + n;
@@ -807,7 +804,7 @@ static int power_pmu_enable(struct perf_counter *counter)
        cpuhw->flags[n0] = counter->hw.counter_base;
        if (check_excludes(cpuhw->counter, cpuhw->flags, n0, 1))
                goto out;
-       if (power_check_constraints(cpuhw->events, cpuhw->flags, n0 + 1))
+       if (power_check_constraints(cpuhw, cpuhw->events, cpuhw->flags, n0 + 1))
                goto out;
 
        counter->hw.config = cpuhw->events[n0];
@@ -1012,6 +1009,7 @@ const struct pmu *hw_perf_counter_init(struct perf_counter *counter)
        unsigned int cflags[MAX_HWCOUNTERS];
        int n;
        int err;
+       struct cpu_hw_counters *cpuhw;
 
        if (!ppmu)
                return ERR_PTR(-ENXIO);
@@ -1090,7 +1088,11 @@ const struct pmu *hw_perf_counter_init(struct perf_counter *counter)
        cflags[n] = flags;
        if (check_excludes(ctrs, cflags, n, 1))
                return ERR_PTR(-EINVAL);
-       if (power_check_constraints(events, cflags, n + 1))
+
+       cpuhw = &get_cpu_var(cpu_hw_counters);
+       err = power_check_constraints(cpuhw, events, cflags, n + 1);
+       put_cpu_var(cpu_hw_counters);
+       if (err)
                return ERR_PTR(-EINVAL);
 
        counter->hw.config = events[n];
index 892a9f2e6d76a40c44b7d67d5bff9a8912863020..0a3216433051e0d2c806b5533a09853d230c2502 100644 (file)
@@ -284,14 +284,13 @@ int set_dabr(unsigned long dabr)
                return ppc_md.set_dabr(dabr);
 
        /* XXX should we have a CPU_FTR_HAS_DABR ? */
-#if defined(CONFIG_PPC64) || defined(CONFIG_6xx)
-       mtspr(SPRN_DABR, dabr);
-#endif
-
 #if defined(CONFIG_BOOKE)
        mtspr(SPRN_DAC1, dabr);
+#elif defined(CONFIG_PPC_BOOK3S)
+       mtspr(SPRN_DABR, dabr);
 #endif
 
+
        return 0;
 }
 
@@ -372,15 +371,16 @@ struct task_struct *__switch_to(struct task_struct *prev,
 
 #endif /* CONFIG_SMP */
 
-       if (unlikely(__get_cpu_var(current_dabr) != new->thread.dabr))
-               set_dabr(new->thread.dabr);
-
 #if defined(CONFIG_BOOKE)
        /* If new thread DAC (HW breakpoint) is the same then leave it */
        if (new->thread.dabr)
                set_dabr(new->thread.dabr);
+#else
+       if (unlikely(__get_cpu_var(current_dabr) != new->thread.dabr))
+               set_dabr(new->thread.dabr);
 #endif
 
+
        new_thread = &new->thread;
        old_thread = &current->thread;
 
@@ -664,6 +664,7 @@ int copy_thread(unsigned long clone_flags, unsigned long usp,
                sp_vsid |= SLB_VSID_KERNEL | llp;
                p->thread.ksp_vsid = sp_vsid;
        }
+#endif /* CONFIG_PPC_STD_MMU_64 */
 
        /*
         * The PPC64 ABI makes use of a TOC to contain function 
@@ -671,6 +672,7 @@ int copy_thread(unsigned long clone_flags, unsigned long usp,
         * to the TOC entry.  The first entry is a pointer to the actual
         * function.
         */
+#ifdef CONFIG_PPC64
        kregs->nip = *((unsigned long *)ret_from_fork);
 #else
        kregs->nip = (unsigned long)ret_from_fork;
index a538824616fd736e20978bb822e09b98f2432263..864334b337a356c9f8615790eb82a56da4f13715 100644 (file)
@@ -190,6 +190,8 @@ static int __initdata of_platform;
 
 static char __initdata prom_cmd_line[COMMAND_LINE_SIZE];
 
+static unsigned long __initdata prom_memory_limit;
+
 static unsigned long __initdata alloc_top;
 static unsigned long __initdata alloc_top_high;
 static unsigned long __initdata alloc_bottom;
@@ -484,6 +486,67 @@ static int __init prom_setprop(phandle node, const char *nodename,
        return call_prom("interpret", 1, 1, (u32)(unsigned long) cmd);
 }
 
+/* We can't use the standard versions because of RELOC headaches. */
+#define isxdigit(c)    (('0' <= (c) && (c) <= '9') \
+                        || ('a' <= (c) && (c) <= 'f') \
+                        || ('A' <= (c) && (c) <= 'F'))
+
+#define isdigit(c)     ('0' <= (c) && (c) <= '9')
+#define islower(c)     ('a' <= (c) && (c) <= 'z')
+#define toupper(c)     (islower(c) ? ((c) - 'a' + 'A') : (c))
+
+unsigned long prom_strtoul(const char *cp, const char **endp)
+{
+       unsigned long result = 0, base = 10, value;
+
+       if (*cp == '0') {
+               base = 8;
+               cp++;
+               if (toupper(*cp) == 'X') {
+                       cp++;
+                       base = 16;
+               }
+       }
+
+       while (isxdigit(*cp) &&
+              (value = isdigit(*cp) ? *cp - '0' : toupper(*cp) - 'A' + 10) < base) {
+               result = result * base + value;
+               cp++;
+       }
+
+       if (endp)
+               *endp = cp;
+
+       return result;
+}
+
+unsigned long prom_memparse(const char *ptr, const char **retptr)
+{
+       unsigned long ret = prom_strtoul(ptr, retptr);
+       int shift = 0;
+
+       /*
+        * We can't use a switch here because GCC *may* generate a
+        * jump table which won't work, because we're not running at
+        * the address we're linked at.
+        */
+       if ('G' == **retptr || 'g' == **retptr)
+               shift = 30;
+
+       if ('M' == **retptr || 'm' == **retptr)
+               shift = 20;
+
+       if ('K' == **retptr || 'k' == **retptr)
+               shift = 10;
+
+       if (shift) {
+               ret <<= shift;
+               (*retptr)++;
+       }
+
+       return ret;
+}
+
 /*
  * Early parsing of the command line passed to the kernel, used for
  * "mem=x" and the options that affect the iommu
@@ -491,9 +554,8 @@ static int __init prom_setprop(phandle node, const char *nodename,
 static void __init early_cmdline_parse(void)
 {
        struct prom_t *_prom = &RELOC(prom);
-#ifdef CONFIG_PPC64
        const char *opt;
-#endif
+
        char *p;
        int l = 0;
 
@@ -521,6 +583,15 @@ static void __init early_cmdline_parse(void)
                        RELOC(prom_iommu_force_on) = 1;
        }
 #endif
+       opt = strstr(RELOC(prom_cmd_line), RELOC("mem="));
+       if (opt) {
+               opt += 4;
+               RELOC(prom_memory_limit) = prom_memparse(opt, (const char **)&opt);
+#ifdef CONFIG_PPC64
+               /* Align to 16 MB == size of ppc64 large page */
+               RELOC(prom_memory_limit) = ALIGN(RELOC(prom_memory_limit), 0x1000000);
+#endif
+       }
 }
 
 #ifdef CONFIG_PPC_PSERIES
@@ -1026,6 +1097,29 @@ static void __init prom_init_mem(void)
                        RELOC(alloc_bottom) = PAGE_ALIGN(RELOC(prom_initrd_end));
        }
 
+       /*
+        * If prom_memory_limit is set we reduce the upper limits *except* for
+        * alloc_top_high. This must be the real top of RAM so we can put
+        * TCE's up there.
+        */
+
+       RELOC(alloc_top_high) = RELOC(ram_top);
+
+       if (RELOC(prom_memory_limit)) {
+               if (RELOC(prom_memory_limit) <= RELOC(alloc_bottom)) {
+                       prom_printf("Ignoring mem=%x <= alloc_bottom.\n",
+                               RELOC(prom_memory_limit));
+                       RELOC(prom_memory_limit) = 0;
+               } else if (RELOC(prom_memory_limit) >= RELOC(ram_top)) {
+                       prom_printf("Ignoring mem=%x >= ram_top.\n",
+                               RELOC(prom_memory_limit));
+                       RELOC(prom_memory_limit) = 0;
+               } else {
+                       RELOC(ram_top) = RELOC(prom_memory_limit);
+                       RELOC(rmo_top) = min(RELOC(rmo_top), RELOC(prom_memory_limit));
+               }
+       }
+
        /*
         * Setup our top alloc point, that is top of RMO or top of
         * segment 0 when running non-LPAR.
@@ -1041,6 +1135,7 @@ static void __init prom_init_mem(void)
        RELOC(alloc_top_high) = RELOC(ram_top);
 
        prom_printf("memory layout at init:\n");
+       prom_printf("  memory_limit : %x (16 MB aligned)\n", RELOC(prom_memory_limit));
        prom_printf("  alloc_bottom : %x\n", RELOC(alloc_bottom));
        prom_printf("  alloc_top    : %x\n", RELOC(alloc_top));
        prom_printf("  alloc_top_hi : %x\n", RELOC(alloc_top_high));
@@ -1259,10 +1354,6 @@ static void __init prom_initialize_tce_table(void)
  *
  * -- Cort
  */
-extern char __secondary_hold;
-extern unsigned long __secondary_hold_spinloop;
-extern unsigned long __secondary_hold_acknowledge;
-
 /*
  * We want to reference the copy of __secondary_hold_* in the
  * 0 - 0x100 address range
@@ -2399,6 +2490,10 @@ unsigned long __init prom_init(unsigned long r3, unsigned long r4,
        /*
         * Fill in some infos for use by the kernel later on
         */
+       if (RELOC(prom_memory_limit))
+               prom_setprop(_prom->chosen, "/chosen", "linux,memory-limit",
+                            &RELOC(prom_memory_limit),
+                            sizeof(prom_memory_limit));
 #ifdef CONFIG_PPC64
        if (RELOC(prom_iommu_off))
                prom_setprop(_prom->chosen, "/chosen", "linux,iommu-off",
index c434823b8c83a02b9ccd161e2e22bea1c52a1c65..bf90361bb70f3664fb02742bc3514f145207b26d 100644 (file)
@@ -39,6 +39,7 @@
 #include <asm/smp.h>
 #include <asm/atomic.h>
 #include <asm/time.h>
+#include <asm/mmu.h>
 
 struct rtas_t rtas = {
        .lock = __RAW_SPIN_LOCK_UNLOCKED
@@ -713,6 +714,7 @@ static void rtas_percpu_suspend_me(void *info)
 {
        long rc = H_SUCCESS;
        unsigned long msr_save;
+       u16 slb_size = mmu_slb_size;
        int cpu;
        struct rtas_suspend_me_data *data =
                (struct rtas_suspend_me_data *)info;
@@ -735,13 +737,16 @@ static void rtas_percpu_suspend_me(void *info)
                /* All other cpus are in H_JOIN, this cpu does
                 * the suspend.
                 */
+               slb_set_size(SLB_MIN_SIZE);
                printk(KERN_DEBUG "calling ibm,suspend-me on cpu %i\n",
                       smp_processor_id());
                data->error = rtas_call(data->token, 0, 1, NULL);
 
-               if (data->error)
+               if (data->error) {
                        printk(KERN_DEBUG "ibm,suspend-me returned %d\n",
                               data->error);
+                       slb_set_size(slb_size);
+               }
        } else {
                printk(KERN_ERR "H_JOIN on cpu %i failed with rc = %ld\n",
                       smp_processor_id(), rc);
index e1e3059cf34b9472ea06f1d71b1cc9114ee8ead2..53bcf3d792db1e16bce7066389fa29e7451602a7 100644 (file)
@@ -210,6 +210,14 @@ void nvram_write_byte(unsigned char val, int addr)
 }
 EXPORT_SYMBOL(nvram_write_byte);
 
+ssize_t nvram_get_size(void)
+{
+       if (ppc_md.nvram_size)
+               return ppc_md.nvram_size();
+       return -1;
+}
+EXPORT_SYMBOL(nvram_get_size);
+
 void nvram_sync(void)
 {
        if (ppc_md.nvram_sync)
index 1f6816003ebef9bebcbb3319e83bac2243437d47..797ea95aae2e66858f9a8dbb1ac47d8e1de6b02a 100644 (file)
 #include <asm/cache.h>
 #include <asm/page.h>
 #include <asm/mmu.h>
+#include <asm/mmu-hash64.h>
 #include <asm/firmware.h>
 #include <asm/xmon.h>
 #include <asm/udbg.h>
 #include <asm/kexec.h>
 #include <asm/swiotlb.h>
+#include <asm/mmu_context.h>
 
 #include "setup.h"
 
@@ -142,11 +144,14 @@ early_param("smt-enabled", early_smt_enabled);
 #define check_smt_enabled()
 #endif /* CONFIG_SMP */
 
-/* Put the paca pointer into r13 and SPRG3 */
+/* Put the paca pointer into r13 and SPRG_PACA */
 void __init setup_paca(int cpu)
 {
        local_paca = &paca[cpu];
-       mtspr(SPRN_SPRG3, local_paca);
+       mtspr(SPRN_SPRG_PACA, local_paca);
+#ifdef CONFIG_PPC_BOOK3E
+       mtspr(SPRN_SPRG_TLB_EXFRAME, local_paca->extlb);
+#endif
 }
 
 /*
@@ -230,9 +235,6 @@ void early_setup_secondary(void)
 #endif /* CONFIG_SMP */
 
 #if defined(CONFIG_SMP) || defined(CONFIG_KEXEC)
-extern unsigned long __secondary_hold_spinloop;
-extern void generic_secondary_smp_init(void);
-
 void smp_release_cpus(void)
 {
        unsigned long *ptr;
@@ -453,6 +455,24 @@ static void __init irqstack_early_init(void)
 #define irqstack_early_init()
 #endif
 
+#ifdef CONFIG_PPC_BOOK3E
+static void __init exc_lvl_early_init(void)
+{
+       unsigned int i;
+
+       for_each_possible_cpu(i) {
+               critirq_ctx[i] = (struct thread_info *)
+                       __va(lmb_alloc(THREAD_SIZE, THREAD_SIZE));
+               dbgirq_ctx[i] = (struct thread_info *)
+                       __va(lmb_alloc(THREAD_SIZE, THREAD_SIZE));
+               mcheckirq_ctx[i] = (struct thread_info *)
+                       __va(lmb_alloc(THREAD_SIZE, THREAD_SIZE));
+       }
+}
+#else
+#define exc_lvl_early_init()
+#endif
+
 /*
  * Stack space used when we detect a bad kernel stack pointer, and
  * early in SMP boots before relocation is enabled.
@@ -512,6 +532,7 @@ void __init setup_arch(char **cmdline_p)
        init_mm.brk = klimit;
        
        irqstack_early_init();
+       exc_lvl_early_init();
        emergency_stack_init();
 
 #ifdef CONFIG_PPC_STD_MMU_64
@@ -534,6 +555,10 @@ void __init setup_arch(char **cmdline_p)
 #endif
 
        paging_init();
+
+       /* Initialize the MMU context management stuff */
+       mmu_context_init();
+
        ppc64_boot_msg(0x15, "Setup Done");
 }
 
@@ -569,25 +594,53 @@ void cpu_die(void)
 }
 
 #ifdef CONFIG_SMP
-void __init setup_per_cpu_areas(void)
+#define PCPU_DYN_SIZE          ()
+
+static void * __init pcpu_fc_alloc(unsigned int cpu, size_t size, size_t align)
 {
-       int i;
-       unsigned long size;
-       char *ptr;
-
-       /* Copy section for each CPU (we discard the original) */
-       size = ALIGN(__per_cpu_end - __per_cpu_start, PAGE_SIZE);
-#ifdef CONFIG_MODULES
-       if (size < PERCPU_ENOUGH_ROOM)
-               size = PERCPU_ENOUGH_ROOM;
-#endif
+       return __alloc_bootmem_node(NODE_DATA(cpu_to_node(cpu)), size, align,
+                                   __pa(MAX_DMA_ADDRESS));
+}
 
-       for_each_possible_cpu(i) {
-               ptr = alloc_bootmem_pages_node(NODE_DATA(cpu_to_node(i)), size);
+static void __init pcpu_fc_free(void *ptr, size_t size)
+{
+       free_bootmem(__pa(ptr), size);
+}
 
-               paca[i].data_offset = ptr - __per_cpu_start;
-               memcpy(ptr, __per_cpu_start, __per_cpu_end - __per_cpu_start);
-       }
+static int pcpu_cpu_distance(unsigned int from, unsigned int to)
+{
+       if (cpu_to_node(from) == cpu_to_node(to))
+               return LOCAL_DISTANCE;
+       else
+               return REMOTE_DISTANCE;
+}
+
+void __init setup_per_cpu_areas(void)
+{
+       const size_t dyn_size = PERCPU_MODULE_RESERVE + PERCPU_DYNAMIC_RESERVE;
+       size_t atom_size;
+       unsigned long delta;
+       unsigned int cpu;
+       int rc;
+
+       /*
+        * Linear mapping is one of 4K, 1M and 16M.  For 4K, no need
+        * to group units.  For larger mappings, use 1M atom which
+        * should be large enough to contain a number of units.
+        */
+       if (mmu_linear_psize == MMU_PAGE_4K)
+               atom_size = PAGE_SIZE;
+       else
+               atom_size = 1 << 20;
+
+       rc = pcpu_embed_first_chunk(0, dyn_size, atom_size, pcpu_cpu_distance,
+                                   pcpu_fc_alloc, pcpu_fc_free);
+       if (rc < 0)
+               panic("cannot initialize percpu area (err=%d)", rc);
+
+       delta = (unsigned long)pcpu_base_addr - (unsigned long)__per_cpu_start;
+       for_each_possible_cpu(cpu)
+               paca[cpu].data_offset = delta + pcpu_unit_offsets[cpu];
 }
 #endif
 
index 0b47de07302d1306dcedf5dff3188a0a5514fd47..d387b3937ccceb16bd84d707b8949a3200338d20 100644 (file)
@@ -269,7 +269,10 @@ void __init smp_prepare_cpus(unsigned int max_cpus)
        cpu_callin_map[boot_cpuid] = 1;
 
        if (smp_ops)
-               max_cpus = smp_ops->probe();
+               if (smp_ops->probe)
+                       max_cpus = smp_ops->probe();
+               else
+                       max_cpus = NR_CPUS;
        else
                max_cpus = 1;
  
@@ -412,9 +415,8 @@ int __cpuinit __cpu_up(unsigned int cpu)
                 * CPUs can take much longer to come up in the
                 * hotplug case.  Wait five seconds.
                 */
-               for (c = 25; c && !cpu_callin_map[cpu]; c--) {
-                       msleep(200);
-               }
+               for (c = 5000; c && !cpu_callin_map[cpu]; c--)
+                       msleep(1);
 #endif
 
        if (!cpu_callin_map[cpu]) {
@@ -494,7 +496,8 @@ int __devinit start_secondary(void *unused)
        preempt_disable();
        cpu_callin_map[cpu] = 1;
 
-       smp_ops->setup_cpu(cpu);
+       if (smp_ops->setup_cpu)
+               smp_ops->setup_cpu(cpu);
        if (smp_ops->take_timebase)
                smp_ops->take_timebase();
 
@@ -557,7 +560,7 @@ void __init smp_cpus_done(unsigned int max_cpus)
        old_mask = current->cpus_allowed;
        set_cpus_allowed(current, cpumask_of_cpu(boot_cpuid));
        
-       if (smp_ops)
+       if (smp_ops && smp_ops->setup_cpu)
                smp_ops->setup_cpu(boot_cpuid);
 
        set_cpus_allowed(current, old_mask);
index bb1cfcfdbbbbc02e73c4c5292b900e6f7a86c8f8..1cc5e9e5da96a78b6a5c58ac678583be63e2b4b2 100644 (file)
@@ -343,6 +343,18 @@ off_t ppc32_lseek(unsigned int fd, u32 offset, unsigned int origin)
        return sys_lseek(fd, (int)offset, origin);
 }
 
+long compat_sys_truncate(const char __user * path, u32 length)
+{
+       /* sign extend length */
+       return sys_truncate(path, (int)length);
+}
+
+long compat_sys_ftruncate(int fd, u32 length)
+{
+       /* sign extend length */
+       return sys_ftruncate(fd, (int)length);
+}
+
 /* Note: it is necessary to treat bufsiz as an unsigned int,
  * with the corresponding cast to a signed int to insure that the 
  * proper conversion (sign extension) between the register representation of a signed int (msr in 32-bit mode)
index f41aec85aa497b1dd90c6da64d9e8389c22c80e1..956ab33fd73fb98096c16fb760dce8695aa6f873 100644 (file)
@@ -17,6 +17,7 @@
 #include <asm/prom.h>
 #include <asm/machdep.h>
 #include <asm/smp.h>
+#include <asm/pmc.h>
 
 #include "cacheinfo.h"
 
@@ -123,6 +124,8 @@ static DEFINE_PER_CPU(char, pmcs_enabled);
 
 void ppc_enable_pmcs(void)
 {
+       ppc_set_pmu_inuse(1);
+
        /* Only need to enable them once */
        if (__get_cpu_var(pmcs_enabled))
                return;
index eae4511ceeac272947f3e164befc73a3145481dd..a180b4f9a4f64c6d4d5b79bb9384285d4802e462 100644 (file)
@@ -479,7 +479,8 @@ static int __init iSeries_tb_recal(void)
                unsigned long tb_ticks = tb - iSeries_recal_tb;
                unsigned long titan_usec = (titan - iSeries_recal_titan) >> 12;
                unsigned long new_tb_ticks_per_sec   = (tb_ticks * USEC_PER_SEC)/titan_usec;
-               unsigned long new_tb_ticks_per_jiffy = (new_tb_ticks_per_sec+(HZ/2))/HZ;
+               unsigned long new_tb_ticks_per_jiffy =
+                       DIV_ROUND_CLOSEST(new_tb_ticks_per_sec, HZ);
                long tick_diff = new_tb_ticks_per_jiffy - tb_ticks_per_jiffy;
                char sign = '+';                
                /* make sure tb_ticks_per_sec and tb_ticks_per_jiffy are consistent */
@@ -726,6 +727,18 @@ static int __init get_freq(char *name, int cells, unsigned long *val)
        return found;
 }
 
+/* should become __cpuinit when secondary_cpu_time_init also is */
+void start_cpu_decrementer(void)
+{
+#if defined(CONFIG_BOOKE) || defined(CONFIG_40x)
+       /* Clear any pending timer interrupts */
+       mtspr(SPRN_TSR, TSR_ENW | TSR_WIS | TSR_DIS | TSR_FIS);
+
+       /* Enable decrementer interrupt */
+       mtspr(SPRN_TCR, TCR_DIE);
+#endif /* defined(CONFIG_BOOKE) || defined(CONFIG_40x) */
+}
+
 void __init generic_calibrate_decr(void)
 {
        ppc_tb_freq = DEFAULT_TB_FREQ;          /* hardcoded default */
@@ -745,14 +758,6 @@ void __init generic_calibrate_decr(void)
                printk(KERN_ERR "WARNING: Estimating processor frequency "
                                "(not found)\n");
        }
-
-#if defined(CONFIG_BOOKE) || defined(CONFIG_40x)
-       /* Clear any pending timer interrupts */
-       mtspr(SPRN_TSR, TSR_ENW | TSR_WIS | TSR_DIS | TSR_FIS);
-
-       /* Enable decrementer interrupt */
-       mtspr(SPRN_TCR, TCR_DIE);
-#endif
 }
 
 int update_persistent_clock(struct timespec now)
@@ -913,6 +918,11 @@ static void __init init_decrementer_clockevent(void)
 
 void secondary_cpu_time_init(void)
 {
+       /* Start the decrementer on CPUs that have manual control
+        * such as BookE
+        */
+       start_cpu_decrementer();
+
        /* FIME: Should make unrelatred change to move snapshot_timebase
         * call here ! */
        register_decrementer_clockevent(smp_processor_id());
@@ -1016,6 +1026,11 @@ void __init time_init(void)
 
        write_sequnlock_irqrestore(&xtime_lock, flags);
 
+       /* Start the decrementer on CPUs that have manual control
+        * such as BookE
+        */
+       start_cpu_decrementer();
+
        /* Register the clocksource, if we're not running on iSeries */
        if (!firmware_has_feature(FW_FEATURE_ISERIES))
                clocksource_init();
index ad06d5c75b15ddb4ac6c92e00cfde45f3174d452..a0abce251d0a0ae1021e1012fdc9b37fff31c7c6 100644 (file)
@@ -203,7 +203,12 @@ int arch_setup_additional_pages(struct linux_binprm *bprm, int uses_interp)
        } else {
                vdso_pagelist = vdso64_pagelist;
                vdso_pages = vdso64_pages;
-               vdso_base = VDSO64_MBASE;
+               /*
+                * On 64bit we don't have a preferred map address. This
+                * allows get_unmapped_area to find an area near other mmaps
+                * and most likely share a SLB entry.
+                */
+               vdso_base = 0;
        }
 #else
        vdso_pagelist = vdso32_pagelist;
index c3d57bd01a88ab2157b5ae92ca9fd34561d9008f..b54b81688132bab49851646f7b3697ee65bae5c0 100644 (file)
@@ -12,6 +12,7 @@ endif
 targets := $(obj-vdso32) vdso32.so vdso32.so.dbg
 obj-vdso32 := $(addprefix $(obj)/, $(obj-vdso32))
 
+GCOV_PROFILE := n
 
 EXTRA_CFLAGS := -shared -fno-common -fno-builtin
 EXTRA_CFLAGS += -nostdlib -Wl,-soname=linux-vdso32.so.1 \
index fa7f1b8f3e5024c2ed705837d728694ff56f15b7..dd0c8e9367751eb2cd3bc55795a819dbde4bc085 100644 (file)
@@ -7,6 +7,8 @@ obj-vdso64 = sigtramp.o gettimeofday.o datapage.o cacheflush.o note.o
 targets := $(obj-vdso64) vdso64.so vdso64.so.dbg
 obj-vdso64 := $(addprefix $(obj)/, $(obj-vdso64))
 
+GCOV_PROFILE := n
+
 EXTRA_CFLAGS := -shared -fno-common -fno-builtin
 EXTRA_CFLAGS += -nostdlib -Wl,-soname=linux-vdso64.so.1 \
                $(call ld-option, -Wl$(comma)--hash-style=sysv)
index ea4d64644d029a283fe17e379d03be319d845b2e..67b6916f0e942283553a2a5d3b5b82b6899fff19 100644 (file)
@@ -65,7 +65,7 @@ _GLOBAL(load_up_altivec)
 1:
        /* enable use of VMX after return */
 #ifdef CONFIG_PPC32
-       mfspr   r5,SPRN_SPRG3           /* current task's THREAD (phys) */
+       mfspr   r5,SPRN_SPRG_THREAD             /* current task's THREAD (phys) */
        oris    r9,r9,MSR_VEC@h
 #else
        ld      r4,PACACURRENT(r13)
index 819e59f6f7c7c31b680080bdcffe1171d4026058..bc7b41edbdfce10671e942cc0857fdf9d022ea5e 100644 (file)
@@ -601,7 +601,7 @@ static void vio_dma_iommu_unmap_sg(struct device *dev,
        vio_cmo_dealloc(viodev, alloc_size);
 }
 
-struct dma_mapping_ops vio_dma_mapping_ops = {
+struct dma_map_ops vio_dma_mapping_ops = {
        .alloc_coherent = vio_dma_iommu_alloc_coherent,
        .free_coherent  = vio_dma_iommu_free_coherent,
        .map_sg         = vio_dma_iommu_map_sg,
index 8ef8a14abc95b5ccf9bc2ba93e84ba9c881a6729..58da4070723df37108247c2a01838ddbd4295610 100644 (file)
@@ -37,12 +37,6 @@ jiffies = jiffies_64 + 4;
 #endif
 SECTIONS
 {
-       /* Sections to be discarded. */
-       /DISCARD/ : {
-       *(.exitcall.exit)
-       EXIT_DATA
-       }
-
        . = KERNELBASE;
 
 /*
@@ -245,10 +239,6 @@ SECTIONS
        }
 #endif
 
-       . = ALIGN(PAGE_SIZE);
-       _edata  =  .;
-       PROVIDE32 (edata = .);
-
        /* The initial task and kernel stack */
 #ifdef CONFIG_PPC32
        . = ALIGN(8192);
@@ -282,6 +272,10 @@ SECTIONS
                __nosave_end = .;
        }
 
+       . = ALIGN(PAGE_SIZE);
+       _edata  =  .;
+       PROVIDE32 (edata = .);
+
 /*
  * And finally the bss
  */
@@ -298,4 +292,7 @@ SECTIONS
        . = ALIGN(PAGE_SIZE);
        _end = . ;
        PROVIDE32 (end = .);
+
+       /* Sections to be discarded. */
+       DISCARDS
 }
index d0c6f841bbd10ddb4b73ef5c7609ee0726004e18..380a78cf484dc2bdce54ef4b23b26eeb60d2e264 100644 (file)
@@ -56,8 +56,8 @@
 .macro KVM_HANDLER ivor_nr
 _GLOBAL(kvmppc_handler_\ivor_nr)
        /* Get pointer to vcpu and record exit number. */
-       mtspr   SPRN_SPRG0, r4
-       mfspr   r4, SPRN_SPRG1
+       mtspr   SPRN_SPRG_WSCRATCH0, r4
+       mfspr   r4, SPRN_SPRG_RVCPU
        stw     r5, VCPU_GPR(r5)(r4)
        stw     r6, VCPU_GPR(r6)(r4)
        mfctr   r5
@@ -95,7 +95,7 @@ _GLOBAL(kvmppc_handler_len)
 
 
 /* Registers:
- *  SPRG0: guest r4
+ *  SPRG_SCRATCH0: guest r4
  *  r4: vcpu pointer
  *  r5: KVM exit number
  */
@@ -181,7 +181,7 @@ _GLOBAL(kvmppc_resume_host)
        stw     r3, VCPU_LR(r4)
        mfxer   r3
        stw     r3, VCPU_XER(r4)
-       mfspr   r3, SPRN_SPRG0
+       mfspr   r3, SPRN_SPRG_RSCRATCH0
        stw     r3, VCPU_GPR(r4)(r4)
        mfspr   r3, SPRN_SRR0
        stw     r3, VCPU_PC(r4)
@@ -374,7 +374,7 @@ lightweight_exit:
        mtspr   SPRN_IVPR, r8
 
        /* Save vcpu pointer for the exception handlers. */
-       mtspr   SPRN_SPRG1, r4
+       mtspr   SPRN_SPRG_WVCPU, r4
 
        /* Can't switch the stack pointer until after IVPR is switched,
         * because host interrupt handlers would get confused. */
@@ -384,13 +384,13 @@ lightweight_exit:
        /* Host interrupt handlers may have clobbered these guest-readable
         * SPRGs, so we need to reload them here with the guest's values. */
        lwz     r3, VCPU_SPRG4(r4)
-       mtspr   SPRN_SPRG4, r3
+       mtspr   SPRN_SPRG4W, r3
        lwz     r3, VCPU_SPRG5(r4)
-       mtspr   SPRN_SPRG5, r3
+       mtspr   SPRN_SPRG5W, r3
        lwz     r3, VCPU_SPRG6(r4)
-       mtspr   SPRN_SPRG6, r3
+       mtspr   SPRN_SPRG6W, r3
        lwz     r3, VCPU_SPRG7(r4)
-       mtspr   SPRN_SPRG7, r3
+       mtspr   SPRN_SPRG7W, r3
 
 #ifdef CONFIG_KVM_EXIT_TIMING
        /* save enter time */
index 29954dc28942ff8408c940402f9cac7a72b7ebd3..f5e7b9ce63ddaa46f9ee10da0636b6d070b95431 100644 (file)
@@ -105,7 +105,7 @@ unsigned long __init mmu_mapin_ram(void)
 
        while (s >= LARGE_PAGE_SIZE_16M) {
                pmd_t *pmdp;
-               unsigned long val = p | _PMD_SIZE_16M | _PAGE_HWEXEC | _PAGE_HWWRITE;
+               unsigned long val = p | _PMD_SIZE_16M | _PAGE_EXEC | _PAGE_HWWRITE;
 
                pmdp = pmd_offset(pud_offset(pgd_offset_k(v), v), v);
                pmd_val(*pmdp++) = val;
@@ -120,7 +120,7 @@ unsigned long __init mmu_mapin_ram(void)
 
        while (s >= LARGE_PAGE_SIZE_4M) {
                pmd_t *pmdp;
-               unsigned long val = p | _PMD_SIZE_4M | _PAGE_HWEXEC | _PAGE_HWWRITE;
+               unsigned long val = p | _PMD_SIZE_4M | _PAGE_EXEC | _PAGE_HWWRITE;
 
                pmdp = pmd_offset(pud_offset(pgd_offset_k(v), v), v);
                pmd_val(*pmdp) = val;
index 3e68363405b79facfba31f3740afef46669fe039..6fb8fc8d2feafb9993ccc3f7457d0ff76e1f2587 100644 (file)
@@ -13,6 +13,7 @@ obj-y                         := fault.o mem.o pgtable.o gup.o \
                                   pgtable_$(CONFIG_WORD_SIZE).o
 obj-$(CONFIG_PPC_MMU_NOHASH)   += mmu_context_nohash.o tlb_nohash.o \
                                   tlb_nohash_low.o
+obj-$(CONFIG_PPC_BOOK3E)       += tlb_low_$(CONFIG_WORD_SIZE)e.o
 obj-$(CONFIG_PPC64)            += mmap_64.o
 hash64-$(CONFIG_PPC_NATIVE)    := hash_native_64.o
 obj-$(CONFIG_PPC_STD_MMU_64)   += hash_utils_64.o \
index bb3d65998e6b514028d8c3af7b6c9c036047ba0d..dc93e95b256eae04e248900e82858d94c8fe822a 100644 (file)
@@ -161,7 +161,7 @@ unsigned long __init mmu_mapin_ram(void)
        unsigned long virt = PAGE_OFFSET;
        phys_addr_t phys = memstart_addr;
 
-       while (cam[tlbcam_index] && tlbcam_index < ARRAY_SIZE(cam)) {
+       while (tlbcam_index < ARRAY_SIZE(cam) && cam[tlbcam_index]) {
                settlbcam(tlbcam_index, virt, phys, cam[tlbcam_index], PAGE_KERNEL_X, 0);
                virt += cam[tlbcam_index];
                phys += cam[tlbcam_index];
index 14af8cedab704031502b59163cf8b2a354c9d5bb..b13d58932bf6dd51118d23b77f97935b92fab5e9 100644 (file)
@@ -40,7 +40,7 @@ mmu_hash_lock:
  * The address is in r4, and r3 contains an access flag:
  * _PAGE_RW (0x400) if a write.
  * r9 contains the SRR1 value, from which we use the MSR_PR bit.
- * SPRG3 contains the physical address of the current task's thread.
+ * SPRG_THREAD contains the physical address of the current task's thread.
  *
  * Returns to the caller if the access is illegal or there is no
  * mapping for the address.  Otherwise it places an appropriate PTE
@@ -68,7 +68,7 @@ _GLOBAL(hash_page)
        /* Get PTE (linux-style) and check access */
        lis     r0,KERNELBASE@h         /* check if kernel address */
        cmplw   0,r4,r0
-       mfspr   r8,SPRN_SPRG3           /* current task's THREAD (phys) */
+       mfspr   r8,SPRN_SPRG_THREAD     /* current task's THREAD (phys) */
        ori     r3,r3,_PAGE_USER|_PAGE_PRESENT /* test low addresses as user */
        lwz     r5,PGDIR(r8)            /* virt page-table root */
        blt+    112f                    /* assume user more likely */
index c46ef2ffa3d95673febbbe9be0d167a5879ec04f..90df6ffe3a43140fcbfcb5ceaa312fdb7c642319 100644 (file)
@@ -57,8 +57,10 @@ unsigned int mmu_huge_psizes[MMU_PAGE_COUNT] = { }; /* initialize all to 0 */
 #define HUGEPTE_CACHE_NAME(psize)      (huge_pgtable_cache_name[psize])
 
 static const char *huge_pgtable_cache_name[MMU_PAGE_COUNT] = {
-       "unused_4K", "hugepte_cache_64K", "unused_64K_AP",
-       "hugepte_cache_1M", "hugepte_cache_16M", "hugepte_cache_16G"
+       [MMU_PAGE_64K]  = "hugepte_cache_64K",
+       [MMU_PAGE_1M]   = "hugepte_cache_1M",
+       [MMU_PAGE_16M]  = "hugepte_cache_16M",
+       [MMU_PAGE_16G]  = "hugepte_cache_16G",
 };
 
 /* Flag to mark huge PD pointers.  This means pmd_bad() and pud_bad()
@@ -700,6 +702,8 @@ static void __init set_huge_psize(int psize)
                if (mmu_huge_psizes[psize] ||
                   mmu_psize_defs[psize].shift == PAGE_SHIFT)
                        return;
+               if (WARN_ON(HUGEPTE_CACHE_NAME(psize) == NULL))
+                       return;
                hugetlb_add_hstate(mmu_psize_defs[psize].shift - PAGE_SHIFT);
 
                switch (mmu_psize_defs[psize].shift) {
index 3de6a0d9382472dc7a81f60b569eb02de298c724..3ef5084b90ca0357b002a9eaf8f004b10a223db1 100644 (file)
@@ -54,8 +54,6 @@
 #endif
 #define MAX_LOW_MEM    CONFIG_LOWMEM_SIZE
 
-DEFINE_PER_CPU(struct mmu_gather, mmu_gathers);
-
 phys_addr_t total_memory;
 phys_addr_t total_lowmem;
 
index 68a821add28df21c09c2716cc2cb8ef5c77dc796..31582329cd6778e0f3dc0b058635ab4015c8d6ad 100644 (file)
@@ -205,6 +205,47 @@ static int __meminit vmemmap_populated(unsigned long start, int page_size)
        return 0;
 }
 
+/* On hash-based CPUs, the vmemmap is bolted in the hash table.
+ *
+ * On Book3E CPUs, the vmemmap is currently mapped in the top half of
+ * the vmalloc space using normal page tables, though the size of
+ * pages encoded in the PTEs can be different
+ */
+
+#ifdef CONFIG_PPC_BOOK3E
+static void __meminit vmemmap_create_mapping(unsigned long start,
+                                            unsigned long page_size,
+                                            unsigned long phys)
+{
+       /* Create a PTE encoding without page size */
+       unsigned long i, flags = _PAGE_PRESENT | _PAGE_ACCESSED |
+               _PAGE_KERNEL_RW;
+
+       /* PTEs only contain page size encodings up to 32M */
+       BUG_ON(mmu_psize_defs[mmu_vmemmap_psize].enc > 0xf);
+
+       /* Encode the size in the PTE */
+       flags |= mmu_psize_defs[mmu_vmemmap_psize].enc << 8;
+
+       /* For each PTE for that area, map things. Note that we don't
+        * increment phys because all PTEs are of the large size and
+        * thus must have the low bits clear
+        */
+       for (i = 0; i < page_size; i += PAGE_SIZE)
+               BUG_ON(map_kernel_page(start + i, phys, flags));
+}
+#else /* CONFIG_PPC_BOOK3E */
+static void __meminit vmemmap_create_mapping(unsigned long start,
+                                            unsigned long page_size,
+                                            unsigned long phys)
+{
+       int  mapped = htab_bolt_mapping(start, start + page_size, phys,
+                                       PAGE_KERNEL, mmu_vmemmap_psize,
+                                       mmu_kernel_ssize);
+       BUG_ON(mapped < 0);
+}
+#endif /* CONFIG_PPC_BOOK3E */
+
 int __meminit vmemmap_populate(struct page *start_page,
                               unsigned long nr_pages, int node)
 {
@@ -215,8 +256,11 @@ int __meminit vmemmap_populate(struct page *start_page,
        /* Align to the page size of the linear mapping. */
        start = _ALIGN_DOWN(start, page_size);
 
+       pr_debug("vmemmap_populate page %p, %ld pages, node %d\n",
+                start_page, nr_pages, node);
+       pr_debug(" -> map %lx..%lx\n", start, end);
+
        for (; start < end; start += page_size) {
-               int mapped;
                void *p;
 
                if (vmemmap_populated(start, page_size))
@@ -226,13 +270,10 @@ int __meminit vmemmap_populate(struct page *start_page,
                if (!p)
                        return -ENOMEM;
 
-               pr_debug("vmemmap %08lx allocated at %p, physical %08lx.\n",
-                       start, p, __pa(p));
+               pr_debug("      * %016lx..%016lx allocated at %p\n",
+                        start, start + page_size, p);
 
-               mapped = htab_bolt_mapping(start, start + page_size, __pa(p),
-                                          pgprot_val(PAGE_KERNEL),
-                                          mmu_vmemmap_psize, mmu_kernel_ssize);
-               BUG_ON(mapped < 0);
+               vmemmap_create_mapping(start, page_size, __pa(p));
        }
 
        return 0;
index b1a727def15b4a49b01f850ef76d8388d7ce1853..c2f93dc470e6c9bdc692cf43fd91ea9b6faef00a 100644 (file)
  *     also clear mm->cpu_vm_mask bits when processes are migrated
  */
 
-#undef DEBUG
-#define DEBUG_STEAL_ONLY
-#undef DEBUG_MAP_CONSISTENCY
-/*#define DEBUG_CLAMP_LAST_CONTEXT   15 */
+#define DEBUG_MAP_CONSISTENCY
+#define DEBUG_CLAMP_LAST_CONTEXT   31
+//#define DEBUG_HARDER
+
+/* We don't use DEBUG because it tends to be compiled in always nowadays
+ * and this would generate way too much output
+ */
+#ifdef DEBUG_HARDER
+#define pr_hard(args...)       printk(KERN_DEBUG args)
+#define pr_hardcont(args...)   printk(KERN_CONT args)
+#else
+#define pr_hard(args...)       do { } while(0)
+#define pr_hardcont(args...)   do { } while(0)
+#endif
 
 #include <linux/kernel.h>
 #include <linux/mm.h>
@@ -71,7 +81,7 @@ static DEFINE_SPINLOCK(context_lock);
 static unsigned int steal_context_smp(unsigned int id)
 {
        struct mm_struct *mm;
-       unsigned int cpu, max;
+       unsigned int cpu, max, i;
 
        max = last_context - first_context;
 
@@ -89,15 +99,22 @@ static unsigned int steal_context_smp(unsigned int id)
                                id = first_context;
                        continue;
                }
-               pr_devel("[%d] steal context %d from mm @%p\n",
-                        smp_processor_id(), id, mm);
+               pr_hardcont(" | steal %d from 0x%p", id, mm);
 
                /* Mark this mm has having no context anymore */
                mm->context.id = MMU_NO_CONTEXT;
 
-               /* Mark it stale on all CPUs that used this mm */
-               for_each_cpu(cpu, mm_cpumask(mm))
-                       __set_bit(id, stale_map[cpu]);
+               /* Mark it stale on all CPUs that used this mm. For threaded
+                * implementations, we set it on all threads on each core
+                * represented in the mask. A future implementation will use
+                * a core map instead but this will do for now.
+                */
+               for_each_cpu(cpu, mm_cpumask(mm)) {
+                       for (i = cpu_first_thread_in_core(cpu);
+                            i <= cpu_last_thread_in_core(cpu); i++)
+                               __set_bit(id, stale_map[i]);
+                       cpu = i - 1;
+               }
                return id;
        }
 
@@ -126,7 +143,7 @@ static unsigned int steal_context_up(unsigned int id)
        /* Pick up the victim mm */
        mm = context_mm[id];
 
-       pr_devel("[%d] steal context %d from mm @%p\n", cpu, id, mm);
+       pr_hardcont(" | steal %d from 0x%p", id, mm);
 
        /* Flush the TLB for that context */
        local_flush_tlb_mm(mm);
@@ -173,25 +190,20 @@ static void context_check_map(void) { }
 
 void switch_mmu_context(struct mm_struct *prev, struct mm_struct *next)
 {
-       unsigned int id, cpu = smp_processor_id();
+       unsigned int i, id, cpu = smp_processor_id();
        unsigned long *map;
 
        /* No lockless fast path .. yet */
        spin_lock(&context_lock);
 
-#ifndef DEBUG_STEAL_ONLY
-       pr_devel("[%d] activating context for mm @%p, active=%d, id=%d\n",
-                cpu, next, next->context.active, next->context.id);
-#endif
+       pr_hard("[%d] activating context for mm @%p, active=%d, id=%d",
+               cpu, next, next->context.active, next->context.id);
 
 #ifdef CONFIG_SMP
        /* Mark us active and the previous one not anymore */
        next->context.active++;
        if (prev) {
-#ifndef DEBUG_STEAL_ONLY
-               pr_devel(" old context %p active was: %d\n",
-                        prev, prev->context.active);
-#endif
+               pr_hardcont(" (old=0x%p a=%d)", prev, prev->context.active);
                WARN_ON(prev->context.active < 1);
                prev->context.active--;
        }
@@ -201,8 +213,14 @@ void switch_mmu_context(struct mm_struct *prev, struct mm_struct *next)
 
        /* If we already have a valid assigned context, skip all that */
        id = next->context.id;
-       if (likely(id != MMU_NO_CONTEXT))
+       if (likely(id != MMU_NO_CONTEXT)) {
+#ifdef DEBUG_MAP_CONSISTENCY
+               if (context_mm[id] != next)
+                       pr_err("MMU: mm 0x%p has id %d but context_mm[%d] says 0x%p\n",
+                              next, id, id, context_mm[id]);
+#endif
                goto ctxt_ok;
+       }
 
        /* We really don't have a context, let's try to acquire one */
        id = next_context;
@@ -235,11 +253,7 @@ void switch_mmu_context(struct mm_struct *prev, struct mm_struct *next)
        next_context = id + 1;
        context_mm[id] = next;
        next->context.id = id;
-
-#ifndef DEBUG_STEAL_ONLY
-       pr_devel("[%d] picked up new id %d, nrf is now %d\n",
-                cpu, id, nr_free_contexts);
-#endif
+       pr_hardcont(" | new id=%d,nrf=%d", id, nr_free_contexts);
 
        context_check_map();
  ctxt_ok:
@@ -248,15 +262,21 @@ void switch_mmu_context(struct mm_struct *prev, struct mm_struct *next)
         * local TLB for it and unmark it before we use it
         */
        if (test_bit(id, stale_map[cpu])) {
-               pr_devel("[%d] flushing stale context %d for mm @%p !\n",
-                        cpu, id, next);
+               pr_hardcont(" | stale flush %d [%d..%d]",
+                           id, cpu_first_thread_in_core(cpu),
+                           cpu_last_thread_in_core(cpu));
+
                local_flush_tlb_mm(next);
 
                /* XXX This clear should ultimately be part of local_flush_tlb_mm */
-               __clear_bit(id, stale_map[cpu]);
+               for (i = cpu_first_thread_in_core(cpu);
+                    i <= cpu_last_thread_in_core(cpu); i++) {
+                       __clear_bit(id, stale_map[i]);
+               }
        }
 
        /* Flick the MMU and release lock */
+       pr_hardcont(" -> %d\n", id);
        set_context(id, next->pgd);
        spin_unlock(&context_lock);
 }
@@ -266,6 +286,8 @@ void switch_mmu_context(struct mm_struct *prev, struct mm_struct *next)
  */
 int init_new_context(struct task_struct *t, struct mm_struct *mm)
 {
+       pr_hard("initing context for mm @%p\n", mm);
+
        mm->context.id = MMU_NO_CONTEXT;
        mm->context.active = 0;
 
@@ -305,7 +327,9 @@ static int __cpuinit mmu_context_cpu_notify(struct notifier_block *self,
                                            unsigned long action, void *hcpu)
 {
        unsigned int cpu = (unsigned int)(long)hcpu;
-
+#ifdef CONFIG_HOTPLUG_CPU
+       struct task_struct *p;
+#endif
        /* We don't touch CPU 0 map, it's allocated at aboot and kept
         * around forever
         */
@@ -324,8 +348,16 @@ static int __cpuinit mmu_context_cpu_notify(struct notifier_block *self,
                pr_devel("MMU: Freeing stale context map for CPU %d\n", cpu);
                kfree(stale_map[cpu]);
                stale_map[cpu] = NULL;
-               break;
-#endif
+
+               /* We also clear the cpu_vm_mask bits of CPUs going away */
+               read_lock(&tasklist_lock);
+               for_each_process(p) {
+                       if (p->mm)
+                               cpu_mask_clear_cpu(cpu, mm_cpumask(p->mm));
+               }
+               read_unlock(&tasklist_lock);
+       break;
+#endif /* CONFIG_HOTPLUG_CPU */
        }
        return NOTIFY_OK;
 }
index d1f9c62dc177b527179a0db0c2b4ad7583fc85d7..d2e5321d5ea6aba3a4d5827ca6f7fc2d7fe61c6a 100644 (file)
@@ -36,21 +36,37 @@ static inline void _tlbil_pid(unsigned int pid)
 {
        asm volatile ("sync; tlbia; isync" : : : "memory");
 }
+#define _tlbil_pid_noind(pid)  _tlbil_pid(pid)
+
 #else /* CONFIG_40x || CONFIG_8xx */
 extern void _tlbil_all(void);
 extern void _tlbil_pid(unsigned int pid);
+#ifdef CONFIG_PPC_BOOK3E
+extern void _tlbil_pid_noind(unsigned int pid);
+#else
+#define _tlbil_pid_noind(pid)  _tlbil_pid(pid)
+#endif
 #endif /* !(CONFIG_40x || CONFIG_8xx) */
 
 /*
  * On 8xx, we directly inline tlbie, on others, it's extern
  */
 #ifdef CONFIG_8xx
-static inline void _tlbil_va(unsigned long address, unsigned int pid)
+static inline void _tlbil_va(unsigned long address, unsigned int pid,
+                            unsigned int tsize, unsigned int ind)
 {
        asm volatile ("tlbie %0; sync" : : "r" (address) : "memory");
 }
-#else /* CONFIG_8xx */
-extern void _tlbil_va(unsigned long address, unsigned int pid);
+#elif defined(CONFIG_PPC_BOOK3E)
+extern void _tlbil_va(unsigned long address, unsigned int pid,
+                     unsigned int tsize, unsigned int ind);
+#else
+extern void __tlbil_va(unsigned long address, unsigned int pid);
+static inline void _tlbil_va(unsigned long address, unsigned int pid,
+                            unsigned int tsize, unsigned int ind)
+{
+       __tlbil_va(address, pid);
+}
 #endif /* CONIFG_8xx */
 
 /*
@@ -58,10 +74,16 @@ extern void _tlbil_va(unsigned long address, unsigned int pid);
  * implementation. When that becomes the case, this will be
  * an extern.
  */
-static inline void _tlbivax_bcast(unsigned long address, unsigned int pid)
+#ifdef CONFIG_PPC_BOOK3E
+extern void _tlbivax_bcast(unsigned long address, unsigned int pid,
+                          unsigned int tsize, unsigned int ind);
+#else
+static inline void _tlbivax_bcast(unsigned long address, unsigned int pid,
+                                  unsigned int tsize, unsigned int ind)
 {
        BUG();
 }
+#endif
 
 #else /* CONFIG_PPC_MMU_NOHASH */
 
@@ -99,7 +121,12 @@ extern unsigned int rtas_data, rtas_size;
 struct hash_pte;
 extern struct hash_pte *Hash, *Hash_end;
 extern unsigned long Hash_size, Hash_mask;
-#endif
+
+#endif /* CONFIG_PPC32 */
+
+#ifdef CONFIG_PPC64
+extern int map_kernel_page(unsigned long ea, unsigned long pa, int flags);
+#endif /* CONFIG_PPC64 */
 
 extern unsigned long ioremap_bot;
 extern unsigned long __max_low_memory;
index 627767d6169bd4e4300528f4c37907693beea6a7..83f1551ec2c9182d9299b0504fcdc2138ea3c917 100644 (file)
 #include <asm/tlbflush.h>
 #include <asm/tlb.h>
 
+DEFINE_PER_CPU(struct mmu_gather, mmu_gathers);
+
+#ifdef CONFIG_SMP
+
+/*
+ * Handle batching of page table freeing on SMP. Page tables are
+ * queued up and send to be freed later by RCU in order to avoid
+ * freeing a page table page that is being walked without locks
+ */
+
 static DEFINE_PER_CPU(struct pte_freelist_batch *, pte_freelist_cur);
 static unsigned long pte_freelist_forced_free;
 
@@ -116,27 +126,7 @@ void pte_free_finish(void)
        *batchp = NULL;
 }
 
-/*
- * Handle i/d cache flushing, called from set_pte_at() or ptep_set_access_flags()
- */
-static pte_t do_dcache_icache_coherency(pte_t pte)
-{
-       unsigned long pfn = pte_pfn(pte);
-       struct page *page;
-
-       if (unlikely(!pfn_valid(pfn)))
-               return pte;
-       page = pfn_to_page(pfn);
-
-       if (!PageReserved(page) && !test_bit(PG_arch_1, &page->flags)) {
-               pr_devel("do_dcache_icache_coherency... flushing\n");
-               flush_dcache_icache_page(page);
-               set_bit(PG_arch_1, &page->flags);
-       }
-       else
-               pr_devel("do_dcache_icache_coherency... already clean\n");
-       return __pte(pte_val(pte) | _PAGE_HWEXEC);
-}
+#endif /* CONFIG_SMP */
 
 static inline int is_exec_fault(void)
 {
@@ -145,49 +135,139 @@ static inline int is_exec_fault(void)
 
 /* We only try to do i/d cache coherency on stuff that looks like
  * reasonably "normal" PTEs. We currently require a PTE to be present
- * and we avoid _PAGE_SPECIAL and _PAGE_NO_CACHE
+ * and we avoid _PAGE_SPECIAL and _PAGE_NO_CACHE. We also only do that
+ * on userspace PTEs
  */
 static inline int pte_looks_normal(pte_t pte)
 {
        return (pte_val(pte) &
-               (_PAGE_PRESENT | _PAGE_SPECIAL | _PAGE_NO_CACHE)) ==
-               (_PAGE_PRESENT);
+           (_PAGE_PRESENT | _PAGE_SPECIAL | _PAGE_NO_CACHE | _PAGE_USER)) ==
+           (_PAGE_PRESENT | _PAGE_USER);
 }
 
-#if defined(CONFIG_PPC_STD_MMU)
+struct page * maybe_pte_to_page(pte_t pte)
+{
+       unsigned long pfn = pte_pfn(pte);
+       struct page *page;
+
+       if (unlikely(!pfn_valid(pfn)))
+               return NULL;
+       page = pfn_to_page(pfn);
+       if (PageReserved(page))
+               return NULL;
+       return page;
+}
+
+#if defined(CONFIG_PPC_STD_MMU) || _PAGE_EXEC == 0
+
 /* Server-style MMU handles coherency when hashing if HW exec permission
- * is supposed per page (currently 64-bit only). Else, we always flush
- * valid PTEs in set_pte.
+ * is supposed per page (currently 64-bit only). If not, then, we always
+ * flush the cache for valid PTEs in set_pte. Embedded CPU without HW exec
+ * support falls into the same category.
  */
-static inline int pte_need_exec_flush(pte_t pte, int set_pte)
+
+static pte_t set_pte_filter(pte_t pte)
 {
-       return set_pte && pte_looks_normal(pte) &&
-               !(cpu_has_feature(CPU_FTR_COHERENT_ICACHE) ||
-                 cpu_has_feature(CPU_FTR_NOEXECUTE));
+       pte = __pte(pte_val(pte) & ~_PAGE_HPTEFLAGS);
+       if (pte_looks_normal(pte) && !(cpu_has_feature(CPU_FTR_COHERENT_ICACHE) ||
+                                      cpu_has_feature(CPU_FTR_NOEXECUTE))) {
+               struct page *pg = maybe_pte_to_page(pte);
+               if (!pg)
+                       return pte;
+               if (!test_bit(PG_arch_1, &pg->flags)) {
+                       flush_dcache_icache_page(pg);
+                       set_bit(PG_arch_1, &pg->flags);
+               }
+       }
+       return pte;
 }
-#elif _PAGE_HWEXEC == 0
-/* Embedded type MMU without HW exec support (8xx only so far), we flush
- * the cache for any present PTE
- */
-static inline int pte_need_exec_flush(pte_t pte, int set_pte)
+
+static pte_t set_access_flags_filter(pte_t pte, struct vm_area_struct *vma,
+                                    int dirty)
 {
-       return set_pte && pte_looks_normal(pte);
+       return pte;
 }
-#else
-/* Other embedded CPUs with HW exec support per-page, we flush on exec
- * fault if HWEXEC is not set
+
+#else /* defined(CONFIG_PPC_STD_MMU) || _PAGE_EXEC == 0 */
+
+/* Embedded type MMU with HW exec support. This is a bit more complicated
+ * as we don't have two bits to spare for _PAGE_EXEC and _PAGE_HWEXEC so
+ * instead we "filter out" the exec permission for non clean pages.
  */
-static inline int pte_need_exec_flush(pte_t pte, int set_pte)
+static pte_t set_pte_filter(pte_t pte)
 {
-       return pte_looks_normal(pte) && is_exec_fault() &&
-               !(pte_val(pte) & _PAGE_HWEXEC);
+       struct page *pg;
+
+       /* No exec permission in the first place, move on */
+       if (!(pte_val(pte) & _PAGE_EXEC) || !pte_looks_normal(pte))
+               return pte;
+
+       /* If you set _PAGE_EXEC on weird pages you're on your own */
+       pg = maybe_pte_to_page(pte);
+       if (unlikely(!pg))
+               return pte;
+
+       /* If the page clean, we move on */
+       if (test_bit(PG_arch_1, &pg->flags))
+               return pte;
+
+       /* If it's an exec fault, we flush the cache and make it clean */
+       if (is_exec_fault()) {
+               flush_dcache_icache_page(pg);
+               set_bit(PG_arch_1, &pg->flags);
+               return pte;
+       }
+
+       /* Else, we filter out _PAGE_EXEC */
+       return __pte(pte_val(pte) & ~_PAGE_EXEC);
 }
-#endif
+
+static pte_t set_access_flags_filter(pte_t pte, struct vm_area_struct *vma,
+                                    int dirty)
+{
+       struct page *pg;
+
+       /* So here, we only care about exec faults, as we use them
+        * to recover lost _PAGE_EXEC and perform I$/D$ coherency
+        * if necessary. Also if _PAGE_EXEC is already set, same deal,
+        * we just bail out
+        */
+       if (dirty || (pte_val(pte) & _PAGE_EXEC) || !is_exec_fault())
+               return pte;
+
+#ifdef CONFIG_DEBUG_VM
+       /* So this is an exec fault, _PAGE_EXEC is not set. If it was
+        * an error we would have bailed out earlier in do_page_fault()
+        * but let's make sure of it
+        */
+       if (WARN_ON(!(vma->vm_flags & VM_EXEC)))
+               return pte;
+#endif /* CONFIG_DEBUG_VM */
+
+       /* If you set _PAGE_EXEC on weird pages you're on your own */
+       pg = maybe_pte_to_page(pte);
+       if (unlikely(!pg))
+               goto bail;
+
+       /* If the page is already clean, we move on */
+       if (test_bit(PG_arch_1, &pg->flags))
+               goto bail;
+
+       /* Clean the page and set PG_arch_1 */
+       flush_dcache_icache_page(pg);
+       set_bit(PG_arch_1, &pg->flags);
+
+ bail:
+       return __pte(pte_val(pte) | _PAGE_EXEC);
+}
+
+#endif /* !(defined(CONFIG_PPC_STD_MMU) || _PAGE_EXEC == 0) */
 
 /*
  * set_pte stores a linux PTE into the linux page table.
  */
-void set_pte_at(struct mm_struct *mm, unsigned long addr, pte_t *ptep, pte_t pte)
+void set_pte_at(struct mm_struct *mm, unsigned long addr, pte_t *ptep,
+               pte_t pte)
 {
 #ifdef CONFIG_DEBUG_VM
        WARN_ON(pte_present(*ptep));
@@ -196,9 +276,7 @@ void set_pte_at(struct mm_struct *mm, unsigned long addr, pte_t *ptep, pte_t pte
         * this context might not have been activated yet when this
         * is called.
         */
-       pte = __pte(pte_val(pte) & ~_PAGE_HPTEFLAGS);
-       if (pte_need_exec_flush(pte, 1))
-               pte = do_dcache_icache_coherency(pte);
+       pte = set_pte_filter(pte);
 
        /* Perform the setting of the PTE */
        __set_pte_at(mm, addr, ptep, pte, 0);
@@ -215,8 +293,7 @@ int ptep_set_access_flags(struct vm_area_struct *vma, unsigned long address,
                          pte_t *ptep, pte_t entry, int dirty)
 {
        int changed;
-       if (!dirty && pte_need_exec_flush(entry, 0))
-               entry = do_dcache_icache_coherency(entry);
+       entry = set_access_flags_filter(entry, vma, dirty);
        changed = !pte_same(*(ptep), entry);
        if (changed) {
                if (!(vma->vm_flags & VM_HUGETLB))
@@ -242,7 +319,7 @@ void assert_pte_locked(struct mm_struct *mm, unsigned long addr)
        BUG_ON(pud_none(*pud));
        pmd = pmd_offset(pud, addr);
        BUG_ON(!pmd_present(*pmd));
-       BUG_ON(!spin_is_locked(pte_lockptr(mm, pmd)));
+       assert_spin_locked(pte_lockptr(mm, pmd));
 }
 #endif /* CONFIG_DEBUG_VM */
 
index 5422169626ba8f7baa5b0f1a4930ee57a91e246f..cb96cb2e17cc0560e947550690013a342f63929c 100644 (file)
@@ -142,7 +142,7 @@ ioremap_flags(phys_addr_t addr, unsigned long size, unsigned long flags)
                flags |= _PAGE_DIRTY | _PAGE_HWWRITE;
 
        /* we don't want to let _PAGE_USER and _PAGE_EXEC leak out */
-       flags &= ~(_PAGE_USER | _PAGE_EXEC | _PAGE_HWEXEC);
+       flags &= ~(_PAGE_USER | _PAGE_EXEC);
 
        return __ioremap_caller(addr, size, flags, __builtin_return_address(0));
 }
index bfa7db6b2fd5446e193669a1afd02d09f7f9aab9..853d5565eed52b88deb8d37b2379d12fe8d6d6bb 100644 (file)
@@ -33,6 +33,8 @@
 #include <linux/stddef.h>
 #include <linux/vmalloc.h>
 #include <linux/init.h>
+#include <linux/bootmem.h>
+#include <linux/lmb.h>
 
 #include <asm/pgalloc.h>
 #include <asm/page.h>
 
 unsigned long ioremap_bot = IOREMAP_BASE;
 
+
+#ifdef CONFIG_PPC_MMU_NOHASH
+static void *early_alloc_pgtable(unsigned long size)
+{
+       void *pt;
+
+       if (init_bootmem_done)
+               pt = __alloc_bootmem(size, size, __pa(MAX_DMA_ADDRESS));
+       else
+               pt = __va(lmb_alloc_base(size, size,
+                                        __pa(MAX_DMA_ADDRESS)));
+       memset(pt, 0, size);
+
+       return pt;
+}
+#endif /* CONFIG_PPC_MMU_NOHASH */
+
 /*
- * map_io_page currently only called by __ioremap
- * map_io_page adds an entry to the ioremap page table
+ * map_kernel_page currently only called by __ioremap
+ * map_kernel_page adds an entry to the ioremap page table
  * and adds an entry to the HPT, possibly bolting it
  */
-static int map_io_page(unsigned long ea, unsigned long pa, int flags)
+int map_kernel_page(unsigned long ea, unsigned long pa, int flags)
 {
        pgd_t *pgdp;
        pud_t *pudp;
        pmd_t *pmdp;
        pte_t *ptep;
 
-       if (mem_init_done) {
+       if (slab_is_available()) {
                pgdp = pgd_offset_k(ea);
                pudp = pud_alloc(&init_mm, pgdp, ea);
                if (!pudp)
@@ -81,6 +100,35 @@ static int map_io_page(unsigned long ea, unsigned long pa, int flags)
                set_pte_at(&init_mm, ea, ptep, pfn_pte(pa >> PAGE_SHIFT,
                                                          __pgprot(flags)));
        } else {
+#ifdef CONFIG_PPC_MMU_NOHASH
+               /* Warning ! This will blow up if bootmem is not initialized
+                * which our ppc64 code is keen to do that, we'll need to
+                * fix it and/or be more careful
+                */
+               pgdp = pgd_offset_k(ea);
+#ifdef PUD_TABLE_SIZE
+               if (pgd_none(*pgdp)) {
+                       pudp = early_alloc_pgtable(PUD_TABLE_SIZE);
+                       BUG_ON(pudp == NULL);
+                       pgd_populate(&init_mm, pgdp, pudp);
+               }
+#endif /* PUD_TABLE_SIZE */
+               pudp = pud_offset(pgdp, ea);
+               if (pud_none(*pudp)) {
+                       pmdp = early_alloc_pgtable(PMD_TABLE_SIZE);
+                       BUG_ON(pmdp == NULL);
+                       pud_populate(&init_mm, pudp, pmdp);
+               }
+               pmdp = pmd_offset(pudp, ea);
+               if (!pmd_present(*pmdp)) {
+                       ptep = early_alloc_pgtable(PAGE_SIZE);
+                       BUG_ON(ptep == NULL);
+                       pmd_populate_kernel(&init_mm, pmdp, ptep);
+               }
+               ptep = pte_offset_kernel(pmdp, ea);
+               set_pte_at(&init_mm, ea, ptep, pfn_pte(pa >> PAGE_SHIFT,
+                                                         __pgprot(flags)));
+#else /* CONFIG_PPC_MMU_NOHASH */
                /*
                 * If the mm subsystem is not fully up, we cannot create a
                 * linux page table entry for this mapping.  Simply bolt an
@@ -93,6 +141,7 @@ static int map_io_page(unsigned long ea, unsigned long pa, int flags)
                               "memory at %016lx !\n", pa);
                        return -ENOMEM;
                }
+#endif /* !CONFIG_PPC_MMU_NOHASH */
        }
        return 0;
 }
@@ -124,7 +173,7 @@ void __iomem * __ioremap_at(phys_addr_t pa, void *ea, unsigned long size,
        WARN_ON(size & ~PAGE_MASK);
 
        for (i = 0; i < size; i += PAGE_SIZE)
-               if (map_io_page((unsigned long)ea+i, pa+i, flags))
+               if (map_kernel_page((unsigned long)ea+i, pa+i, flags))
                        return NULL;
 
        return (void __iomem *)ea;
index a685652effeb05cd303b75a7a2a07e796d1a9a89..1d98ecc8eecd2d4cabfe08f2d883d75432981684 100644 (file)
@@ -191,7 +191,7 @@ void switch_slb(struct task_struct *tsk, struct mm_struct *mm)
        unsigned long slbie_data = 0;
        unsigned long pc = KSTK_EIP(tsk);
        unsigned long stack = KSTK_ESP(tsk);
-       unsigned long unmapped_base;
+       unsigned long exec_base;
 
        /*
         * We need interrupts hard-disabled here, not just soft-disabled,
@@ -227,42 +227,44 @@ void switch_slb(struct task_struct *tsk, struct mm_struct *mm)
 
        /*
         * preload some userspace segments into the SLB.
+        * Almost all 32 and 64bit PowerPC executables are linked at
+        * 0x10000000 so it makes sense to preload this segment.
         */
-       if (test_tsk_thread_flag(tsk, TIF_32BIT))
-               unmapped_base = TASK_UNMAPPED_BASE_USER32;
-       else
-               unmapped_base = TASK_UNMAPPED_BASE_USER64;
+       exec_base = 0x10000000;
 
-       if (is_kernel_addr(pc))
-               return;
-       slb_allocate(pc);
-
-       if (esids_match(pc,stack))
+       if (is_kernel_addr(pc) || is_kernel_addr(stack) ||
+           is_kernel_addr(exec_base))
                return;
 
-       if (is_kernel_addr(stack))
-               return;
-       slb_allocate(stack);
+       slb_allocate(pc);
 
-       if (esids_match(pc,unmapped_base) || esids_match(stack,unmapped_base))
-               return;
+       if (!esids_match(pc, stack))
+               slb_allocate(stack);
 
-       if (is_kernel_addr(unmapped_base))
-               return;
-       slb_allocate(unmapped_base);
+       if (!esids_match(pc, exec_base) &&
+           !esids_match(stack, exec_base))
+               slb_allocate(exec_base);
 }
 
 static inline void patch_slb_encoding(unsigned int *insn_addr,
                                      unsigned int immed)
 {
-       /* Assume the instruction had a "0" immediate value, just
-        * "or" in the new value
-        */
-       *insn_addr |= immed;
+       *insn_addr = (*insn_addr & 0xffff0000) | immed;
        flush_icache_range((unsigned long)insn_addr, 4+
                           (unsigned long)insn_addr);
 }
 
+void slb_set_size(u16 size)
+{
+       extern unsigned int *slb_compare_rr_to_size;
+
+       if (mmu_slb_size == size)
+               return;
+
+       mmu_slb_size = size;
+       patch_slb_encoding(slb_compare_rr_to_size, mmu_slb_size);
+}
+
 void slb_initialize(void)
 {
        unsigned long linear_llp, vmalloc_llp, io_llp;
index ab5fb48b3e90ae07723ca9b3ead715d443c02fb2..687fddaa24c564fb19491b146525ba2ffc58ac67 100644 (file)
@@ -31,7 +31,7 @@ struct stab_entry {
 
 #define NR_STAB_CACHE_ENTRIES 8
 static DEFINE_PER_CPU(long, stab_cache_ptr);
-static DEFINE_PER_CPU(long, stab_cache[NR_STAB_CACHE_ENTRIES]);
+static DEFINE_PER_CPU(long [NR_STAB_CACHE_ENTRIES], stab_cache);
 
 /*
  * Create a segment table entry for the given esid/vsid pair.
index 65190587a365056cb35ce04aebc41d9dc1fb7cd1..8aaa8b7eb324f32920930d6c2a60aab4cb8e927a 100644 (file)
@@ -71,6 +71,9 @@ void tlb_flush(struct mmu_gather *tlb)
                 */
                _tlbia();
        }
+
+       /* Push out batch of freed page tables */
+       pte_free_finish();
 }
 
 /*
index 937eb90677d9ef658b4a2e7d9ebd982a9e0820f7..2b2f35f6985e561aaacf2ef515e654d0ba1985b4 100644 (file)
 
 DEFINE_PER_CPU(struct ppc64_tlb_batch, ppc64_tlb_batch);
 
-/* This is declared as we are using the more or less generic
- * arch/powerpc/include/asm/tlb.h file -- tgall
- */
-DEFINE_PER_CPU(struct mmu_gather, mmu_gathers);
-
 /*
  * A linux PTE was changed and the corresponding hash table entry
  * neesd to be flushed. This function will either perform the flush
@@ -154,6 +149,21 @@ void __flush_tlb_pending(struct ppc64_tlb_batch *batch)
        batch->index = 0;
 }
 
+void tlb_flush(struct mmu_gather *tlb)
+{
+       struct ppc64_tlb_batch *tlbbatch = &__get_cpu_var(ppc64_tlb_batch);
+
+       /* If there's a TLB batch pending, then we must flush it because the
+        * pages are going to be freed and we really don't want to have a CPU
+        * access a freed page because it has a stale TLB
+        */
+       if (tlbbatch->index)
+               __flush_tlb_pending(tlbbatch);
+
+       /* Push out batch of freed page tables */
+       pte_free_finish();
+}
+
 /**
  * __flush_hash_table_range - Flush all HPTEs for a given address range
  *                            from the hash table (and the TLB). But keeps
diff --git a/arch/powerpc/mm/tlb_low_64e.S b/arch/powerpc/mm/tlb_low_64e.S
new file mode 100644 (file)
index 0000000..ef1cccf
--- /dev/null
@@ -0,0 +1,770 @@
+/*
+ *  Low leve TLB miss handlers for Book3E
+ *
+ *  Copyright (C) 2008-2009
+ *      Ben. Herrenschmidt (benh@kernel.crashing.org), IBM Corp.
+ *
+ *  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 <asm/processor.h>
+#include <asm/reg.h>
+#include <asm/page.h>
+#include <asm/mmu.h>
+#include <asm/ppc_asm.h>
+#include <asm/asm-offsets.h>
+#include <asm/cputable.h>
+#include <asm/pgtable.h>
+#include <asm/reg.h>
+#include <asm/exception-64e.h>
+#include <asm/ppc-opcode.h>
+
+#ifdef CONFIG_PPC_64K_PAGES
+#define VPTE_PMD_SHIFT (PTE_INDEX_SIZE+1)
+#else
+#define VPTE_PMD_SHIFT (PTE_INDEX_SIZE)
+#endif
+#define VPTE_PUD_SHIFT (VPTE_PMD_SHIFT + PMD_INDEX_SIZE)
+#define VPTE_PGD_SHIFT (VPTE_PUD_SHIFT + PUD_INDEX_SIZE)
+#define VPTE_INDEX_SIZE (VPTE_PGD_SHIFT + PGD_INDEX_SIZE)
+
+
+/**********************************************************************
+ *                                                                    *
+ * TLB miss handling for Book3E with TLB reservation and HES support  *
+ *                                                                    *
+ **********************************************************************/
+
+
+/* Data TLB miss */
+       START_EXCEPTION(data_tlb_miss)
+       TLB_MISS_PROLOG
+
+       /* Now we handle the fault proper. We only save DEAR in normal
+        * fault case since that's the only interesting values here.
+        * We could probably also optimize by not saving SRR0/1 in the
+        * linear mapping case but I'll leave that for later
+        */
+       mfspr   r14,SPRN_ESR
+       mfspr   r16,SPRN_DEAR           /* get faulting address */
+       srdi    r15,r16,60              /* get region */
+       cmpldi  cr0,r15,0xc             /* linear mapping ? */
+       TLB_MISS_STATS_SAVE_INFO
+       beq     tlb_load_linear         /* yes -> go to linear map load */
+
+       /* The page tables are mapped virtually linear. At this point, though,
+        * we don't know whether we are trying to fault in a first level
+        * virtual address or a virtual page table address. We can get that
+        * from bit 0x1 of the region ID which we have set for a page table
+        */
+       andi.   r10,r15,0x1
+       bne-    virt_page_table_tlb_miss
+
+       std     r14,EX_TLB_ESR(r12);    /* save ESR */
+       std     r16,EX_TLB_DEAR(r12);   /* save DEAR */
+
+        /* We need _PAGE_PRESENT and  _PAGE_ACCESSED set */
+       li      r11,_PAGE_PRESENT
+       oris    r11,r11,_PAGE_ACCESSED@h
+
+       /* We do the user/kernel test for the PID here along with the RW test
+        */
+       cmpldi  cr0,r15,0               /* Check for user region */
+
+       /* We pre-test some combination of permissions to avoid double
+        * faults:
+        *
+        * We move the ESR:ST bit into the position of _PAGE_BAP_SW in the PTE
+        * ESR_ST   is 0x00800000
+        * _PAGE_BAP_SW is 0x00000010
+        * So the shift is >> 19. This tests for supervisor writeability.
+        * If the page happens to be supervisor writeable and not user
+        * writeable, we will take a new fault later, but that should be
+        * a rare enough case.
+        *
+        * We also move ESR_ST in _PAGE_DIRTY position
+        * _PAGE_DIRTY is 0x00001000 so the shift is >> 11
+        *
+        * MAS1 is preset for all we need except for TID that needs to
+        * be cleared for kernel translations
+        */
+       rlwimi  r11,r14,32-19,27,27
+       rlwimi  r11,r14,32-16,19,19
+       beq     normal_tlb_miss
+       /* XXX replace the RMW cycles with immediate loads + writes */
+1:     mfspr   r10,SPRN_MAS1
+       cmpldi  cr0,r15,8               /* Check for vmalloc region */
+       rlwinm  r10,r10,0,16,1          /* Clear TID */
+       mtspr   SPRN_MAS1,r10
+       beq+    normal_tlb_miss
+
+       /* We got a crappy address, just fault with whatever DEAR and ESR
+        * are here
+        */
+       TLB_MISS_STATS_D(MMSTAT_TLB_MISS_NORM_FAULT)
+       TLB_MISS_EPILOG_ERROR
+       b       exc_data_storage_book3e
+
+/* Instruction TLB miss */
+       START_EXCEPTION(instruction_tlb_miss)
+       TLB_MISS_PROLOG
+
+       /* If we take a recursive fault, the second level handler may need
+        * to know whether we are handling a data or instruction fault in
+        * order to get to the right store fault handler. We provide that
+        * info by writing a crazy value in ESR in our exception frame
+        */
+       li      r14,-1  /* store to exception frame is done later */
+
+       /* Now we handle the fault proper. We only save DEAR in the non
+        * linear mapping case since we know the linear mapping case will
+        * not re-enter. We could indeed optimize and also not save SRR0/1
+        * in the linear mapping case but I'll leave that for later
+        *
+        * Faulting address is SRR0 which is already in r16
+        */
+       srdi    r15,r16,60              /* get region */
+       cmpldi  cr0,r15,0xc             /* linear mapping ? */
+       TLB_MISS_STATS_SAVE_INFO
+       beq     tlb_load_linear         /* yes -> go to linear map load */
+
+       /* We do the user/kernel test for the PID here along with the RW test
+        */
+       li      r11,_PAGE_PRESENT|_PAGE_EXEC    /* Base perm */
+       oris    r11,r11,_PAGE_ACCESSED@h
+
+       cmpldi  cr0,r15,0                       /* Check for user region */
+       std     r14,EX_TLB_ESR(r12)             /* write crazy -1 to frame */
+       beq     normal_tlb_miss
+       /* XXX replace the RMW cycles with immediate loads + writes */
+1:     mfspr   r10,SPRN_MAS1
+       cmpldi  cr0,r15,8                       /* Check for vmalloc region */
+       rlwinm  r10,r10,0,16,1                  /* Clear TID */
+       mtspr   SPRN_MAS1,r10
+       beq+    normal_tlb_miss
+
+       /* We got a crappy address, just fault */
+       TLB_MISS_STATS_I(MMSTAT_TLB_MISS_NORM_FAULT)
+       TLB_MISS_EPILOG_ERROR
+       b       exc_instruction_storage_book3e
+
+/*
+ * This is the guts of the first-level TLB miss handler for direct
+ * misses. We are entered with:
+ *
+ * r16 = faulting address
+ * r15 = region ID
+ * r14 = crap (free to use)
+ * r13 = PACA
+ * r12 = TLB exception frame in PACA
+ * r11 = PTE permission mask
+ * r10 = crap (free to use)
+ */
+normal_tlb_miss:
+       /* So we first construct the page table address. We do that by
+        * shifting the bottom of the address (not the region ID) by
+        * PAGE_SHIFT-3, clearing the bottom 3 bits (get a PTE ptr) and
+        * or'ing the fourth high bit.
+        *
+        * NOTE: For 64K pages, we do things slightly differently in
+        * order to handle the weird page table format used by linux
+        */
+       ori     r10,r15,0x1
+#ifdef CONFIG_PPC_64K_PAGES
+       /* For the top bits, 16 bytes per PTE */
+       rldicl  r14,r16,64-(PAGE_SHIFT-4),PAGE_SHIFT-4+4
+       /* Now create the bottom bits as 0 in position 0x8000 and
+        * the rest calculated for 8 bytes per PTE
+        */
+       rldicl  r15,r16,64-(PAGE_SHIFT-3),64-15
+       /* Insert the bottom bits in */
+       rlwimi  r14,r15,0,16,31
+#else
+       rldicl  r14,r16,64-(PAGE_SHIFT-3),PAGE_SHIFT-3+4
+#endif
+       sldi    r15,r10,60
+       clrrdi  r14,r14,3
+       or      r10,r15,r14
+
+BEGIN_MMU_FTR_SECTION
+       /* Set the TLB reservation and seach for existing entry. Then load
+        * the entry.
+        */
+       PPC_TLBSRX_DOT(0,r16)
+       ld      r14,0(r10)
+       beq     normal_tlb_miss_done
+MMU_FTR_SECTION_ELSE
+       ld      r14,0(r10)
+ALT_MMU_FTR_SECTION_END_IFSET(MMU_FTR_USE_TLBRSRV)
+
+finish_normal_tlb_miss:
+       /* Check if required permissions are met */
+       andc.   r15,r11,r14
+       bne-    normal_tlb_miss_access_fault
+
+       /* Now we build the MAS:
+        *
+        * MAS 0   :    Fully setup with defaults in MAS4 and TLBnCFG
+        * MAS 1   :    Almost fully setup
+        *               - PID already updated by caller if necessary
+        *               - TSIZE need change if !base page size, not
+        *                 yet implemented for now
+        * MAS 2   :    Defaults not useful, need to be redone
+        * MAS 3+7 :    Needs to be done
+        *
+        * TODO: mix up code below for better scheduling
+        */
+       clrrdi  r11,r16,12              /* Clear low crap in EA */
+       rlwimi  r11,r14,32-19,27,31     /* Insert WIMGE */
+       mtspr   SPRN_MAS2,r11
+
+       /* Check page size, if not standard, update MAS1 */
+       rldicl  r11,r14,64-8,64-8
+#ifdef CONFIG_PPC_64K_PAGES
+       cmpldi  cr0,r11,BOOK3E_PAGESZ_64K
+#else
+       cmpldi  cr0,r11,BOOK3E_PAGESZ_4K
+#endif
+       beq-    1f
+       mfspr   r11,SPRN_MAS1
+       rlwimi  r11,r14,31,21,24
+       rlwinm  r11,r11,0,21,19
+       mtspr   SPRN_MAS1,r11
+1:
+       /* Move RPN in position */
+       rldicr  r11,r14,64-(PTE_RPN_SHIFT-PAGE_SHIFT),63-PAGE_SHIFT
+       clrldi  r15,r11,12              /* Clear crap at the top */
+       rlwimi  r15,r14,32-8,22,25      /* Move in U bits */
+       rlwimi  r15,r14,32-2,26,31      /* Move in BAP bits */
+
+       /* Mask out SW and UW if !DIRTY (XXX optimize this !) */
+       andi.   r11,r14,_PAGE_DIRTY
+       bne     1f
+       li      r11,MAS3_SW|MAS3_UW
+       andc    r15,r15,r11
+1:
+BEGIN_MMU_FTR_SECTION
+       srdi    r16,r15,32
+       mtspr   SPRN_MAS3,r15
+       mtspr   SPRN_MAS7,r16
+MMU_FTR_SECTION_ELSE
+       mtspr   SPRN_MAS7_MAS3,r15
+ALT_MMU_FTR_SECTION_END_IFCLR(MMU_FTR_USE_PAIRED_MAS)
+
+       tlbwe
+
+normal_tlb_miss_done:
+       /* We don't bother with restoring DEAR or ESR since we know we are
+        * level 0 and just going back to userland. They are only needed
+        * if you are going to take an access fault
+        */
+       TLB_MISS_STATS_X(MMSTAT_TLB_MISS_NORM_OK)
+       TLB_MISS_EPILOG_SUCCESS
+       rfi
+
+normal_tlb_miss_access_fault:
+       /* We need to check if it was an instruction miss */
+       andi.   r10,r11,_PAGE_EXEC
+       bne     1f
+       ld      r14,EX_TLB_DEAR(r12)
+       ld      r15,EX_TLB_ESR(r12)
+       mtspr   SPRN_DEAR,r14
+       mtspr   SPRN_ESR,r15
+       TLB_MISS_STATS_D(MMSTAT_TLB_MISS_NORM_FAULT)
+       TLB_MISS_EPILOG_ERROR
+       b       exc_data_storage_book3e
+1:     TLB_MISS_STATS_I(MMSTAT_TLB_MISS_NORM_FAULT)
+       TLB_MISS_EPILOG_ERROR
+       b       exc_instruction_storage_book3e
+
+
+/*
+ * This is the guts of the second-level TLB miss handler for direct
+ * misses. We are entered with:
+ *
+ * r16 = virtual page table faulting address
+ * r15 = region (top 4 bits of address)
+ * r14 = crap (free to use)
+ * r13 = PACA
+ * r12 = TLB exception frame in PACA
+ * r11 = crap (free to use)
+ * r10 = crap (free to use)
+ *
+ * Note that this should only ever be called as a second level handler
+ * with the current scheme when using SW load.
+ * That means we can always get the original fault DEAR at
+ * EX_TLB_DEAR-EX_TLB_SIZE(r12)
+ *
+ * It can be re-entered by the linear mapping miss handler. However, to
+ * avoid too much complication, it will restart the whole fault at level
+ * 0 so we don't care too much about clobbers
+ *
+ * XXX That code was written back when we couldn't clobber r14. We can now,
+ * so we could probably optimize things a bit
+ */
+virt_page_table_tlb_miss:
+       /* Are we hitting a kernel page table ? */
+       andi.   r10,r15,0x8
+
+       /* The cool thing now is that r10 contains 0 for user and 8 for kernel,
+        * and we happen to have the swapper_pg_dir at offset 8 from the user
+        * pgdir in the PACA :-).
+        */
+       add     r11,r10,r13
+
+       /* If kernel, we need to clear MAS1 TID */
+       beq     1f
+       /* XXX replace the RMW cycles with immediate loads + writes */
+       mfspr   r10,SPRN_MAS1
+       rlwinm  r10,r10,0,16,1                  /* Clear TID */
+       mtspr   SPRN_MAS1,r10
+1:
+BEGIN_MMU_FTR_SECTION
+       /* Search if we already have a TLB entry for that virtual address, and
+        * if we do, bail out.
+        */
+       PPC_TLBSRX_DOT(0,r16)
+       beq     virt_page_table_tlb_miss_done
+END_MMU_FTR_SECTION_IFSET(MMU_FTR_USE_TLBRSRV)
+
+       /* Now, we need to walk the page tables. First check if we are in
+        * range.
+        */
+       rldicl. r10,r16,64-(VPTE_INDEX_SIZE+3),VPTE_INDEX_SIZE+3+4
+       bne-    virt_page_table_tlb_miss_fault
+
+       /* Get the PGD pointer */
+       ld      r15,PACAPGD(r11)
+       cmpldi  cr0,r15,0
+       beq-    virt_page_table_tlb_miss_fault
+
+       /* Get to PGD entry */
+       rldicl  r11,r16,64-VPTE_PGD_SHIFT,64-PGD_INDEX_SIZE-3
+       clrrdi  r10,r11,3
+       ldx     r15,r10,r15
+       cmpldi  cr0,r15,0
+       beq     virt_page_table_tlb_miss_fault
+
+#ifndef CONFIG_PPC_64K_PAGES
+       /* Get to PUD entry */
+       rldicl  r11,r16,64-VPTE_PUD_SHIFT,64-PUD_INDEX_SIZE-3
+       clrrdi  r10,r11,3
+       ldx     r15,r10,r15
+       cmpldi  cr0,r15,0
+       beq     virt_page_table_tlb_miss_fault
+#endif /* CONFIG_PPC_64K_PAGES */
+
+       /* Get to PMD entry */
+       rldicl  r11,r16,64-VPTE_PMD_SHIFT,64-PMD_INDEX_SIZE-3
+       clrrdi  r10,r11,3
+       ldx     r15,r10,r15
+       cmpldi  cr0,r15,0
+       beq     virt_page_table_tlb_miss_fault
+
+       /* Ok, we're all right, we can now create a kernel translation for
+        * a 4K or 64K page from r16 -> r15.
+        */
+       /* Now we build the MAS:
+        *
+        * MAS 0   :    Fully setup with defaults in MAS4 and TLBnCFG
+        * MAS 1   :    Almost fully setup
+        *               - PID already updated by caller if necessary
+        *               - TSIZE for now is base page size always
+        * MAS 2   :    Use defaults
+        * MAS 3+7 :    Needs to be done
+        *
+        * So we only do MAS 2 and 3 for now...
+        */
+       clrldi  r11,r15,4               /* remove region ID from RPN */
+       ori     r10,r11,1               /* Or-in SR */
+
+BEGIN_MMU_FTR_SECTION
+       srdi    r16,r10,32
+       mtspr   SPRN_MAS3,r10
+       mtspr   SPRN_MAS7,r16
+MMU_FTR_SECTION_ELSE
+       mtspr   SPRN_MAS7_MAS3,r10
+ALT_MMU_FTR_SECTION_END_IFCLR(MMU_FTR_USE_PAIRED_MAS)
+
+       tlbwe
+
+BEGIN_MMU_FTR_SECTION
+virt_page_table_tlb_miss_done:
+
+       /* We have overriden MAS2:EPN but currently our primary TLB miss
+        * handler will always restore it so that should not be an issue,
+        * if we ever optimize the primary handler to not write MAS2 on
+        * some cases, we'll have to restore MAS2:EPN here based on the
+        * original fault's DEAR. If we do that we have to modify the
+        * ITLB miss handler to also store SRR0 in the exception frame
+        * as DEAR.
+        *
+        * However, one nasty thing we did is we cleared the reservation
+        * (well, potentially we did). We do a trick here thus if we
+        * are not a level 0 exception (we interrupted the TLB miss) we
+        * offset the return address by -4 in order to replay the tlbsrx
+        * instruction there
+        */
+       subf    r10,r13,r12
+       cmpldi  cr0,r10,PACA_EXTLB+EX_TLB_SIZE
+       bne-    1f
+       ld      r11,PACA_EXTLB+EX_TLB_SIZE+EX_TLB_SRR0(r13)
+       addi    r10,r11,-4
+       std     r10,PACA_EXTLB+EX_TLB_SIZE+EX_TLB_SRR0(r13)
+1:
+END_MMU_FTR_SECTION_IFSET(MMU_FTR_USE_TLBRSRV)
+       /* Return to caller, normal case */
+       TLB_MISS_STATS_X(MMSTAT_TLB_MISS_PT_OK);
+       TLB_MISS_EPILOG_SUCCESS
+       rfi
+
+virt_page_table_tlb_miss_fault:
+       /* If we fault here, things are a little bit tricky. We need to call
+        * either data or instruction store fault, and we need to retreive
+        * the original fault address and ESR (for data).
+        *
+        * The thing is, we know that in normal circumstances, this is
+        * always called as a second level tlb miss for SW load or as a first
+        * level TLB miss for HW load, so we should be able to peek at the
+        * relevant informations in the first exception frame in the PACA.
+        *
+        * However, we do need to double check that, because we may just hit
+        * a stray kernel pointer or a userland attack trying to hit those
+        * areas. If that is the case, we do a data fault. (We can't get here
+        * from an instruction tlb miss anyway).
+        *
+        * Note also that when going to a fault, we must unwind the previous
+        * level as well. Since we are doing that, we don't need to clear or
+        * restore the TLB reservation neither.
+        */
+       subf    r10,r13,r12
+       cmpldi  cr0,r10,PACA_EXTLB+EX_TLB_SIZE
+       bne-    virt_page_table_tlb_miss_whacko_fault
+
+       /* We dig the original DEAR and ESR from slot 0 */
+       ld      r15,EX_TLB_DEAR+PACA_EXTLB(r13)
+       ld      r16,EX_TLB_ESR+PACA_EXTLB(r13)
+
+       /* We check for the "special" ESR value for instruction faults */
+       cmpdi   cr0,r16,-1
+       beq     1f
+       mtspr   SPRN_DEAR,r15
+       mtspr   SPRN_ESR,r16
+       TLB_MISS_STATS_D(MMSTAT_TLB_MISS_PT_FAULT);
+       TLB_MISS_EPILOG_ERROR
+       b       exc_data_storage_book3e
+1:     TLB_MISS_STATS_I(MMSTAT_TLB_MISS_PT_FAULT);
+       TLB_MISS_EPILOG_ERROR
+       b       exc_instruction_storage_book3e
+
+virt_page_table_tlb_miss_whacko_fault:
+       /* The linear fault will restart everything so ESR and DEAR will
+        * not have been clobbered, let's just fault with what we have
+        */
+       TLB_MISS_STATS_X(MMSTAT_TLB_MISS_PT_FAULT);
+       TLB_MISS_EPILOG_ERROR
+       b       exc_data_storage_book3e
+
+
+/**************************************************************
+ *                                                            *
+ * TLB miss handling for Book3E with hw page table support    *
+ *                                                            *
+ **************************************************************/
+
+
+/* Data TLB miss */
+       START_EXCEPTION(data_tlb_miss_htw)
+       TLB_MISS_PROLOG
+
+       /* Now we handle the fault proper. We only save DEAR in normal
+        * fault case since that's the only interesting values here.
+        * We could probably also optimize by not saving SRR0/1 in the
+        * linear mapping case but I'll leave that for later
+        */
+       mfspr   r14,SPRN_ESR
+       mfspr   r16,SPRN_DEAR           /* get faulting address */
+       srdi    r11,r16,60              /* get region */
+       cmpldi  cr0,r11,0xc             /* linear mapping ? */
+       TLB_MISS_STATS_SAVE_INFO
+       beq     tlb_load_linear         /* yes -> go to linear map load */
+
+       /* We do the user/kernel test for the PID here along with the RW test
+        */
+       cmpldi  cr0,r11,0               /* Check for user region */
+       ld      r15,PACAPGD(r13)        /* Load user pgdir */
+       beq     htw_tlb_miss
+
+       /* XXX replace the RMW cycles with immediate loads + writes */
+1:     mfspr   r10,SPRN_MAS1
+       cmpldi  cr0,r11,8               /* Check for vmalloc region */
+       rlwinm  r10,r10,0,16,1          /* Clear TID */
+       mtspr   SPRN_MAS1,r10
+       ld      r15,PACA_KERNELPGD(r13) /* Load kernel pgdir */
+       beq+    htw_tlb_miss
+
+       /* We got a crappy address, just fault with whatever DEAR and ESR
+        * are here
+        */
+       TLB_MISS_STATS_D(MMSTAT_TLB_MISS_NORM_FAULT)
+       TLB_MISS_EPILOG_ERROR
+       b       exc_data_storage_book3e
+
+/* Instruction TLB miss */
+       START_EXCEPTION(instruction_tlb_miss_htw)
+       TLB_MISS_PROLOG
+
+       /* If we take a recursive fault, the second level handler may need
+        * to know whether we are handling a data or instruction fault in
+        * order to get to the right store fault handler. We provide that
+        * info by keeping a crazy value for ESR in r14
+        */
+       li      r14,-1  /* store to exception frame is done later */
+
+       /* Now we handle the fault proper. We only save DEAR in the non
+        * linear mapping case since we know the linear mapping case will
+        * not re-enter. We could indeed optimize and also not save SRR0/1
+        * in the linear mapping case but I'll leave that for later
+        *
+        * Faulting address is SRR0 which is already in r16
+        */
+       srdi    r11,r16,60              /* get region */
+       cmpldi  cr0,r11,0xc             /* linear mapping ? */
+       TLB_MISS_STATS_SAVE_INFO
+       beq     tlb_load_linear         /* yes -> go to linear map load */
+
+       /* We do the user/kernel test for the PID here along with the RW test
+        */
+       cmpldi  cr0,r11,0                       /* Check for user region */
+       ld      r15,PACAPGD(r13)                /* Load user pgdir */
+       beq     htw_tlb_miss
+
+       /* XXX replace the RMW cycles with immediate loads + writes */
+1:     mfspr   r10,SPRN_MAS1
+       cmpldi  cr0,r11,8                       /* Check for vmalloc region */
+       rlwinm  r10,r10,0,16,1                  /* Clear TID */
+       mtspr   SPRN_MAS1,r10
+       ld      r15,PACA_KERNELPGD(r13)         /* Load kernel pgdir */
+       beq+    htw_tlb_miss
+
+       /* We got a crappy address, just fault */
+       TLB_MISS_STATS_I(MMSTAT_TLB_MISS_NORM_FAULT)
+       TLB_MISS_EPILOG_ERROR
+       b       exc_instruction_storage_book3e
+
+
+/*
+ * This is the guts of the second-level TLB miss handler for direct
+ * misses. We are entered with:
+ *
+ * r16 = virtual page table faulting address
+ * r15 = PGD pointer
+ * r14 = ESR
+ * r13 = PACA
+ * r12 = TLB exception frame in PACA
+ * r11 = crap (free to use)
+ * r10 = crap (free to use)
+ *
+ * It can be re-entered by the linear mapping miss handler. However, to
+ * avoid too much complication, it will save/restore things for us
+ */
+htw_tlb_miss:
+       /* Search if we already have a TLB entry for that virtual address, and
+        * if we do, bail out.
+        *
+        * MAS1:IND should be already set based on MAS4
+        */
+       PPC_TLBSRX_DOT(0,r16)
+       beq     htw_tlb_miss_done
+
+       /* Now, we need to walk the page tables. First check if we are in
+        * range.
+        */
+       rldicl. r10,r16,64-PGTABLE_EADDR_SIZE,PGTABLE_EADDR_SIZE+4
+       bne-    htw_tlb_miss_fault
+
+       /* Get the PGD pointer */
+       cmpldi  cr0,r15,0
+       beq-    htw_tlb_miss_fault
+
+       /* Get to PGD entry */
+       rldicl  r11,r16,64-(PGDIR_SHIFT-3),64-PGD_INDEX_SIZE-3
+       clrrdi  r10,r11,3
+       ldx     r15,r10,r15
+       cmpldi  cr0,r15,0
+       beq     htw_tlb_miss_fault
+
+#ifndef CONFIG_PPC_64K_PAGES
+       /* Get to PUD entry */
+       rldicl  r11,r16,64-(PUD_SHIFT-3),64-PUD_INDEX_SIZE-3
+       clrrdi  r10,r11,3
+       ldx     r15,r10,r15
+       cmpldi  cr0,r15,0
+       beq     htw_tlb_miss_fault
+#endif /* CONFIG_PPC_64K_PAGES */
+
+       /* Get to PMD entry */
+       rldicl  r11,r16,64-(PMD_SHIFT-3),64-PMD_INDEX_SIZE-3
+       clrrdi  r10,r11,3
+       ldx     r15,r10,r15
+       cmpldi  cr0,r15,0
+       beq     htw_tlb_miss_fault
+
+       /* Ok, we're all right, we can now create an indirect entry for
+        * a 1M or 256M page.
+        *
+        * The last trick is now that because we use "half" pages for
+        * the HTW (1M IND is 2K and 256M IND is 32K) we need to account
+        * for an added LSB bit to the RPN. For 64K pages, there is no
+        * problem as we already use 32K arrays (half PTE pages), but for
+        * 4K page we need to extract a bit from the virtual address and
+        * insert it into the "PA52" bit of the RPN.
+        */
+#ifndef CONFIG_PPC_64K_PAGES
+       rlwimi  r15,r16,32-9,20,20
+#endif
+       /* Now we build the MAS:
+        *
+        * MAS 0   :    Fully setup with defaults in MAS4 and TLBnCFG
+        * MAS 1   :    Almost fully setup
+        *               - PID already updated by caller if necessary
+        *               - TSIZE for now is base ind page size always
+        * MAS 2   :    Use defaults
+        * MAS 3+7 :    Needs to be done
+        */
+#ifdef CONFIG_PPC_64K_PAGES
+       ori     r10,r15,(BOOK3E_PAGESZ_64K << MAS3_SPSIZE_SHIFT)
+#else
+       ori     r10,r15,(BOOK3E_PAGESZ_4K << MAS3_SPSIZE_SHIFT)
+#endif
+
+BEGIN_MMU_FTR_SECTION
+       srdi    r16,r10,32
+       mtspr   SPRN_MAS3,r10
+       mtspr   SPRN_MAS7,r16
+MMU_FTR_SECTION_ELSE
+       mtspr   SPRN_MAS7_MAS3,r10
+ALT_MMU_FTR_SECTION_END_IFCLR(MMU_FTR_USE_PAIRED_MAS)
+
+       tlbwe
+
+htw_tlb_miss_done:
+       /* We don't bother with restoring DEAR or ESR since we know we are
+        * level 0 and just going back to userland. They are only needed
+        * if you are going to take an access fault
+        */
+       TLB_MISS_STATS_X(MMSTAT_TLB_MISS_PT_OK)
+       TLB_MISS_EPILOG_SUCCESS
+       rfi
+
+htw_tlb_miss_fault:
+       /* We need to check if it was an instruction miss. We know this
+        * though because r14 would contain -1
+        */
+       cmpdi   cr0,r14,-1
+       beq     1f
+       mtspr   SPRN_DEAR,r16
+       mtspr   SPRN_ESR,r14
+       TLB_MISS_STATS_D(MMSTAT_TLB_MISS_PT_FAULT)
+       TLB_MISS_EPILOG_ERROR
+       b       exc_data_storage_book3e
+1:     TLB_MISS_STATS_I(MMSTAT_TLB_MISS_PT_FAULT)
+       TLB_MISS_EPILOG_ERROR
+       b       exc_instruction_storage_book3e
+
+/*
+ * This is the guts of "any" level TLB miss handler for kernel linear
+ * mapping misses. We are entered with:
+ *
+ *
+ * r16 = faulting address
+ * r15 = crap (free to use)
+ * r14 = ESR (data) or -1 (instruction)
+ * r13 = PACA
+ * r12 = TLB exception frame in PACA
+ * r11 = crap (free to use)
+ * r10 = crap (free to use)
+ *
+ * In addition we know that we will not re-enter, so in theory, we could
+ * use a simpler epilog not restoring SRR0/1 etc.. but we'll do that later.
+ *
+ * We also need to be careful about MAS registers here & TLB reservation,
+ * as we know we'll have clobbered them if we interrupt the main TLB miss
+ * handlers in which case we probably want to do a full restart at level
+ * 0 rather than saving / restoring the MAS.
+ *
+ * Note: If we care about performance of that core, we can easily shuffle
+ *       a few things around
+ */
+tlb_load_linear:
+       /* For now, we assume the linear mapping is contiguous and stops at
+        * linear_map_top. We also assume the size is a multiple of 1G, thus
+        * we only use 1G pages for now. That might have to be changed in a
+        * final implementation, especially when dealing with hypervisors
+        */
+       ld      r11,PACATOC(r13)
+       ld      r11,linear_map_top@got(r11)
+       ld      r10,0(r11)
+       cmpld   cr0,r10,r16
+       bge     tlb_load_linear_fault
+
+       /* MAS1 need whole new setup. */
+       li      r15,(BOOK3E_PAGESZ_1GB<<MAS1_TSIZE_SHIFT)
+       oris    r15,r15,MAS1_VALID@h    /* MAS1 needs V and TSIZE */
+       mtspr   SPRN_MAS1,r15
+
+       /* Already somebody there ? */
+       PPC_TLBSRX_DOT(0,r16)
+       beq     tlb_load_linear_done
+
+       /* Now we build the remaining MAS. MAS0 and 2 should be fine
+        * with their defaults, which leaves us with MAS 3 and 7. The
+        * mapping is linear, so we just take the address, clear the
+        * region bits, and or in the permission bits which are currently
+        * hard wired
+        */
+       clrrdi  r10,r16,30              /* 1G page index */
+       clrldi  r10,r10,4               /* clear region bits */
+       ori     r10,r10,MAS3_SR|MAS3_SW|MAS3_SX
+
+BEGIN_MMU_FTR_SECTION
+       srdi    r16,r10,32
+       mtspr   SPRN_MAS3,r10
+       mtspr   SPRN_MAS7,r16
+MMU_FTR_SECTION_ELSE
+       mtspr   SPRN_MAS7_MAS3,r10
+ALT_MMU_FTR_SECTION_END_IFCLR(MMU_FTR_USE_PAIRED_MAS)
+
+       tlbwe
+
+tlb_load_linear_done:
+       /* We use the "error" epilog for success as we do want to
+        * restore to the initial faulting context, whatever it was.
+        * We do that because we can't resume a fault within a TLB
+        * miss handler, due to MAS and TLB reservation being clobbered.
+        */
+       TLB_MISS_STATS_X(MMSTAT_TLB_MISS_LINEAR)
+       TLB_MISS_EPILOG_ERROR
+       rfi
+
+tlb_load_linear_fault:
+       /* We keep the DEAR and ESR around, this shouldn't have happened */
+       cmpdi   cr0,r14,-1
+       beq     1f
+       TLB_MISS_EPILOG_ERROR_SPECIAL
+       b       exc_data_storage_book3e
+1:     TLB_MISS_EPILOG_ERROR_SPECIAL
+       b       exc_instruction_storage_book3e
+
+
+#ifdef CONFIG_BOOK3E_MMU_TLB_STATS
+.tlb_stat_inc:
+1:     ldarx   r8,0,r9
+       addi    r8,r8,1
+       stdcx.  r8,0,r9
+       bne-    1b
+       blr
+#endif
index ad2eb4d34dd4c05c882096c9a43c28682a7158f1..2fbc680c2c7147f8ca2800d383c00a4500cb0b69 100644 (file)
@@ -7,8 +7,8 @@
  *
  *  -- BenH
  *
- * Copyright 2008 Ben Herrenschmidt <benh@kernel.crashing.org>
- *                IBM Corp.
+ * Copyright 2008,2009 Ben Herrenschmidt <benh@kernel.crashing.org>
+ *                     IBM Corp.
  *
  *  Derived from arch/ppc/mm/init.c:
  *    Copyright (C) 1995-1996 Gary Thomas (gdt@linuxppc.org)
 #include <linux/pagemap.h>
 #include <linux/preempt.h>
 #include <linux/spinlock.h>
+#include <linux/lmb.h>
 
 #include <asm/tlbflush.h>
 #include <asm/tlb.h>
+#include <asm/code-patching.h>
 
 #include "mmu_decl.h"
 
+#ifdef CONFIG_PPC_BOOK3E
+struct mmu_psize_def mmu_psize_defs[MMU_PAGE_COUNT] = {
+       [MMU_PAGE_4K] = {
+               .shift  = 12,
+               .enc    = BOOK3E_PAGESZ_4K,
+       },
+       [MMU_PAGE_16K] = {
+               .shift  = 14,
+               .enc    = BOOK3E_PAGESZ_16K,
+       },
+       [MMU_PAGE_64K] = {
+               .shift  = 16,
+               .enc    = BOOK3E_PAGESZ_64K,
+       },
+       [MMU_PAGE_1M] = {
+               .shift  = 20,
+               .enc    = BOOK3E_PAGESZ_1M,
+       },
+       [MMU_PAGE_16M] = {
+               .shift  = 24,
+               .enc    = BOOK3E_PAGESZ_16M,
+       },
+       [MMU_PAGE_256M] = {
+               .shift  = 28,
+               .enc    = BOOK3E_PAGESZ_256M,
+       },
+       [MMU_PAGE_1G] = {
+               .shift  = 30,
+               .enc    = BOOK3E_PAGESZ_1GB,
+       },
+};
+static inline int mmu_get_tsize(int psize)
+{
+       return mmu_psize_defs[psize].enc;
+}
+#else
+static inline int mmu_get_tsize(int psize)
+{
+       /* This isn't used on !Book3E for now */
+       return 0;
+}
+#endif
+
+/* The variables below are currently only used on 64-bit Book3E
+ * though this will probably be made common with other nohash
+ * implementations at some point
+ */
+#ifdef CONFIG_PPC64
+
+int mmu_linear_psize;          /* Page size used for the linear mapping */
+int mmu_pte_psize;             /* Page size used for PTE pages */
+int mmu_vmemmap_psize;         /* Page size used for the virtual mem map */
+int book3e_htw_enabled;                /* Is HW tablewalk enabled ? */
+unsigned long linear_map_top;  /* Top of linear mapping */
+
+#endif /* CONFIG_PPC64 */
+
 /*
  * Base TLB flushing operations:
  *
@@ -67,18 +126,24 @@ void local_flush_tlb_mm(struct mm_struct *mm)
 }
 EXPORT_SYMBOL(local_flush_tlb_mm);
 
-void local_flush_tlb_page(struct vm_area_struct *vma, unsigned long vmaddr)
+void __local_flush_tlb_page(struct mm_struct *mm, unsigned long vmaddr,
+                           int tsize, int ind)
 {
        unsigned int pid;
 
        preempt_disable();
-       pid = vma ? vma->vm_mm->context.id : 0;
+       pid = mm ? mm->context.id : 0;
        if (pid != MMU_NO_CONTEXT)
-               _tlbil_va(vmaddr, pid);
+               _tlbil_va(vmaddr, pid, tsize, ind);
        preempt_enable();
 }
-EXPORT_SYMBOL(local_flush_tlb_page);
 
+void local_flush_tlb_page(struct vm_area_struct *vma, unsigned long vmaddr)
+{
+       __local_flush_tlb_page(vma ? vma->vm_mm : NULL, vmaddr,
+                              mmu_get_tsize(mmu_virtual_psize), 0);
+}
+EXPORT_SYMBOL(local_flush_tlb_page);
 
 /*
  * And here are the SMP non-local implementations
@@ -87,9 +152,17 @@ EXPORT_SYMBOL(local_flush_tlb_page);
 
 static DEFINE_SPINLOCK(tlbivax_lock);
 
+static int mm_is_core_local(struct mm_struct *mm)
+{
+       return cpumask_subset(mm_cpumask(mm),
+                             topology_thread_cpumask(smp_processor_id()));
+}
+
 struct tlb_flush_param {
        unsigned long addr;
        unsigned int pid;
+       unsigned int tsize;
+       unsigned int ind;
 };
 
 static void do_flush_tlb_mm_ipi(void *param)
@@ -103,7 +176,7 @@ static void do_flush_tlb_page_ipi(void *param)
 {
        struct tlb_flush_param *p = param;
 
-       _tlbil_va(p->addr, p->pid);
+       _tlbil_va(p->addr, p->pid, p->tsize, p->ind);
 }
 
 
@@ -131,7 +204,7 @@ void flush_tlb_mm(struct mm_struct *mm)
        pid = mm->context.id;
        if (unlikely(pid == MMU_NO_CONTEXT))
                goto no_context;
-       if (!cpumask_equal(mm_cpumask(mm), cpumask_of(smp_processor_id()))) {
+       if (!mm_is_core_local(mm)) {
                struct tlb_flush_param p = { .pid = pid };
                /* Ignores smp_processor_id() even if set. */
                smp_call_function_many(mm_cpumask(mm),
@@ -143,37 +216,49 @@ void flush_tlb_mm(struct mm_struct *mm)
 }
 EXPORT_SYMBOL(flush_tlb_mm);
 
-void flush_tlb_page(struct vm_area_struct *vma, unsigned long vmaddr)
+void __flush_tlb_page(struct mm_struct *mm, unsigned long vmaddr,
+                     int tsize, int ind)
 {
        struct cpumask *cpu_mask;
        unsigned int pid;
 
        preempt_disable();
-       pid = vma ? vma->vm_mm->context.id : 0;
+       pid = mm ? mm->context.id : 0;
        if (unlikely(pid == MMU_NO_CONTEXT))
                goto bail;
-       cpu_mask = mm_cpumask(vma->vm_mm);
-       if (!cpumask_equal(cpu_mask, cpumask_of(smp_processor_id()))) {
+       cpu_mask = mm_cpumask(mm);
+       if (!mm_is_core_local(mm)) {
                /* If broadcast tlbivax is supported, use it */
                if (mmu_has_feature(MMU_FTR_USE_TLBIVAX_BCAST)) {
                        int lock = mmu_has_feature(MMU_FTR_LOCK_BCAST_INVAL);
                        if (lock)
                                spin_lock(&tlbivax_lock);
-                       _tlbivax_bcast(vmaddr, pid);
+                       _tlbivax_bcast(vmaddr, pid, tsize, ind);
                        if (lock)
                                spin_unlock(&tlbivax_lock);
                        goto bail;
                } else {
-                       struct tlb_flush_param p = { .pid = pid, .addr = vmaddr };
+                       struct tlb_flush_param p = {
+                               .pid = pid,
+                               .addr = vmaddr,
+                               .tsize = tsize,
+                               .ind = ind,
+                       };
                        /* Ignores smp_processor_id() even if set in cpu_mask */
                        smp_call_function_many(cpu_mask,
                                               do_flush_tlb_page_ipi, &p, 1);
                }
        }
-       _tlbil_va(vmaddr, pid);
+       _tlbil_va(vmaddr, pid, tsize, ind);
  bail:
        preempt_enable();
 }
+
+void flush_tlb_page(struct vm_area_struct *vma, unsigned long vmaddr)
+{
+       __flush_tlb_page(vma ? vma->vm_mm : NULL, vmaddr,
+                        mmu_get_tsize(mmu_virtual_psize), 0);
+}
 EXPORT_SYMBOL(flush_tlb_page);
 
 #endif /* CONFIG_SMP */
@@ -207,3 +292,156 @@ void flush_tlb_range(struct vm_area_struct *vma, unsigned long start,
        flush_tlb_mm(vma->vm_mm);
 }
 EXPORT_SYMBOL(flush_tlb_range);
+
+void tlb_flush(struct mmu_gather *tlb)
+{
+       flush_tlb_mm(tlb->mm);
+
+       /* Push out batch of freed page tables */
+       pte_free_finish();
+}
+
+/*
+ * Below are functions specific to the 64-bit variant of Book3E though that
+ * may change in the future
+ */
+
+#ifdef CONFIG_PPC64
+
+/*
+ * Handling of virtual linear page tables or indirect TLB entries
+ * flushing when PTE pages are freed
+ */
+void tlb_flush_pgtable(struct mmu_gather *tlb, unsigned long address)
+{
+       int tsize = mmu_psize_defs[mmu_pte_psize].enc;
+
+       if (book3e_htw_enabled) {
+               unsigned long start = address & PMD_MASK;
+               unsigned long end = address + PMD_SIZE;
+               unsigned long size = 1UL << mmu_psize_defs[mmu_pte_psize].shift;
+
+               /* This isn't the most optimal, ideally we would factor out the
+                * while preempt & CPU mask mucking around, or even the IPI but
+                * it will do for now
+                */
+               while (start < end) {
+                       __flush_tlb_page(tlb->mm, start, tsize, 1);
+                       start += size;
+               }
+       } else {
+               unsigned long rmask = 0xf000000000000000ul;
+               unsigned long rid = (address & rmask) | 0x1000000000000000ul;
+               unsigned long vpte = address & ~rmask;
+
+#ifdef CONFIG_PPC_64K_PAGES
+               vpte = (vpte >> (PAGE_SHIFT - 4)) & ~0xfffful;
+#else
+               vpte = (vpte >> (PAGE_SHIFT - 3)) & ~0xffful;
+#endif
+               vpte |= rid;
+               __flush_tlb_page(tlb->mm, vpte, tsize, 0);
+       }
+}
+
+/*
+ * Early initialization of the MMU TLB code
+ */
+static void __early_init_mmu(int boot_cpu)
+{
+       extern unsigned int interrupt_base_book3e;
+       extern unsigned int exc_data_tlb_miss_htw_book3e;
+       extern unsigned int exc_instruction_tlb_miss_htw_book3e;
+
+       unsigned int *ibase = &interrupt_base_book3e;
+       unsigned int mas4;
+
+       /* XXX This will have to be decided at runtime, but right
+        * now our boot and TLB miss code hard wires it. Ideally
+        * we should find out a suitable page size and patch the
+        * TLB miss code (either that or use the PACA to store
+        * the value we want)
+        */
+       mmu_linear_psize = MMU_PAGE_1G;
+
+       /* XXX This should be decided at runtime based on supported
+        * page sizes in the TLB, but for now let's assume 16M is
+        * always there and a good fit (which it probably is)
+        */
+       mmu_vmemmap_psize = MMU_PAGE_16M;
+
+       /* Check if HW tablewalk is present, and if yes, enable it by:
+        *
+        * - patching the TLB miss handlers to branch to the
+        *   one dedicates to it
+        *
+        * - setting the global book3e_htw_enabled
+        *
+        * - Set MAS4:INDD and default page size
+        */
+
+       /* XXX This code only checks for TLB 0 capabilities and doesn't
+        *     check what page size combos are supported by the HW. It
+        *     also doesn't handle the case where a separate array holds
+        *     the IND entries from the array loaded by the PT.
+        */
+       if (boot_cpu) {
+               unsigned int tlb0cfg = mfspr(SPRN_TLB0CFG);
+
+               /* Check if HW loader is supported */
+               if ((tlb0cfg & TLBnCFG_IND) &&
+                   (tlb0cfg & TLBnCFG_PT)) {
+                       patch_branch(ibase + (0x1c0 / 4),
+                            (unsigned long)&exc_data_tlb_miss_htw_book3e, 0);
+                       patch_branch(ibase + (0x1e0 / 4),
+                            (unsigned long)&exc_instruction_tlb_miss_htw_book3e, 0);
+                       book3e_htw_enabled = 1;
+               }
+               pr_info("MMU: Book3E Page Tables %s\n",
+                       book3e_htw_enabled ? "Enabled" : "Disabled");
+       }
+
+       /* Set MAS4 based on page table setting */
+
+       mas4 = 0x4 << MAS4_WIMGED_SHIFT;
+       if (book3e_htw_enabled) {
+               mas4 |= mas4 | MAS4_INDD;
+#ifdef CONFIG_PPC_64K_PAGES
+               mas4 |= BOOK3E_PAGESZ_256M << MAS4_TSIZED_SHIFT;
+               mmu_pte_psize = MMU_PAGE_256M;
+#else
+               mas4 |= BOOK3E_PAGESZ_1M << MAS4_TSIZED_SHIFT;
+               mmu_pte_psize = MMU_PAGE_1M;
+#endif
+       } else {
+#ifdef CONFIG_PPC_64K_PAGES
+               mas4 |= BOOK3E_PAGESZ_64K << MAS4_TSIZED_SHIFT;
+#else
+               mas4 |= BOOK3E_PAGESZ_4K << MAS4_TSIZED_SHIFT;
+#endif
+               mmu_pte_psize = mmu_virtual_psize;
+       }
+       mtspr(SPRN_MAS4, mas4);
+
+       /* Set the global containing the top of the linear mapping
+        * for use by the TLB miss code
+        */
+       linear_map_top = lmb_end_of_DRAM();
+
+       /* A sync won't hurt us after mucking around with
+        * the MMU configuration
+        */
+       mb();
+}
+
+void __init early_init_mmu(void)
+{
+       __early_init_mmu(1);
+}
+
+void __cpuinit early_init_mmu_secondary(void)
+{
+       __early_init_mmu(0);
+}
+
+#endif /* CONFIG_PPC64 */
index 3037911279b197c088014eb9b17304ee26a9265c..bbdc5b577b85612b0a5bf5debe03a9f6324fc0c1 100644 (file)
@@ -39,7 +39,7 @@
 /*
  * 40x implementation needs only tlbil_va
  */
-_GLOBAL(_tlbil_va)
+_GLOBAL(__tlbil_va)
        /* We run the search with interrupts disabled because we have to change
         * the PID and I don't want to preempt when that happens.
         */
@@ -71,7 +71,7 @@ _GLOBAL(_tlbil_va)
  * 440 implementation uses tlbsx/we for tlbil_va and a full sweep
  * of the TLB for everything else.
  */
-_GLOBAL(_tlbil_va)
+_GLOBAL(__tlbil_va)
        mfspr   r5,SPRN_MMUCR
        rlwimi  r5,r4,0,24,31                   /* Set TID */
 
@@ -124,8 +124,6 @@ _GLOBAL(_tlbil_pid)
  * to have the larger code path before the _SECTION_ELSE
  */
 
-#define MMUCSR0_TLBFI  (MMUCSR0_TLB0FI | MMUCSR0_TLB1FI | \
-                        MMUCSR0_TLB2FI | MMUCSR0_TLB3FI)
 /*
  * Flush MMU TLB on the local processor
  */
@@ -170,7 +168,7 @@ ALT_MMU_FTR_SECTION_END_IFSET(MMU_FTR_USE_TLBILX)
  * Flush MMU TLB for a particular address, but only on the local processor
  * (no broadcast)
  */
-_GLOBAL(_tlbil_va)
+_GLOBAL(__tlbil_va)
        mfmsr   r10
        wrteei  0
        slwi    r4,r4,16
@@ -191,6 +189,85 @@ ALT_MMU_FTR_SECTION_END_IFCLR(MMU_FTR_USE_TLBILX)
        isync
 1:     wrtee   r10
        blr
+#elif defined(CONFIG_PPC_BOOK3E)
+/*
+ * New Book3E (>= 2.06) implementation
+ *
+ * Note: We may be able to get away without the interrupt masking stuff
+ * if we save/restore MAS6 on exceptions that might modify it
+ */
+_GLOBAL(_tlbil_pid)
+       slwi    r4,r3,MAS6_SPID_SHIFT
+       mfmsr   r10
+       wrteei  0
+       mtspr   SPRN_MAS6,r4
+       PPC_TLBILX_PID(0,0)
+       wrtee   r10
+       msync
+       isync
+       blr
+
+_GLOBAL(_tlbil_pid_noind)
+       slwi    r4,r3,MAS6_SPID_SHIFT
+       mfmsr   r10
+       ori     r4,r4,MAS6_SIND
+       wrteei  0
+       mtspr   SPRN_MAS6,r4
+       PPC_TLBILX_PID(0,0)
+       wrtee   r10
+       msync
+       isync
+       blr
+
+_GLOBAL(_tlbil_all)
+       PPC_TLBILX_ALL(0,0)
+       msync
+       isync
+       blr
+
+_GLOBAL(_tlbil_va)
+       mfmsr   r10
+       wrteei  0
+       cmpwi   cr0,r6,0
+       slwi    r4,r4,MAS6_SPID_SHIFT
+       rlwimi  r4,r5,MAS6_ISIZE_SHIFT,MAS6_ISIZE_MASK
+       beq     1f
+       rlwimi  r4,r6,MAS6_SIND_SHIFT,MAS6_SIND
+1:     mtspr   SPRN_MAS6,r4            /* assume AS=0 for now */
+       PPC_TLBILX_VA(0,r3)
+       msync
+       isync
+       wrtee   r10
+       blr
+
+_GLOBAL(_tlbivax_bcast)
+       mfmsr   r10
+       wrteei  0
+       cmpwi   cr0,r6,0
+       slwi    r4,r4,MAS6_SPID_SHIFT
+       rlwimi  r4,r5,MAS6_ISIZE_SHIFT,MAS6_ISIZE_MASK
+       beq     1f
+       rlwimi  r4,r6,MAS6_SIND_SHIFT,MAS6_SIND
+1:     mtspr   SPRN_MAS6,r4            /* assume AS=0 for now */
+       PPC_TLBIVAX(0,r3)
+       eieio
+       tlbsync
+       sync
+       wrtee   r10
+       blr
+
+_GLOBAL(set_context)
+#ifdef CONFIG_BDI_SWITCH
+       /* Context switch the PTE pointer for the Abatron BDI2000.
+        * The PGDIR is the second parameter.
+        */
+       lis     r5, abatron_pteptrs@h
+       ori     r5, r5, abatron_pteptrs@l
+       stw     r4, 0x4(r5)
+#endif
+       mtspr   SPRN_PID,r3
+       isync                   /* Force context change */
+       blr
 #else
 #error Unsupported processor type !
 #endif
index a6e43cb6f8252aa96d5a421609d1cbd82152bc60..ec64264f7a506c8b99c3542240c36a9730429e31 100644 (file)
@@ -40,6 +40,16 @@ config HCU4
        help
          This option enables support for the Nestal Maschinen HCU4 board.
 
+config HOTFOOT
+        bool "Hotfoot"
+       depends on 40x
+       default n
+       select 405EP
+       select PPC40x_SIMPLE
+       select PCI
+        help
+        This option enables support for the ESTEEM 195E Hotfoot board.
+
 config KILAUEA
        bool "Kilauea"
        depends on 40x
index 5fd5a5974001c918f33080906e6570e107cc1531..546bbc229d19dd0d64277aa31b678f5b441eb432 100644 (file)
@@ -54,7 +54,8 @@ static char *board[] __initdata = {
        "amcc,acadia",
        "amcc,haleakala",
        "amcc,kilauea",
-       "amcc,makalu"
+       "amcc,makalu",
+       "est,hotfoot"
 };
 
 static int __init ppc40x_probe(void)
index 90e3192611a4d52d5b19d2b8876912453fcdec84..7486bffd3ebb17bb5f00738b31917fcbd5802faf 100644 (file)
@@ -129,6 +129,18 @@ config REDWOOD
        help
          This option enables support for the AMCC PPC460SX Redwood board.
 
+config EIGER
+       bool "Eiger"
+       depends on 44x
+       default n
+       select PPC44x_SIMPLE
+       select 460SX
+       select PCI
+       select PPC4xx_PCI_EXPRESS
+       select IBM_NEW_EMAC_RGMII
+       help
+         This option enables support for the AMCC PPC460SX evaluation board.
+
 config YOSEMITE
        bool "Yosemite"
        depends on 44x
index 5bcd441885e83c5fb4f62a488c012710a397b916..e8c23ccaa1fcfc628744d4490f408860352d0969 100644 (file)
@@ -55,6 +55,7 @@ static char *board[] __initdata = {
        "amcc,canyonlands",
        "amcc,glacier",
        "ibm,ebony",
+       "amcc,eiger",
        "amcc,katmai",
        "amcc,rainier",
        "amcc,redwood",
index c2af169c1d1dd743a385d9dbc9823b41b517a7ce..7a5de9eb3c73dffd4fa795fbf889636eaed72df6 100644 (file)
@@ -50,16 +50,63 @@ struct cpm_pin {
 static __initdata struct cpm_pin mgcoge_pins[] = {
 
        /* SMC2 */
-       {1, 8, CPM_PIN_INPUT | CPM_PIN_PRIMARY},
-       {1, 9, CPM_PIN_OUTPUT | CPM_PIN_PRIMARY},
+       {0, 8, CPM_PIN_INPUT | CPM_PIN_PRIMARY},
+       {0, 9, CPM_PIN_OUTPUT | CPM_PIN_PRIMARY},
 
        /* SCC4 */
-       {3, 25, CPM_PIN_INPUT | CPM_PIN_PRIMARY},
-       {3, 24, CPM_PIN_INPUT | CPM_PIN_PRIMARY},
-       {3,  9, CPM_PIN_INPUT | CPM_PIN_PRIMARY},
-       {3,  8, CPM_PIN_INPUT | CPM_PIN_PRIMARY},
-       {4, 22, CPM_PIN_INPUT | CPM_PIN_PRIMARY},
-       {4, 21, CPM_PIN_OUTPUT | CPM_PIN_PRIMARY},
+       {2, 25, CPM_PIN_INPUT | CPM_PIN_PRIMARY},
+       {2, 24, CPM_PIN_INPUT | CPM_PIN_PRIMARY},
+       {2,  9, CPM_PIN_INPUT | CPM_PIN_PRIMARY},
+       {2,  8, CPM_PIN_INPUT | CPM_PIN_PRIMARY},
+       {3, 22, CPM_PIN_INPUT | CPM_PIN_PRIMARY},
+       {3, 21, CPM_PIN_OUTPUT | CPM_PIN_PRIMARY},
+
+       /* FCC1 */
+       {0, 14, CPM_PIN_INPUT | CPM_PIN_PRIMARY},
+       {0, 15, CPM_PIN_INPUT | CPM_PIN_PRIMARY},
+       {0, 16, CPM_PIN_INPUT | CPM_PIN_PRIMARY},
+       {0, 17, CPM_PIN_INPUT | CPM_PIN_PRIMARY},
+       {0, 18, CPM_PIN_OUTPUT | CPM_PIN_PRIMARY},
+       {0, 19, CPM_PIN_OUTPUT | CPM_PIN_PRIMARY},
+       {0, 20, CPM_PIN_OUTPUT | CPM_PIN_PRIMARY},
+       {0, 21, CPM_PIN_OUTPUT | CPM_PIN_PRIMARY},
+       {0, 26, CPM_PIN_INPUT | CPM_PIN_SECONDARY},
+       {0, 27, CPM_PIN_INPUT | CPM_PIN_SECONDARY},
+       {0, 28, CPM_PIN_OUTPUT | CPM_PIN_SECONDARY},
+       {0, 29, CPM_PIN_OUTPUT | CPM_PIN_SECONDARY},
+       {0, 30, CPM_PIN_INPUT | CPM_PIN_SECONDARY},
+       {0, 31, CPM_PIN_INPUT | CPM_PIN_SECONDARY},
+
+       {2, 22, CPM_PIN_INPUT | CPM_PIN_PRIMARY},
+       {2, 23, CPM_PIN_INPUT | CPM_PIN_PRIMARY},
+
+       /* FCC2 */
+       {1, 18, CPM_PIN_INPUT | CPM_PIN_PRIMARY},
+       {1, 19, CPM_PIN_INPUT | CPM_PIN_PRIMARY},
+       {1, 20, CPM_PIN_INPUT | CPM_PIN_PRIMARY},
+       {1, 21, CPM_PIN_INPUT | CPM_PIN_PRIMARY},
+       {1, 22, CPM_PIN_OUTPUT | CPM_PIN_PRIMARY},
+       {1, 23, CPM_PIN_OUTPUT | CPM_PIN_PRIMARY},
+       {1, 24, CPM_PIN_OUTPUT | CPM_PIN_PRIMARY},
+       {1, 25, CPM_PIN_OUTPUT | CPM_PIN_PRIMARY},
+       {1, 26, CPM_PIN_INPUT | CPM_PIN_PRIMARY},
+       {1, 27, CPM_PIN_INPUT | CPM_PIN_PRIMARY},
+       {1, 28, CPM_PIN_INPUT | CPM_PIN_PRIMARY},
+       {1, 29, CPM_PIN_OUTPUT | CPM_PIN_SECONDARY},
+       {1, 30, CPM_PIN_INPUT | CPM_PIN_PRIMARY},
+       {1, 31, CPM_PIN_OUTPUT | CPM_PIN_PRIMARY},
+
+       {2, 18, CPM_PIN_INPUT | CPM_PIN_PRIMARY},
+       {2, 19, CPM_PIN_INPUT | CPM_PIN_PRIMARY},
+
+       /* MDC */
+       {0, 13, CPM_PIN_OUTPUT | CPM_PIN_GPIO},
+
+#if defined(CONFIG_I2C_CPM)
+       /* I2C */
+       {3, 14, CPM_PIN_INPUT | CPM_PIN_SECONDARY | CPM_PIN_OPENDRAIN},
+       {3, 15, CPM_PIN_INPUT | CPM_PIN_SECONDARY | CPM_PIN_OPENDRAIN},
+#endif
 };
 
 static void __init init_ioports(void)
@@ -68,12 +115,16 @@ static void __init init_ioports(void)
 
        for (i = 0; i < ARRAY_SIZE(mgcoge_pins); i++) {
                const struct cpm_pin *pin = &mgcoge_pins[i];
-               cpm2_set_pin(pin->port - 1, pin->pin, pin->flags);
+               cpm2_set_pin(pin->port, pin->pin, pin->flags);
        }
 
        cpm2_smc_clk_setup(CPM_CLK_SMC2, CPM_BRG8);
        cpm2_clk_setup(CPM_CLK_SCC4, CPM_CLK7, CPM_CLK_RX);
        cpm2_clk_setup(CPM_CLK_SCC4, CPM_CLK8, CPM_CLK_TX);
+       cpm2_clk_setup(CPM_CLK_FCC1, CPM_CLK10, CPM_CLK_RX);
+       cpm2_clk_setup(CPM_CLK_FCC1, CPM_CLK9,  CPM_CLK_TX);
+       cpm2_clk_setup(CPM_CLK_FCC2, CPM_CLK13, CPM_CLK_RX);
+       cpm2_clk_setup(CPM_CLK_FCC2, CPM_CLK14, CPM_CLK_TX);
 }
 
 static void __init mgcoge_setup_arch(void)
index 8054c685d323a50c90fc7506db4faa76447a6a1f..30394b409b3f98655074d4f55e9514912b3506a5 100644 (file)
@@ -29,7 +29,6 @@
 #include <sysdev/fsl_soc.h>
 #include <sysdev/cpm2_pic.h>
 
-#include "pq2ads.h"
 #include "pq2.h"
 
 static void __init mpc8272_ads_pic_init(void)
@@ -100,6 +99,15 @@ static struct cpm_pin mpc8272_ads_pins[] = {
        /* I2C */
        {3, 14, CPM_PIN_INPUT | CPM_PIN_SECONDARY | CPM_PIN_OPENDRAIN},
        {3, 15, CPM_PIN_INPUT | CPM_PIN_SECONDARY | CPM_PIN_OPENDRAIN},
+
+       /* USB */
+       {2, 10, CPM_PIN_INPUT | CPM_PIN_PRIMARY},
+       {2, 11, CPM_PIN_INPUT | CPM_PIN_PRIMARY},
+       {2, 20, CPM_PIN_OUTPUT | CPM_PIN_PRIMARY},
+       {2, 24, CPM_PIN_INPUT | CPM_PIN_PRIMARY},
+       {3, 23, CPM_PIN_OUTPUT | CPM_PIN_PRIMARY},
+       {3, 24, CPM_PIN_OUTPUT | CPM_PIN_PRIMARY},
+       {3, 25, CPM_PIN_INPUT | CPM_PIN_PRIMARY},
 };
 
 static void __init init_ioports(void)
@@ -113,6 +121,8 @@ static void __init init_ioports(void)
 
        cpm2_clk_setup(CPM_CLK_SCC1, CPM_BRG1, CPM_CLK_RX);
        cpm2_clk_setup(CPM_CLK_SCC1, CPM_BRG1, CPM_CLK_TX);
+       cpm2_clk_setup(CPM_CLK_SCC3, CPM_CLK8, CPM_CLK_RX);
+       cpm2_clk_setup(CPM_CLK_SCC3, CPM_CLK8, CPM_CLK_TX);
        cpm2_clk_setup(CPM_CLK_SCC4, CPM_BRG4, CPM_CLK_RX);
        cpm2_clk_setup(CPM_CLK_SCC4, CPM_BRG4, CPM_CLK_TX);
        cpm2_clk_setup(CPM_CLK_FCC1, CPM_CLK11, CPM_CLK_RX);
@@ -144,12 +154,22 @@ static void __init mpc8272_ads_setup_arch(void)
                return;
        }
 
+#define BCSR1_FETHIEN          0x08000000
+#define BCSR1_FETH_RST         0x04000000
+#define BCSR1_RS232_EN1                0x02000000
+#define BCSR1_RS232_EN2                0x01000000
+#define BCSR3_USB_nEN          0x80000000
+#define BCSR3_FETHIEN2         0x10000000
+#define BCSR3_FETH2_RST                0x08000000
+
        clrbits32(&bcsr[1], BCSR1_RS232_EN1 | BCSR1_RS232_EN2 | BCSR1_FETHIEN);
        setbits32(&bcsr[1], BCSR1_FETH_RST);
 
        clrbits32(&bcsr[3], BCSR3_FETHIEN2);
        setbits32(&bcsr[3], BCSR3_FETH2_RST);
 
+       clrbits32(&bcsr[3], BCSR3_USB_nEN);
+
        iounmap(bcsr);
 
        init_ioports();
index 083ebee9a16d8417af8950f9298645d0bf179c06..f49a2548c5ff2c20ddd45daefe21688f07dcd9a6 100644 (file)
@@ -75,11 +75,11 @@ config MPC837x_MDS
          This option enables support for the MPC837x MDS Processor Board.
 
 config MPC837x_RDB
-       bool "Freescale MPC837x RDB"
+       bool "Freescale MPC837x RDB/WLAN"
        select DEFAULT_UIMAGE
        select PPC_MPC837x
        help
-         This option enables support for the MPC837x RDB Board.
+         This option enables support for the MPC837x RDB and WLAN Boards.
 
 config SBC834x
        bool "Wind River SBC834x"
index 76f3b32a155ed4c9da1bf7a99d95d7629fe26ea3..a1908d261240e07ca93d096418c24fe2e4ad0d76 100644 (file)
 #include <asm/time.h>
 #include <asm/ipic.h>
 #include <asm/udbg.h>
+#include <sysdev/fsl_soc.h>
 #include <sysdev/fsl_pci.h>
 
 #include "mpc83xx.h"
 
+static void mpc837x_rdb_sd_cfg(void)
+{
+       void __iomem *im;
+
+       im = ioremap(get_immrbase(), 0x1000);
+       if (!im) {
+               WARN_ON(1);
+               return;
+       }
+
+       /*
+        * On RDB boards (in contrast to MDS) USBB pins are used for SD only,
+        * so we can safely mux them away from the USB block.
+        */
+       clrsetbits_be32(im + MPC83XX_SICRL_OFFS, MPC837X_SICRL_USBB_MASK,
+                                                MPC837X_SICRL_SD);
+       clrsetbits_be32(im + MPC83XX_SICRH_OFFS, MPC837X_SICRH_SPI_MASK,
+                                                MPC837X_SICRH_SD);
+       iounmap(im);
+}
+
 /* ************************************************************************
  *
  * Setup the architecture
@@ -42,6 +64,7 @@ static void __init mpc837x_rdb_setup_arch(void)
                mpc83xx_add_bridge(np);
 #endif
        mpc837x_usb_cfg();
+       mpc837x_rdb_sd_cfg();
 }
 
 static struct of_device_id mpc837x_ids[] = {
@@ -86,11 +109,12 @@ static int __init mpc837x_rdb_probe(void)
 
        return of_flat_dt_is_compatible(root, "fsl,mpc8377rdb") ||
               of_flat_dt_is_compatible(root, "fsl,mpc8378rdb") ||
-              of_flat_dt_is_compatible(root, "fsl,mpc8379rdb");
+              of_flat_dt_is_compatible(root, "fsl,mpc8379rdb") ||
+              of_flat_dt_is_compatible(root, "fsl,mpc8377wlan");
 }
 
 define_machine(mpc837x_rdb) {
-       .name                   = "MPC837x RDB",
+       .name                   = "MPC837x RDB/WLAN",
        .probe                  = mpc837x_rdb_probe,
        .setup_arch             = mpc837x_rdb_setup_arch,
        .init_IRQ               = mpc837x_rdb_init_IRQ,
index d1dc5b0b4fbfac991beb22578cb99cb559ae3238..0fea8811d45beb304bbf5d4163f6fd467940c521 100644 (file)
@@ -30,6 +30,8 @@
 #define MPC8315_SICRL_USB_ULPI     0x00000054
 #define MPC837X_SICRL_USB_MASK     0xf0000000
 #define MPC837X_SICRL_USB_ULPI     0x50000000
+#define MPC837X_SICRL_USBB_MASK    0x30000000
+#define MPC837X_SICRL_SD           0x20000000
 
 /* system i/o configuration register high */
 #define MPC83XX_SICRH_OFFS         0x118
@@ -38,6 +40,8 @@
 #define MPC831X_SICRH_USB_ULPI     0x000000a0
 #define MPC8315_SICRH_USB_MASK     0x0000ff00
 #define MPC8315_SICRH_USB_ULPI     0x00000000
+#define MPC837X_SICRH_SPI_MASK     0x00000003
+#define MPC837X_SICRH_SD           0x00000001
 
 /* USB Control Register */
 #define FSL_USB2_CONTROL_OFFS      0x500
index a9b416688975a78de67758296ffe65ac1525f552..d3a975e8fd3e1c86bcfb913accb06c1e8bbb8c55 100644 (file)
@@ -55,6 +55,15 @@ config MPC85xx_DS
        help
          This option enables support for the MPC85xx DS (MPC8544 DS) board
 
+config MPC85xx_RDB
+       bool "Freescale MPC85xx RDB"
+       select PPC_I8259
+       select DEFAULT_UIMAGE
+       select FSL_ULI1575
+       select SWIOTLB
+       help
+         This option enables support for the MPC85xx RDB (P2020 RDB) board
+
 config SOCRATES
        bool "Socrates"
        select DEFAULT_UIMAGE
index 835733f2b12c9613ce84c9b3520672a3f583ff82..9098aea0cf325c26e90c7c37f8d5b455c537ed72 100644 (file)
@@ -9,10 +9,11 @@ obj-$(CONFIG_MPC85xx_CDS) += mpc85xx_cds.o
 obj-$(CONFIG_MPC8536_DS)  += mpc8536_ds.o
 obj-$(CONFIG_MPC85xx_DS)  += mpc85xx_ds.o
 obj-$(CONFIG_MPC85xx_MDS) += mpc85xx_mds.o
+obj-$(CONFIG_MPC85xx_RDB) += mpc85xx_rdb.o
 obj-$(CONFIG_STX_GP3)    += stx_gp3.o
 obj-$(CONFIG_TQM85xx)    += tqm85xx.o
 obj-$(CONFIG_SBC8560)     += sbc8560.o
 obj-$(CONFIG_SBC8548)     += sbc8548.o
 obj-$(CONFIG_SOCRATES)    += socrates.o socrates_fpga_pic.o
 obj-$(CONFIG_KSI8560)    += ksi8560.o
-obj-$(CONFIG_XES_MPC85xx) += xes_mpc85xx.o
\ No newline at end of file
+obj-$(CONFIG_XES_MPC85xx) += xes_mpc85xx.o
index 055ff417bae95a298461e2cab002deb6edad9581..004b7d36cdb7512e33b8b774b25057d0b6230e2c 100644 (file)
@@ -96,7 +96,8 @@ static void __init mpc8536_ds_setup_arch(void)
 #ifdef CONFIG_SWIOTLB
        if (lmb_end_of_DRAM() > max) {
                ppc_swiotlb_enable = 1;
-               set_pci_dma_ops(&swiotlb_pci_dma_ops);
+               set_pci_dma_ops(&swiotlb_dma_ops);
+               ppc_md.pci_dma_dev_setup = pci_dma_dev_setup_swiotlb;
        }
 #endif
 
index 849c0ac0025fd6d849fcb2eb9a295e542fb41155..544011a562fb283c64b864b295fe17ff046d4f40 100644 (file)
@@ -192,7 +192,8 @@ static void __init mpc85xx_ds_setup_arch(void)
 #ifdef CONFIG_SWIOTLB
        if (lmb_end_of_DRAM() > max) {
                ppc_swiotlb_enable = 1;
-               set_pci_dma_ops(&swiotlb_pci_dma_ops);
+               set_pci_dma_ops(&swiotlb_dma_ops);
+               ppc_md.pci_dma_dev_setup = pci_dma_dev_setup_swiotlb;
        }
 #endif
 
index bfb32834ab0c442f78c7cbf870ffedf6c34b17a1..3909d57b86e3aed43d2101db2b3fb25ad5d7d004 100644 (file)
@@ -47,6 +47,7 @@
 #include <asm/udbg.h>
 #include <sysdev/fsl_soc.h>
 #include <sysdev/fsl_pci.h>
+#include <sysdev/simple_gpio.h>
 #include <asm/qe.h>
 #include <asm/qe_ic.h>
 #include <asm/mpic.h>
@@ -254,7 +255,8 @@ static void __init mpc85xx_mds_setup_arch(void)
 #ifdef CONFIG_SWIOTLB
        if (lmb_end_of_DRAM() > max) {
                ppc_swiotlb_enable = 1;
-               set_pci_dma_ops(&swiotlb_pci_dma_ops);
+               set_pci_dma_ops(&swiotlb_dma_ops);
+               ppc_md.pci_dma_dev_setup = pci_dma_dev_setup_swiotlb;
        }
 #endif
 }
@@ -304,6 +306,9 @@ static struct of_device_id mpc85xx_ids[] = {
 
 static int __init mpc85xx_publish_devices(void)
 {
+       if (machine_is(mpc8569_mds))
+               simple_gpiochip_init("fsl,mpc8569mds-bcsr-gpio");
+
        /* Publish the QE devices */
        of_platform_bus_probe(NULL, mpc85xx_ids, NULL);
 
diff --git a/arch/powerpc/platforms/85xx/mpc85xx_rdb.c b/arch/powerpc/platforms/85xx/mpc85xx_rdb.c
new file mode 100644 (file)
index 0000000..c8468de
--- /dev/null
@@ -0,0 +1,141 @@
+/*
+ * MPC85xx RDB Board Setup
+ *
+ * Copyright 2009 Freescale Semiconductor 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 of the  License, or (at your
+ * option) any later version.
+ */
+
+#include <linux/stddef.h>
+#include <linux/kernel.h>
+#include <linux/pci.h>
+#include <linux/kdev_t.h>
+#include <linux/delay.h>
+#include <linux/seq_file.h>
+#include <linux/interrupt.h>
+#include <linux/of_platform.h>
+
+#include <asm/system.h>
+#include <asm/time.h>
+#include <asm/machdep.h>
+#include <asm/pci-bridge.h>
+#include <mm/mmu_decl.h>
+#include <asm/prom.h>
+#include <asm/udbg.h>
+#include <asm/mpic.h>
+
+#include <sysdev/fsl_soc.h>
+#include <sysdev/fsl_pci.h>
+
+#undef DEBUG
+
+#ifdef DEBUG
+#define DBG(fmt, args...) printk(KERN_ERR "%s: " fmt, __func__, ## args)
+#else
+#define DBG(fmt, args...)
+#endif
+
+
+void __init mpc85xx_rdb_pic_init(void)
+{
+       struct mpic *mpic;
+       struct resource r;
+       struct device_node *np;
+
+       np = of_find_node_by_type(NULL, "open-pic");
+       if (np == NULL) {
+               printk(KERN_ERR "Could not find open-pic node\n");
+               return;
+       }
+
+       if (of_address_to_resource(np, 0, &r)) {
+               printk(KERN_ERR "Failed to map mpic register space\n");
+               of_node_put(np);
+               return;
+       }
+
+       mpic = mpic_alloc(np, r.start,
+                 MPIC_PRIMARY | MPIC_WANTS_RESET |
+                 MPIC_BIG_ENDIAN | MPIC_BROKEN_FRR_NIRQS |
+                 MPIC_SINGLE_DEST_CPU,
+                 0, 256, " OpenPIC  ");
+
+       BUG_ON(mpic == NULL);
+       of_node_put(np);
+
+       mpic_init(mpic);
+
+}
+
+/*
+ * Setup the architecture
+ */
+#ifdef CONFIG_SMP
+extern void __init mpc85xx_smp_init(void);
+#endif
+static void __init mpc85xx_rdb_setup_arch(void)
+{
+#ifdef CONFIG_PCI
+       struct device_node *np;
+#endif
+
+       if (ppc_md.progress)
+               ppc_md.progress("mpc85xx_rdb_setup_arch()", 0);
+
+#ifdef CONFIG_PCI
+       for_each_node_by_type(np, "pci") {
+               if (of_device_is_compatible(np, "fsl,mpc8548-pcie"))
+                       fsl_add_bridge(np, 0);
+       }
+
+#endif
+
+#ifdef CONFIG_SMP
+       mpc85xx_smp_init();
+#endif
+
+       printk(KERN_INFO "MPC85xx RDB board from Freescale Semiconductor\n");
+}
+
+static struct of_device_id __initdata mpc85xxrdb_ids[] = {
+       { .type = "soc", },
+       { .compatible = "soc", },
+       { .compatible = "simple-bus", },
+       { .compatible = "gianfar", },
+       {},
+};
+
+static int __init mpc85xxrdb_publish_devices(void)
+{
+       return of_platform_bus_probe(NULL, mpc85xxrdb_ids, NULL);
+}
+machine_device_initcall(p2020_rdb, mpc85xxrdb_publish_devices);
+
+/*
+ * Called very early, device-tree isn't unflattened
+ */
+static int __init p2020_rdb_probe(void)
+{
+       unsigned long root = of_get_flat_dt_root();
+
+       if (of_flat_dt_is_compatible(root, "fsl,P2020RDB"))
+               return 1;
+       return 0;
+}
+
+define_machine(p2020_rdb) {
+       .name                   = "P2020 RDB",
+       .probe                  = p2020_rdb_probe,
+       .setup_arch             = mpc85xx_rdb_setup_arch,
+       .init_IRQ               = mpc85xx_rdb_pic_init,
+#ifdef CONFIG_PCI
+       .pcibios_fixup_bus      = fsl_pcibios_fixup_bus,
+#endif
+       .get_irq                = mpic_get_irq,
+       .restart                = fsl_rstcr_restart,
+       .calibrate_decr         = generic_calibrate_decr,
+       .progress               = udbg_progress,
+};
index cc27807a8b64ab657a789d0b41ba2b111ef0d952..a5ad1c7794bfaa0183a5a1a8bbfc54c6f1d3c39e 100644 (file)
@@ -267,6 +267,43 @@ arch_initcall(sbc8560_rtc_init);
 
 #endif /* M48T59 */
 
+static __u8 __iomem *brstcr;
+
+static int __init sbc8560_bdrstcr_init(void)
+{
+       struct device_node *np;
+       struct resource res;
+
+       np = of_find_compatible_node(NULL, NULL, "wrs,sbc8560-brstcr");
+       if (np == NULL) {
+               printk(KERN_WARNING "sbc8560: No board specific RSTCR in DTB.\n");
+               return -ENODEV;
+       }
+
+       of_address_to_resource(np, 0, &res);
+
+       printk(KERN_INFO "sbc8560: Found BRSTCR at i/o 0x%x\n", res.start);
+
+       brstcr = ioremap(res.start, res.end - res.start);
+       if(!brstcr)
+               printk(KERN_WARNING "sbc8560: ioremap of brstcr failed.\n");
+
+       of_node_put(np);
+
+       return 0;
+}
+
+arch_initcall(sbc8560_bdrstcr_init);
+
+void sbc8560_rstcr_restart(char * cmd)
+{
+       local_irq_disable();
+       if(brstcr)
+               clrbits8(brstcr, 0x80);
+
+       while(1);
+}
+
 define_machine(sbc8560) {
        .name                   = "SBC8560",
        .probe                  = sbc8560_probe,
@@ -274,7 +311,7 @@ define_machine(sbc8560) {
        .init_IRQ               = sbc8560_pic_init,
        .show_cpuinfo           = sbc8560_show_cpuinfo,
        .get_irq                = mpic_get_irq,
-       .restart                = fsl_rstcr_restart,
+       .restart                = sbc8560_rstcr_restart,
        .calibrate_decr         = generic_calibrate_decr,
        .progress               = udbg_progress,
 };
index 62c592ede641c4a374a7760fd67604cfc9b2f9de..04160a4cc699a163bfabf725bcbfc3fbcd22998f 100644 (file)
@@ -25,7 +25,6 @@
 
 #include <sysdev/fsl_soc.h>
 
-extern volatile unsigned long __secondary_hold_acknowledge;
 extern void __early_start(void);
 
 #define BOOT_ENTRY_ADDR_UPPER  0
@@ -79,47 +78,25 @@ smp_85xx_kick_cpu(int nr)
        pr_debug("waited %d msecs for CPU #%d.\n", n, nr);
 }
 
-static void __init
-smp_85xx_basic_setup(int cpu_nr)
-{
-       /* Clear any pending timer interrupts */
-       mtspr(SPRN_TSR, TSR_ENW | TSR_WIS | TSR_DIS | TSR_FIS);
-
-       /* Enable decrementer interrupt */
-       mtspr(SPRN_TCR, TCR_DIE);
-}
-
 static void __init
 smp_85xx_setup_cpu(int cpu_nr)
 {
        mpic_setup_this_cpu();
-
-       smp_85xx_basic_setup(cpu_nr);
 }
 
 struct smp_ops_t smp_85xx_ops = {
        .kick_cpu = smp_85xx_kick_cpu,
 };
 
-static int __init smp_dummy_probe(void)
-{
-       return NR_CPUS;
-}
-
 void __init mpc85xx_smp_init(void)
 {
        struct device_node *np;
 
-       smp_85xx_ops.message_pass = NULL;
-
        np = of_find_node_by_type(NULL, "open-pic");
        if (np) {
                smp_85xx_ops.probe = smp_mpic_probe;
                smp_85xx_ops.setup_cpu = smp_85xx_setup_cpu;
                smp_85xx_ops.message_pass = smp_mpic_message_pass;
-       } else {
-               smp_85xx_ops.probe = smp_dummy_probe;
-               smp_85xx_ops.setup_cpu = smp_85xx_basic_setup;
        }
 
        if (cpu_has_feature(CPU_FTR_DBELL))
index 2efa052975e61716935c208b440890b19c860015..287f7bd17dd9027067dfdcd96dd26f48a269bbb8 100644 (file)
@@ -102,8 +102,8 @@ static unsigned int gef_ppc9a_get_pcb_rev(void)
 {
        unsigned int reg;
 
-       reg = ioread32(ppc9a_regs);
-       return (reg >> 8) & 0xff;
+       reg = ioread32be(ppc9a_regs);
+       return (reg >> 16) & 0xff;
 }
 
 /* Return the board (software) revision */
@@ -111,8 +111,8 @@ static unsigned int gef_ppc9a_get_board_rev(void)
 {
        unsigned int reg;
 
-       reg = ioread32(ppc9a_regs);
-       return (reg >> 16) & 0xff;
+       reg = ioread32be(ppc9a_regs);
+       return (reg >> 8) & 0xff;
 }
 
 /* Return the FPGA revision */
@@ -120,8 +120,26 @@ static unsigned int gef_ppc9a_get_fpga_rev(void)
 {
        unsigned int reg;
 
-       reg = ioread32(ppc9a_regs);
-       return (reg >> 24) & 0xf;
+       reg = ioread32be(ppc9a_regs);
+       return reg & 0xf;
+}
+
+/* Return VME Geographical Address */
+static unsigned int gef_ppc9a_get_vme_geo_addr(void)
+{
+       unsigned int reg;
+
+       reg = ioread32be(ppc9a_regs + 0x4);
+       return reg & 0x1f;
+}
+
+/* Return VME System Controller Status */
+static unsigned int gef_ppc9a_get_vme_is_syscon(void)
+{
+       unsigned int reg;
+
+       reg = ioread32be(ppc9a_regs + 0x4);
+       return (reg >> 9) & 0x1;
 }
 
 static void gef_ppc9a_show_cpuinfo(struct seq_file *m)
@@ -131,10 +149,15 @@ static void gef_ppc9a_show_cpuinfo(struct seq_file *m)
        seq_printf(m, "Vendor\t\t: GE Fanuc Intelligent Platforms\n");
 
        seq_printf(m, "Revision\t: %u%c\n", gef_ppc9a_get_pcb_rev(),
-               ('A' + gef_ppc9a_get_board_rev() - 1));
+               ('A' + gef_ppc9a_get_board_rev()));
        seq_printf(m, "FPGA Revision\t: %u\n", gef_ppc9a_get_fpga_rev());
 
        seq_printf(m, "SVR\t\t: 0x%x\n", svid);
+
+       seq_printf(m, "VME geo. addr\t: %u\n", gef_ppc9a_get_vme_geo_addr());
+
+       seq_printf(m, "VME syscon\t: %s\n",
+               gef_ppc9a_get_vme_is_syscon() ? "yes" : "no");
 }
 
 static void __init gef_ppc9a_nec_fixup(struct pci_dev *pdev)
index 66327024a6a6bd73a7597e2220f73600ff29187a..2aa69a69bcc8b3147e7c16b82b5a74ea35777316 100644 (file)
@@ -105,7 +105,8 @@ mpc86xx_hpcn_setup_arch(void)
 #ifdef CONFIG_SWIOTLB
        if (lmb_end_of_DRAM() > max) {
                ppc_swiotlb_enable = 1;
-               set_pci_dma_ops(&swiotlb_pci_dma_ops);
+               set_pci_dma_ops(&swiotlb_dma_ops);
+               ppc_md.pci_dma_dev_setup = pci_dma_dev_setup_swiotlb;
        }
 #endif
 }
index d84bbb508ee7650719857bd6aaf1ee6c2f7ecee8..eacea0e3fcc88b5d42f13bed9e75ca4b589f2db0 100644 (file)
@@ -27,7 +27,6 @@
 #include "mpc86xx.h"
 
 extern void __secondary_start_mpc86xx(void);
-extern unsigned long __secondary_hold_acknowledge;
 
 #define MCM_PORT_CONFIG_OFFSET 0x10
 
index 61187bec75062e0f4656b0399cba3bc5bb492fed..9efc8bda01b483b0e4bf651cea628ec5d966d8c7 100644 (file)
@@ -57,15 +57,35 @@ config E200
 
 endchoice
 
-config PPC_BOOK3S_64
-       def_bool y
+choice
+       prompt "Processor Type"
        depends on PPC64
+       help
+         There are two families of 64 bit PowerPC chips supported.
+         The most common ones are the desktop and server CPUs
+         (POWER3, RS64, POWER4, POWER5, POWER5+, POWER6, ...)
+
+         The other are the "embedded" processors compliant with the
+         "Book 3E" variant of the architecture
+
+config PPC_BOOK3S_64
+       bool "Server processors"
        select PPC_FPU
 
+config PPC_BOOK3E_64
+       bool "Embedded processors"
+       select PPC_FPU # Make it a choice ?
+
+endchoice
+
 config PPC_BOOK3S
        def_bool y
        depends on PPC_BOOK3S_32 || PPC_BOOK3S_64
 
+config PPC_BOOK3E
+       def_bool y
+       depends on PPC_BOOK3E_64
+
 config POWER4_ONLY
        bool "Optimize for POWER4"
        depends on PPC64 && PPC_BOOK3S
@@ -125,7 +145,7 @@ config 4xx
 
 config BOOKE
        bool
-       depends on E200 || E500 || 44x
+       depends on E200 || E500 || 44x || PPC_BOOK3E
        default y
 
 config FSL_BOOKE
@@ -223,9 +243,17 @@ config PPC_MMU_NOHASH
        def_bool y
        depends on !PPC_STD_MMU
 
+config PPC_MMU_NOHASH_32
+       def_bool y
+       depends on PPC_MMU_NOHASH && PPC32
+
+config PPC_MMU_NOHASH_64
+       def_bool y
+       depends on PPC_MMU_NOHASH && PPC64
+
 config PPC_BOOK3E_MMU
        def_bool y
-       depends on FSL_BOOKE
+       depends on FSL_BOOKE || PPC_BOOK3E
 
 config PPC_MM_SLICES
        bool
@@ -257,7 +285,7 @@ config PPC_PERF_CTRS
          This enables the powerpc-specific perf_counter back-end.
 
 config SMP
-       depends on PPC_STD_MMU || FSL_BOOKE
+       depends on PPC_BOOK3S || PPC_BOOK3E || FSL_BOOKE
        bool "Symmetric multi-processing support"
        ---help---
          This enables support for systems with more than one CPU. If you have
index 443035366c128575b61ecca5c2f57b96f203ce1c..9290a7a442d0af9d2736a81e4431ffd367df92b0 100644 (file)
@@ -110,13 +110,16 @@ void __init amigaone_init_IRQ(void)
        irq_set_default_host(i8259_get_host());
 }
 
-void __init amigaone_init(void)
+static int __init request_isa_regions(void)
 {
        request_region(0x00, 0x20, "dma1");
        request_region(0x40, 0x20, "timer");
        request_region(0x80, 0x10, "dma page reg");
        request_region(0xc0, 0x20, "dma2");
+
+       return 0;
 }
+machine_device_initcall(amigaone, request_isa_regions);
 
 void amigaone_restart(char *cmd)
 {
@@ -161,7 +164,6 @@ define_machine(amigaone) {
        .name                   = "AmigaOne",
        .probe                  = amigaone_probe,
        .setup_arch             = amigaone_setup_arch,
-       .init                   = amigaone_init,
        .show_cpuinfo           = amigaone_show_cpuinfo,
        .init_IRQ               = amigaone_init_IRQ,
        .restart                = amigaone_restart,
index 50f17bdd3c163c39187e07fd756f4bfc113e5e2c..48cd7d2e1b75a54a451093121d5348fc0edbccaf 100644 (file)
@@ -80,13 +80,6 @@ config SPU_FS_64K_LS
          uses 4K pages. This can improve performances of applications
          using multiple SPEs by lowering the TLB pressure on them.
 
-config SPU_TRACE
-       tristate "SPU event tracing support"
-       depends on SPU_FS && MARKERS
-       help
-         This option allows reading a trace of spu-related events through
-         the sputrace file in procfs.
-
 config SPU_BASE
        bool
        default n
index 07c234f6b2b686835f0de343a4a06522094da94f..e53845579770fc6d259c979e74ba8d1b573b171c 100644 (file)
@@ -80,8 +80,7 @@ static void celleb_show_cpuinfo(struct seq_file *m)
 
 static int __init celleb_machine_type_hack(char *ptr)
 {
-       strncpy(celleb_machine_type, ptr, sizeof(celleb_machine_type));
-       celleb_machine_type[sizeof(celleb_machine_type)-1] = 0;
+       strlcpy(celleb_machine_type, ptr, sizeof(celleb_machine_type));
        return 0;
 }
 
index 5b34fc211f35bb9b4f4ac5d3fdded3293f6c044c..416db17eb18f08335ac6306abe933ed2d81df29b 100644 (file)
@@ -642,7 +642,7 @@ static int dma_fixed_dma_supported(struct device *dev, u64 mask)
 
 static int dma_set_mask_and_switch(struct device *dev, u64 dma_mask);
 
-struct dma_mapping_ops dma_iommu_fixed_ops = {
+struct dma_map_ops dma_iommu_fixed_ops = {
        .alloc_coherent = dma_fixed_alloc_coherent,
        .free_coherent  = dma_fixed_free_coherent,
        .map_sg         = dma_fixed_map_sg,
index bc97fada48c664662ee59808c9f6424820d42f6a..f774530075b749122424549c2c4009a32737cd0f 100644 (file)
@@ -58,8 +58,6 @@
  */
 static cpumask_t of_spin_map;
 
-extern void generic_secondary_smp_init(unsigned long);
-
 /**
  * smp_startup_cpu() - start the given cpu
  *
index 99610a6361f28133e1eff58c32d4e91455afa92f..b93f877ba5046bded97844766dee257534194b1b 100644 (file)
@@ -4,7 +4,8 @@ spufs-y += inode.o file.o context.o syscalls.o coredump.o
 spufs-y += sched.o backing_ops.o hw_ops.o run.o gang.o
 spufs-y += switch.o fault.o lscsa_alloc.o
 
-obj-$(CONFIG_SPU_TRACE)        += sputrace.o
+# magic for the trace events
+CFLAGS_sched.o := -I$(src)
 
 # Rules to build switch.o with the help of SPU tool chain
 SPU_CROSS      := spu-
index db5398c0339f4a1bbb6bccaccf59c4cc97c6b9a3..0c87bcd2452aa6326d60c8fa4deed828d5624e03 100644 (file)
@@ -28,6 +28,7 @@
 #include <asm/spu.h>
 #include <asm/spu_csa.h>
 #include "spufs.h"
+#include "sputrace.h"
 
 
 atomic_t nr_spu_contexts = ATOMIC_INIT(0);
index d6a519e6e1c1a0682efcb077e79178e0f1f425ce..ab8aef9bb8ea9120dc9e3ce4ea567a96983e5e81 100644 (file)
@@ -38,6 +38,7 @@
 #include <asm/uaccess.h>
 
 #include "spufs.h"
+#include "sputrace.h"
 
 #define SPUFS_MMAP_4K (PAGE_SIZE == 0x1000)
 
index f085369301b13ced53dce0b48bd46f8f9ae9eb19..bb5b77c66d05240ad763c32dd6589ae227940d96 100644 (file)
@@ -47,6 +47,8 @@
 #include <asm/spu_csa.h>
 #include <asm/spu_priv1.h>
 #include "spufs.h"
+#define CREATE_TRACE_POINTS
+#include "sputrace.h"
 
 struct spu_prio_array {
        DECLARE_BITMAP(bitmap, MAX_PRIO);
index ae31573bea4a3027377d9f13f77e1508e9cb30a1..c448bac655184f5eba836d678aa4b93827347e68 100644 (file)
@@ -373,9 +373,4 @@ extern void spu_free_lscsa(struct spu_state *csa);
 extern void spuctx_switch_state(struct spu_context *ctx,
                enum spu_utilization_state new_state);
 
-#define spu_context_trace(name, ctx, spu) \
-       trace_mark(name, "ctx %p spu %p", ctx, spu);
-#define spu_context_nospu_trace(name, ctx) \
-       trace_mark(name, "ctx %p", ctx);
-
 #endif
diff --git a/arch/powerpc/platforms/cell/spufs/sputrace.c b/arch/powerpc/platforms/cell/spufs/sputrace.c
deleted file mode 100644 (file)
index d0b1f3f..0000000
+++ /dev/null
@@ -1,272 +0,0 @@
-/*
- * Copyright (C) 2007 IBM Deutschland Entwicklung GmbH
- *     Released under GPL v2.
- *
- * Partially based on net/ipv4/tcp_probe.c.
- *
- * Simple tracing facility for spu contexts.
- */
-#include <linux/sched.h>
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/marker.h>
-#include <linux/proc_fs.h>
-#include <linux/wait.h>
-#include <asm/atomic.h>
-#include <asm/uaccess.h>
-#include "spufs.h"
-
-struct spu_probe {
-       const char *name;
-       const char *format;
-       marker_probe_func *probe_func;
-};
-
-struct sputrace {
-       ktime_t tstamp;
-       int owner_tid; /* owner */
-       int curr_tid;
-       const char *name;
-       int number;
-};
-
-static int bufsize __read_mostly = 16384;
-MODULE_PARM_DESC(bufsize, "Log buffer size (number of records)");
-module_param(bufsize, int, 0);
-
-
-static DEFINE_SPINLOCK(sputrace_lock);
-static DECLARE_WAIT_QUEUE_HEAD(sputrace_wait);
-static ktime_t sputrace_start;
-static unsigned long sputrace_head, sputrace_tail;
-static struct sputrace *sputrace_log;
-static int sputrace_logging;
-
-static int sputrace_used(void)
-{
-       return (sputrace_head - sputrace_tail) % bufsize;
-}
-
-static inline int sputrace_avail(void)
-{
-       return bufsize - sputrace_used();
-}
-
-static int sputrace_sprint(char *tbuf, int n)
-{
-       const struct sputrace *t = sputrace_log + sputrace_tail % bufsize;
-       struct timespec tv =
-               ktime_to_timespec(ktime_sub(t->tstamp, sputrace_start));
-
-       return snprintf(tbuf, n,
-               "[%lu.%09lu] %d: %s (ctxthread = %d, spu = %d)\n",
-               (unsigned long) tv.tv_sec,
-               (unsigned long) tv.tv_nsec,
-               t->curr_tid,
-               t->name,
-               t->owner_tid,
-               t->number);
-}
-
-static ssize_t sputrace_read(struct file *file, char __user *buf,
-               size_t len, loff_t *ppos)
-{
-       int error = 0, cnt = 0;
-
-       if (!buf || len < 0)
-               return -EINVAL;
-
-       while (cnt < len) {
-               char tbuf[128];
-               int width;
-
-               /* If we have data ready to return, don't block waiting
-                * for more */
-               if (cnt > 0 && sputrace_used() == 0)
-                       break;
-
-               error = wait_event_interruptible(sputrace_wait,
-                                                sputrace_used() > 0);
-               if (error)
-                       break;
-
-               spin_lock(&sputrace_lock);
-               if (sputrace_head == sputrace_tail) {
-                       spin_unlock(&sputrace_lock);
-                       continue;
-               }
-
-               width = sputrace_sprint(tbuf, sizeof(tbuf));
-               if (width < len)
-                       sputrace_tail = (sputrace_tail + 1) % bufsize;
-               spin_unlock(&sputrace_lock);
-
-               if (width >= len)
-                       break;
-
-               error = copy_to_user(buf + cnt, tbuf, width);
-               if (error)
-                       break;
-               cnt += width;
-       }
-
-       return cnt == 0 ? error : cnt;
-}
-
-static int sputrace_open(struct inode *inode, struct file *file)
-{
-       int rc;
-
-       spin_lock(&sputrace_lock);
-       if (sputrace_logging) {
-               rc = -EBUSY;
-               goto out;
-       }
-
-       sputrace_logging = 1;
-       sputrace_head = sputrace_tail = 0;
-       sputrace_start = ktime_get();
-       rc = 0;
-
-out:
-       spin_unlock(&sputrace_lock);
-       return rc;
-}
-
-static int sputrace_release(struct inode *inode, struct file *file)
-{
-       spin_lock(&sputrace_lock);
-       sputrace_logging = 0;
-       spin_unlock(&sputrace_lock);
-       return 0;
-}
-
-static const struct file_operations sputrace_fops = {
-       .owner   = THIS_MODULE,
-       .open    = sputrace_open,
-       .read    = sputrace_read,
-       .release = sputrace_release,
-};
-
-static void sputrace_log_item(const char *name, struct spu_context *ctx,
-               struct spu *spu)
-{
-       spin_lock(&sputrace_lock);
-
-       if (!sputrace_logging) {
-               spin_unlock(&sputrace_lock);
-               return;
-       }
-
-       if (sputrace_avail() > 1) {
-               struct sputrace *t = sputrace_log + sputrace_head;
-
-               t->tstamp = ktime_get();
-               t->owner_tid = ctx->tid;
-               t->name = name;
-               t->curr_tid = current->pid;
-               t->number = spu ? spu->number : -1;
-
-               sputrace_head = (sputrace_head + 1) % bufsize;
-       } else {
-               printk(KERN_WARNING
-                      "sputrace: lost samples due to full buffer.\n");
-       }
-       spin_unlock(&sputrace_lock);
-
-       wake_up(&sputrace_wait);
-}
-
-static void spu_context_event(void *probe_private, void *call_data,
-               const char *format, va_list *args)
-{
-       struct spu_probe *p = probe_private;
-       struct spu_context *ctx;
-       struct spu *spu;
-
-       ctx = va_arg(*args, struct spu_context *);
-       spu = va_arg(*args, struct spu *);
-
-       sputrace_log_item(p->name, ctx, spu);
-}
-
-static void spu_context_nospu_event(void *probe_private, void *call_data,
-               const char *format, va_list *args)
-{
-       struct spu_probe *p = probe_private;
-       struct spu_context *ctx;
-
-       ctx = va_arg(*args, struct spu_context *);
-
-       sputrace_log_item(p->name, ctx, NULL);
-}
-
-struct spu_probe spu_probes[] = {
-       { "spu_bind_context__enter", "ctx %p spu %p", spu_context_event },
-       { "spu_unbind_context__enter", "ctx %p spu %p", spu_context_event },
-       { "spu_get_idle__enter", "ctx %p", spu_context_nospu_event },
-       { "spu_get_idle__found", "ctx %p spu %p", spu_context_event },
-       { "spu_get_idle__not_found", "ctx %p", spu_context_nospu_event },
-       { "spu_find_victim__enter", "ctx %p", spu_context_nospu_event },
-       { "spusched_tick__preempt", "ctx %p spu %p", spu_context_event },
-       { "spusched_tick__newslice", "ctx %p", spu_context_nospu_event },
-       { "spu_yield__enter", "ctx %p", spu_context_nospu_event },
-       { "spu_deactivate__enter", "ctx %p", spu_context_nospu_event },
-       { "__spu_deactivate__unload", "ctx %p spu %p", spu_context_event },
-       { "spufs_ps_fault__enter", "ctx %p", spu_context_nospu_event },
-       { "spufs_ps_fault__sleep", "ctx %p", spu_context_nospu_event },
-       { "spufs_ps_fault__wake", "ctx %p spu %p", spu_context_event },
-       { "spufs_ps_fault__insert", "ctx %p spu %p", spu_context_event },
-       { "spu_acquire_saved__enter", "ctx %p", spu_context_nospu_event },
-       { "destroy_spu_context__enter", "ctx %p", spu_context_nospu_event },
-       { "spufs_stop_callback__enter", "ctx %p spu %p", spu_context_event },
-};
-
-static int __init sputrace_init(void)
-{
-       struct proc_dir_entry *entry;
-       int i, error = -ENOMEM;
-
-       sputrace_log = kcalloc(bufsize, sizeof(struct sputrace), GFP_KERNEL);
-       if (!sputrace_log)
-               goto out;
-
-       entry = proc_create("sputrace", S_IRUSR, NULL, &sputrace_fops);
-       if (!entry)
-               goto out_free_log;
-
-       for (i = 0; i < ARRAY_SIZE(spu_probes); i++) {
-               struct spu_probe *p = &spu_probes[i];
-
-               error = marker_probe_register(p->name, p->format,
-                                             p->probe_func, p);
-               if (error)
-                       printk(KERN_INFO "Unable to register probe %s\n",
-                                       p->name);
-       }
-
-       return 0;
-
-out_free_log:
-       kfree(sputrace_log);
-out:
-       return -ENOMEM;
-}
-
-static void __exit sputrace_exit(void)
-{
-       int i;
-
-       for (i = 0; i < ARRAY_SIZE(spu_probes); i++)
-               marker_probe_unregister(spu_probes[i].name,
-                       spu_probes[i].probe_func, &spu_probes[i]);
-
-       remove_proc_entry("sputrace", NULL);
-       kfree(sputrace_log);
-       marker_synchronize_unregister();
-}
-
-module_init(sputrace_init);
-module_exit(sputrace_exit);
-
-MODULE_LICENSE("GPL");
diff --git a/arch/powerpc/platforms/cell/spufs/sputrace.h b/arch/powerpc/platforms/cell/spufs/sputrace.h
new file mode 100644 (file)
index 0000000..db2656a
--- /dev/null
@@ -0,0 +1,39 @@
+#if !defined(_TRACE_SPUFS_H) || defined(TRACE_HEADER_MULTI_READ)
+#define _TRACE_SPUFS_H
+
+#include <linux/tracepoint.h>
+
+#undef TRACE_SYSTEM
+#define TRACE_SYSTEM spufs
+
+TRACE_EVENT(spufs_context,
+       TP_PROTO(struct spu_context *ctx, struct spu *spu, const char *name),
+       TP_ARGS(ctx, spu, name),
+
+       TP_STRUCT__entry(
+               __field(const char *, name)
+               __field(int, owner_tid)
+               __field(int, number)
+       ),
+
+       TP_fast_assign(
+               __entry->name = name;
+               __entry->owner_tid = ctx->tid;
+               __entry->number = spu ? spu->number : -1;
+       ),
+
+       TP_printk("%s (ctxthread = %d, spu = %d)",
+               __entry->name, __entry->owner_tid, __entry->number)
+);
+
+#define spu_context_trace(name, ctx, spu) \
+       trace_spufs_context(ctx, spu, __stringify(name))
+#define spu_context_nospu_trace(name, ctx) \
+       trace_spufs_context(ctx, NULL, __stringify(name))
+
+#endif /* _TRACE_SPUFS_H */
+
+#undef TRACE_INCLUDE_PATH
+#define TRACE_INCLUDE_PATH .
+#define TRACE_INCLUDE_FILE sputrace
+#include <trace/define_trace.h>
index 2f581521eb9ba9b2e93707eee069cd18a9e322e1..5369653dcf6a97c5ee0af420a1d1451433d5c996 100644 (file)
@@ -47,7 +47,7 @@ system_reset_iSeries:
        LOAD_REG_ADDR(r13, paca)
        mulli   r0,r23,PACA_SIZE
        add     r13,r13,r0
-       mtspr   SPRN_SPRG3,r13          /* Save it away for the future */
+       mtspr   SPRN_SPRG_PACA,r13      /* Save it away for the future */
        mfmsr   r24
        ori     r24,r24,MSR_RI
        mtmsrd  r24                     /* RI on */
@@ -116,7 +116,7 @@ iSeries_secondary_smp_loop:
 #endif /* CONFIG_SMP */
        li      r0,-1                   /* r0=-1 indicates a Hypervisor call */
        sc                              /* Invoke the hypervisor via a system call */
-       mfspr   r13,SPRN_SPRG3          /* Put r13 back ???? */
+       mfspr   r13,SPRN_SPRG_PACA      /* Put r13 back ???? */
        b       2b                      /* If SMP not configured, secondaries
                                         * loop forever */
 
@@ -126,34 +126,45 @@ iSeries_secondary_smp_loop:
 
        .globl data_access_iSeries
 data_access_iSeries:
-       mtspr   SPRN_SPRG1,r13
+       mtspr   SPRN_SPRG_SCRATCH0,r13
 BEGIN_FTR_SECTION
-       mtspr   SPRN_SPRG2,r12
-       mfspr   r13,SPRN_DAR
-       mfspr   r12,SPRN_DSISR
-       srdi    r13,r13,60
-       rlwimi  r13,r12,16,0x20
-       mfcr    r12
-       cmpwi   r13,0x2c
+       mfspr   r13,SPRN_SPRG_PACA
+       std     r9,PACA_EXSLB+EX_R9(r13)
+       std     r10,PACA_EXSLB+EX_R10(r13)
+       mfspr   r10,SPRN_DAR
+       mfspr   r9,SPRN_DSISR
+       srdi    r10,r10,60
+       rlwimi  r10,r9,16,0x20
+       mfcr    r9
+       cmpwi   r10,0x2c
        beq     .do_stab_bolted_iSeries
-       mtcrf   0x80,r12
-       mfspr   r12,SPRN_SPRG2
-END_FTR_SECTION_IFCLR(CPU_FTR_SLB)
+       ld      r10,PACA_EXSLB+EX_R10(r13)
+       std     r11,PACA_EXGEN+EX_R11(r13)
+       ld      r11,PACA_EXSLB+EX_R9(r13)
+       std     r12,PACA_EXGEN+EX_R12(r13)
+       mfspr   r12,SPRN_SPRG_SCRATCH0
+       std     r10,PACA_EXGEN+EX_R10(r13)
+       std     r11,PACA_EXGEN+EX_R9(r13)
+       std     r12,PACA_EXGEN+EX_R13(r13)
+       EXCEPTION_PROLOG_ISERIES_1
+FTR_SECTION_ELSE
        EXCEPTION_PROLOG_1(PACA_EXGEN)
        EXCEPTION_PROLOG_ISERIES_1
+ALT_FTR_SECTION_END_IFCLR(CPU_FTR_SLB)
        b       data_access_common
 
 .do_stab_bolted_iSeries:
-       mtcrf   0x80,r12
-       mfspr   r12,SPRN_SPRG2
-       EXCEPTION_PROLOG_1(PACA_EXSLB)
+       std     r11,PACA_EXSLB+EX_R11(r13)
+       std     r12,PACA_EXSLB+EX_R12(r13)
+       mfspr   r10,SPRN_SPRG_SCRATCH0
+       std     r10,PACA_EXSLB+EX_R13(r13)
        EXCEPTION_PROLOG_ISERIES_1
        b       .do_stab_bolted
 
        .globl  data_access_slb_iSeries
 data_access_slb_iSeries:
-       mtspr   SPRN_SPRG1,r13          /* save r13 */
-       mfspr   r13,SPRN_SPRG3          /* get paca address into r13 */
+       mtspr   SPRN_SPRG_SCRATCH0,r13  /* save r13 */
+       mfspr   r13,SPRN_SPRG_PACA      /* get paca address into r13 */
        std     r3,PACA_EXSLB+EX_R3(r13)
        mfspr   r3,SPRN_DAR
        std     r9,PACA_EXSLB+EX_R9(r13)
@@ -165,7 +176,7 @@ data_access_slb_iSeries:
        std     r10,PACA_EXSLB+EX_R10(r13)
        std     r11,PACA_EXSLB+EX_R11(r13)
        std     r12,PACA_EXSLB+EX_R12(r13)
-       mfspr   r10,SPRN_SPRG1
+       mfspr   r10,SPRN_SPRG_SCRATCH0
        std     r10,PACA_EXSLB+EX_R13(r13)
        ld      r12,PACALPPACAPTR(r13)
        ld      r12,LPPACASRR1(r12)
@@ -175,8 +186,8 @@ data_access_slb_iSeries:
 
        .globl  instruction_access_slb_iSeries
 instruction_access_slb_iSeries:
-       mtspr   SPRN_SPRG1,r13          /* save r13 */
-       mfspr   r13,SPRN_SPRG3          /* get paca address into r13 */
+       mtspr   SPRN_SPRG_SCRATCH0,r13  /* save r13 */
+       mfspr   r13,SPRN_SPRG_PACA      /* get paca address into r13 */
        std     r3,PACA_EXSLB+EX_R3(r13)
        ld      r3,PACALPPACAPTR(r13)
        ld      r3,LPPACASRR0(r3)       /* get SRR0 value */
@@ -189,7 +200,7 @@ instruction_access_slb_iSeries:
        std     r10,PACA_EXSLB+EX_R10(r13)
        std     r11,PACA_EXSLB+EX_R11(r13)
        std     r12,PACA_EXSLB+EX_R12(r13)
-       mfspr   r10,SPRN_SPRG1
+       mfspr   r10,SPRN_SPRG_SCRATCH0
        std     r10,PACA_EXSLB+EX_R13(r13)
        ld      r12,PACALPPACAPTR(r13)
        ld      r12,LPPACASRR1(r12)
@@ -200,7 +211,7 @@ slb_miss_user_iseries:
        std     r10,PACA_EXGEN+EX_R10(r13)
        std     r11,PACA_EXGEN+EX_R11(r13)
        std     r12,PACA_EXGEN+EX_R12(r13)
-       mfspr   r10,SPRG1
+       mfspr   r10,SPRG_SCRATCH0
        ld      r11,PACA_EXSLB+EX_R9(r13)
        ld      r12,PACA_EXSLB+EX_R3(r13)
        std     r10,PACA_EXGEN+EX_R13(r13)
@@ -221,7 +232,7 @@ slb_miss_user_iseries:
        .globl  system_call_iSeries
 system_call_iSeries:
        mr      r9,r13
-       mfspr   r13,SPRN_SPRG3
+       mfspr   r13,SPRN_SPRG_PACA
        EXCEPTION_PROLOG_ISERIES_1
        b       system_call_common
 
index ced45a8fa1aa40c99736c13f00d9d869dd10ee37..bae3fba5ad8efdedd24bd7613ad45fe3cd47fc36 100644 (file)
@@ -24,7 +24,7 @@
  *  as published by the Free Software Foundation; either version
  *  2 of the License, or (at your option) any later version.
  */
-#include <asm/exception.h>
+#include <asm/exception-64s.h>
 
 #define EXCEPTION_PROLOG_ISERIES_1                                     \
        mfmsr   r10;                                                    \
@@ -38,7 +38,7 @@
        .globl label##_iSeries;                                         \
 label##_iSeries:                                                       \
        HMT_MEDIUM;                                                     \
-       mtspr   SPRN_SPRG1,r13;         /* save r13 */                  \
+       mtspr   SPRN_SPRG_SCRATCH0,r13; /* save r13 */                  \
        EXCEPTION_PROLOG_1(area);                                       \
        EXCEPTION_PROLOG_ISERIES_1;                                     \
        b       label##_common
@@ -47,7 +47,7 @@ label##_iSeries:                                                      \
        .globl label##_iSeries;                                         \
 label##_iSeries:                                                       \
        HMT_MEDIUM;                                                     \
-       mtspr   SPRN_SPRG1,r13;         /* save r13 */                  \
+       mtspr   SPRN_SPRG_SCRATCH0,r13; /* save r13 */                  \
        EXCEPTION_PROLOG_1(PACA_EXGEN);                                 \
        lbz     r10,PACASOFTIRQEN(r13);                                 \
        cmpwi   0,r10,0;                                                \
index fef4d5150517474460aa5c97bea5efb5c32254f9..0d9343df35bc7658e54cd823eef7660631aa1003 100644 (file)
@@ -872,7 +872,7 @@ static int proc_mf_dump_cmdline(char *page, char **start, off_t off,
                count = 256 - off;
 
        dma_addr = iseries_hv_map(page, off + count, DMA_FROM_DEVICE);
-       if (dma_mapping_error(NULL, dma_addr))
+       if (dma_addr == DMA_ERROR_CODE)
                return -ENOMEM;
        memset(page, 0, off + count);
        memset(&vsp_cmd, 0, sizeof(vsp_cmd));
index 43911d8b0206bb9e3d423ca4e9c12901634ad6b8..75b296bc51af7afe259d2cc0c70653c0438a01f1 100644 (file)
@@ -90,7 +90,7 @@ machine_late_initcall(pasemi, pasemi_idle_init);
 static int __init idle_param(char *p)
 {
        int i;
-       for (i = 0; i < sizeof(modes)/sizeof(struct sleep_mode); i++) {
+       for (i = 0; i < ARRAY_SIZE(modes); i++) {
                if (!strcmp(modes[i].name, p)) {
                        current_mode = i;
                        break;
index 65c585b8b00df8300661b52922518f19395f1b96..08d94e4cedd359909782c71b3b8219409745fc5b 100644 (file)
  */
 #undef DEBUG_FREQ
 
-/*
- * There is a problem with the core cpufreq code on SMP kernels,
- * it won't recalculate the Bogomips properly
- */
-#ifdef CONFIG_SMP
-#warning "WARNING, CPUFREQ not recommended on SMP kernels"
-#endif
-
 extern void low_choose_7447a_dfs(int dfs);
 extern void low_choose_750fx_pll(int pll);
 extern void low_sleep_handler(void);
index e6c0040ee79752c9721d5b69fbb29dd057de42ef..fbc9bbd74dbdc9337ca2880f1d50a590d8f9f3a1 100644 (file)
@@ -2419,13 +2419,13 @@ static int __init probe_motherboard(void)
        dt = of_find_node_by_name(NULL, "device-tree");
        if (dt != NULL)
                model = of_get_property(dt, "model", NULL);
-       for(i=0; model && i<(sizeof(pmac_mb_defs)/sizeof(struct pmac_mb_def)); i++) {
+       for(i=0; model && i<ARRAY_SIZE(pmac_mb_defs); i++) {
            if (strcmp(model, pmac_mb_defs[i].model_string) == 0) {
                pmac_mb = pmac_mb_defs[i];
                goto found;
            }
        }
-       for(i=0; i<(sizeof(pmac_mb_defs)/sizeof(struct pmac_mb_def)); i++) {
+       for(i=0; i<ARRAY_SIZE(pmac_mb_defs); i++) {
            if (machine_is_compatible(pmac_mb_defs[i].model_string)) {
                pmac_mb = pmac_mb_defs[i];
                goto found;
@@ -2589,9 +2589,16 @@ static void __init probe_uninorth(void)
        if (address == 0)
                return;
        uninorth_base = ioremap(address, 0x40000);
+       if (uninorth_base == NULL)
+               return;
        uninorth_rev = in_be32(UN_REG(UNI_N_VERSION));
-       if (uninorth_maj == 3 || uninorth_maj == 4)
+       if (uninorth_maj == 3 || uninorth_maj == 4) {
                u3_ht_base = ioremap(address + U3_HT_CONFIG_BASE, 0x1000);
+               if (u3_ht_base == NULL) {
+                       iounmap(uninorth_base);
+                       return;
+               }
+       }
 
        printk(KERN_INFO "Found %s memory controller & host bridge"
               " @ 0x%08x revision: 0x%02x\n", uninorth_maj == 3 ? "U3" :
index 04cdd32624d40b08ffac327f44e9d1124b58e41f..e81403b245b5d848f237ebe4aaeb17f00dc322df 100644 (file)
@@ -1286,3 +1286,64 @@ static void fixup_k2_sata(struct pci_dev* dev)
 }
 DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_SERVERWORKS, 0x0240, fixup_k2_sata);
 
+/*
+ * On U4 (aka CPC945) the PCIe root complex "P2P" bridge resource ranges aren't
+ * configured by the firmware. The bridge itself seems to ignore them but it
+ * causes problems with Linux which then re-assigns devices below the bridge,
+ * thus changing addresses of those devices from what was in the device-tree,
+ * which sucks when those are video cards using offb
+ *
+ * We could just mark it transparent but I prefer fixing up the resources to
+ * properly show what's going on here, as I have some doubts about having them
+ * badly configured potentially being an issue for DMA.
+ *
+ * We leave PIO alone, it seems to be fine
+ *
+ * Oh and there's another funny bug. The OF properties advertize the region
+ * 0xf1000000..0xf1ffffff as being forwarded as memory space. But that's
+ * actually not true, this region is the memory mapped config space. So we
+ * also need to filter it out or we'll map things in the wrong place.
+ */
+static void fixup_u4_pcie(struct pci_dev* dev)
+{
+       struct pci_controller *host = pci_bus_to_host(dev->bus);
+       struct resource *region = NULL;
+       u32 reg;
+       int i;
+
+       /* Only do that on PowerMac */
+       if (!machine_is(powermac))
+               return;
+
+       /* Find the largest MMIO region */
+       for (i = 0; i < 3; i++) {
+               struct resource *r = &host->mem_resources[i];
+               if (!(r->flags & IORESOURCE_MEM))
+                       continue;
+               /* Skip the 0xf0xxxxxx..f2xxxxxx regions, we know they
+                * are reserved by HW for other things
+                */
+               if (r->start >= 0xf0000000 && r->start < 0xf3000000)
+                       continue;
+               if (!region || (r->end - r->start) >
+                   (region->end - region->start))
+                       region = r;
+       }
+       /* Nothing found, bail */
+       if (region == 0)
+               return;
+
+       /* Print things out */
+       printk(KERN_INFO "PCI: Fixup U4 PCIe bridge range: %pR\n", region);
+
+       /* Fixup bridge config space. We know it's a Mac, resource aren't
+        * offset so let's just blast them as-is. We also know that they
+        * fit in 32 bits
+        */
+       reg = ((region->start >> 16) & 0xfff0) | (region->end & 0xfff00000);
+       pci_write_config_dword(dev, PCI_MEMORY_BASE, reg);
+       pci_write_config_dword(dev, PCI_PREF_BASE_UPPER32, 0);
+       pci_write_config_dword(dev, PCI_PREF_LIMIT_UPPER32, 0);
+       pci_write_config_dword(dev, PCI_PREF_MEMORY_BASE, 0);
+}
+DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_APPLE, PCI_DEVICE_ID_APPLE_U4_PCIE, fixup_u4_pcie);
index 6d4da7b46b419a751891e74b02554d6b7e0a89e1..937a38e73178c0c7168bf27b75913e69c3d2f9c0 100644 (file)
@@ -408,7 +408,7 @@ static void __init smp_psurge_setup_cpu(int cpu_nr)
        /* reset the entry point so if we get another intr we won't
         * try to startup again */
        out_be32(psurge_start, 0x100);
-       if (setup_irq(30, &psurge_irqaction))
+       if (setup_irq(irq_create_mapping(NULL, 30), &psurge_irqaction))
                printk(KERN_ERR "Couldn't get primary IPI interrupt");
 }
 
index 846eb8b57fd1dbb80fca175bb2813e97f0e7ef49..189a25b80735cb7c6731b3ce5d7ab9cd24ca605e 100644 (file)
@@ -23,8 +23,8 @@
 #include <linux/memory_hotplug.h>
 #include <linux/lmb.h>
 
+#include <asm/cell-regs.h>
 #include <asm/firmware.h>
-#include <asm/iommu.h>
 #include <asm/prom.h>
 #include <asm/udbg.h>
 #include <asm/lv1call.h>
index f6e04bcc70ef8a1ede3735a6ebd9804302537ef6..51ffde40af2b7d5c9ba41fee997c4790073d8035 100644 (file)
@@ -37,7 +37,7 @@
   */
 
 #define MSG_COUNT 4
-static DEFINE_PER_CPU(unsigned int, ps3_ipi_virqs[MSG_COUNT]);
+static DEFINE_PER_CPU(unsigned int [MSG_COUNT], ps3_ipi_virqs);
 
 static void do_message_pass(int target, int msg)
 {
index 3f763c5284acc2e682f0f9a3832159565bf3598b..e34b305a7a52a13cdaa7dee57e11a0262940fde3 100644 (file)
@@ -27,7 +27,7 @@
 #include <asm/udbg.h>
 #include <asm/lv1call.h>
 #include <asm/firmware.h>
-#include <asm/iommu.h>
+#include <asm/cell-regs.h>
 
 #include "platform.h"
 
@@ -694,7 +694,7 @@ static int ps3_dma_supported(struct device *_dev, u64 mask)
        return mask >= DMA_BIT_MASK(32);
 }
 
-static struct dma_mapping_ops ps3_sb_dma_ops = {
+static struct dma_map_ops ps3_sb_dma_ops = {
        .alloc_coherent = ps3_alloc_coherent,
        .free_coherent = ps3_free_coherent,
        .map_sg = ps3_sb_map_sg,
@@ -704,7 +704,7 @@ static struct dma_mapping_ops ps3_sb_dma_ops = {
        .unmap_page = ps3_unmap_page,
 };
 
-static struct dma_mapping_ops ps3_ioc0_dma_ops = {
+static struct dma_map_ops ps3_ioc0_dma_ops = {
        .alloc_coherent = ps3_alloc_coherent,
        .free_coherent = ps3_free_coherent,
        .map_sg = ps3_ioc0_map_sg,
index ad152a0e39469da2af3ed2cece1dad816dbadc80..b6fa3e4b51b5ee6c351ee97237dcd0564b1c204b 100644 (file)
@@ -151,7 +151,7 @@ struct pci_controller * __devinit init_phb_dynamic(struct device_node *dn)
        if (dn->child)
                eeh_add_device_tree_early(dn);
 
-       scan_phb(phb);
+       pcibios_scan_phb(phb, dn);
        pcibios_finish_adding_to_bus(phb->bus);
 
        return phb;
index b6f1b137d427e68de2ea6c4e95dfa63a30e80760..2e2bbe120b908ec2816067214006f969f6504492 100644 (file)
@@ -20,6 +20,7 @@
 #include <asm/machdep.h>
 #include <asm/uaccess.h>
 #include <asm/pSeries_reconfig.h>
+#include <asm/mmu.h>
 
 
 
@@ -439,9 +440,15 @@ static int do_update_property(char *buf, size_t bufsize)
        if (!newprop)
                return -ENOMEM;
 
+       if (!strcmp(name, "slb-size") || !strcmp(name, "ibm,slb-size"))
+               slb_set_size(*(int *)value);
+
        oldprop = of_find_property(np, name,NULL);
-       if (!oldprop)
+       if (!oldprop) {
+               if (strlen(name))
+                       return prom_add_property(np, newprop);
                return -ENODEV;
+       }
 
        rc = prom_update_property(np, newprop, oldprop);
        if (rc)
index 8d75ea21296f7dafdf2465f59cf6c3ae0d846aa0..ca5f2e10972c32db9c737f28e4bbf36b76a1241e 100644 (file)
@@ -223,10 +223,6 @@ static void pseries_lpar_enable_pmcs(void)
        set = 1UL << 63;
        reset = 0;
        plpar_hcall_norets(H_PERFMON, set, reset);
-
-       /* instruct hypervisor to maintain PMCs */
-       if (firmware_has_feature(FW_FEATURE_SPLPAR))
-               get_lppaca()->pmcregs_in_use = 1;
 }
 
 static void __init pseries_discover_pic(void)
index 1f8f6cfb94f7f504b4f44f025fc02b600b392000..440000cc71307ac83df8ac251af13085c910aec6 100644 (file)
@@ -56,8 +56,6 @@
  */
 static cpumask_t of_spin_map;
 
-extern void generic_secondary_smp_init(unsigned long);
-
 /**
  * smp_startup_cpu() - start the given cpu
  *
index cbb3bed75d3c0c56a218e1a2678702d6ca0bcfd7..757a83fe5e59f7ecdb28f82a4ae7b68e77e54363 100644 (file)
@@ -1057,6 +1057,10 @@ int fsl_rio_setup(struct of_device *dev)
                        law_start, law_size);
 
        ops = kmalloc(sizeof(struct rio_ops), GFP_KERNEL);
+       if (!ops) {
+               rc = -ENOMEM;
+               goto err_ops;
+       }
        ops->lcread = fsl_local_config_read;
        ops->lcwrite = fsl_local_config_write;
        ops->cread = fsl_rio_config_read;
@@ -1064,6 +1068,10 @@ int fsl_rio_setup(struct of_device *dev)
        ops->dsend = fsl_rio_doorbell_send;
 
        port = kzalloc(sizeof(struct rio_mport), GFP_KERNEL);
+       if (!port) {
+               rc = -ENOMEM;
+               goto err_port;
+       }
        port->id = 0;
        port->index = 0;
 
@@ -1071,7 +1079,7 @@ int fsl_rio_setup(struct of_device *dev)
        if (!priv) {
                printk(KERN_ERR "Can't alloc memory for 'priv'\n");
                rc = -ENOMEM;
-               goto err;
+               goto err_priv;
        }
 
        INIT_LIST_HEAD(&port->dbells);
@@ -1169,11 +1177,13 @@ int fsl_rio_setup(struct of_device *dev)
 
        return 0;
 err:
-       if (priv)
-               iounmap(priv->regs_win);
-       kfree(ops);
+       iounmap(priv->regs_win);
        kfree(priv);
+err_priv:
        kfree(port);
+err_port:
+       kfree(ops);
+err_ops:
        return rc;
 }
 
index 95dbc643c4fc0ba2c411809b624e8fbc7bd1e734..adca4affcf1f7086d652c592dfe719a414594e08 100644 (file)
@@ -37,6 +37,7 @@
 #include <asm/irq.h>
 #include <asm/time.h>
 #include <asm/prom.h>
+#include <asm/machdep.h>
 #include <sysdev/fsl_soc.h>
 #include <mm/mmu_decl.h>
 #include <asm/cpm2.h>
@@ -383,8 +384,9 @@ static int __init setup_rstcr(void)
                if (!rstcr)
                        printk (KERN_EMERG "Error: reset control register "
                                        "not mapped!\n");
-       } else
-               printk (KERN_INFO "rstcr compatible register does not exist!\n");
+       } else if (ppc_md.restart == fsl_rstcr_restart)
+               printk(KERN_ERR "No RSTCR register, warm reboot won't work\n");
+
        if (np)
                of_node_put(np);
        return 0;
index 69e2630c90624cf40690d0ecfd7643a75e1d4bf5..cb7689c4bfbd5e7f3578a78961e3a0293f20de8b 100644 (file)
@@ -735,8 +735,10 @@ struct ipic * __init ipic_init(struct device_node *node, unsigned int flags)
        ipic->irqhost = irq_alloc_host(node, IRQ_HOST_MAP_LINEAR,
                                       NR_IPIC_INTS,
                                       &ipic_host_ops, 0);
-       if (ipic->irqhost == NULL)
+       if (ipic->irqhost == NULL) {
+               kfree(ipic);
                return NULL;
+       }
 
        ipic->regs = ioremap(res.start, res.end - res.start + 1);
 
@@ -781,6 +783,9 @@ struct ipic * __init ipic_init(struct device_node *node, unsigned int flags)
        primary_ipic = ipic;
        irq_set_default_host(primary_ipic->irqhost);
 
+       ipic_write(ipic->regs, IPIC_SIMSR_H, 0);
+       ipic_write(ipic->regs, IPIC_SIMSR_L, 0);
+
        printk ("IPIC (%d IRQ sources) at %p\n", NR_IPIC_INTS,
                        primary_ipic->regs);
 
index 7b49633a4bd0590960af399f67b70c41c7c5e841..207324209065341df70115612c98b3b902bd4c3a 100644 (file)
@@ -53,6 +53,23 @@ static ssize_t mmio_nvram_read(char *buf, size_t count, loff_t *index)
        return count;
 }
 
+static unsigned char mmio_nvram_read_val(int addr)
+{
+       unsigned long flags;
+       unsigned char val;
+
+       if (addr >= mmio_nvram_len)
+               return 0xff;
+
+       spin_lock_irqsave(&mmio_nvram_lock, flags);
+
+       val = ioread8(mmio_nvram_start + addr);
+
+       spin_unlock_irqrestore(&mmio_nvram_lock, flags);
+
+       return val;
+}
+
 static ssize_t mmio_nvram_write(char *buf, size_t count, loff_t *index)
 {
        unsigned long flags;
@@ -72,6 +89,19 @@ static ssize_t mmio_nvram_write(char *buf, size_t count, loff_t *index)
        return count;
 }
 
+void mmio_nvram_write_val(int addr, unsigned char val)
+{
+       unsigned long flags;
+
+       if (addr < mmio_nvram_len) {
+               spin_lock_irqsave(&mmio_nvram_lock, flags);
+
+               iowrite8(val, mmio_nvram_start + addr);
+
+               spin_unlock_irqrestore(&mmio_nvram_lock, flags);
+       }
+}
+
 static ssize_t mmio_nvram_get_size(void)
 {
        return mmio_nvram_len;
@@ -114,6 +144,8 @@ int __init mmio_nvram_init(void)
        printk(KERN_INFO "mmio NVRAM, %luk at 0x%lx mapped to %p\n",
               mmio_nvram_len >> 10, nvram_addr, mmio_nvram_start);
 
+       ppc_md.nvram_read_val   = mmio_nvram_read_val;
+       ppc_md.nvram_write_val  = mmio_nvram_write_val;
        ppc_md.nvram_read       = mmio_nvram_read;
        ppc_md.nvram_write      = mmio_nvram_write;
        ppc_md.nvram_size       = mmio_nvram_get_size;
index 3981ae4cb58e7f3f41fb7ffa25e9a4757bed3d6f..30c44e6b0413e5981f2500fab9c4ad1c8a3a493a 100644 (file)
@@ -230,14 +230,16 @@ static inline u32 _mpic_irq_read(struct mpic *mpic, unsigned int src_no, unsigne
 {
        unsigned int    isu = src_no >> mpic->isu_shift;
        unsigned int    idx = src_no & mpic->isu_mask;
+       unsigned int    val;
 
+       val = _mpic_read(mpic->reg_type, &mpic->isus[isu],
+                        reg + (idx * MPIC_INFO(IRQ_STRIDE)));
 #ifdef CONFIG_MPIC_BROKEN_REGREAD
        if (reg == 0)
-               return mpic->isu_reg0_shadow[idx];
-       else
+               val = (val & (MPIC_VECPRI_MASK | MPIC_VECPRI_ACTIVITY)) |
+                       mpic->isu_reg0_shadow[src_no];
 #endif
-               return _mpic_read(mpic->reg_type, &mpic->isus[isu],
-                                 reg + (idx * MPIC_INFO(IRQ_STRIDE)));
+       return val;
 }
 
 static inline void _mpic_irq_write(struct mpic *mpic, unsigned int src_no,
@@ -251,7 +253,8 @@ static inline void _mpic_irq_write(struct mpic *mpic, unsigned int src_no,
 
 #ifdef CONFIG_MPIC_BROKEN_REGREAD
        if (reg == 0)
-               mpic->isu_reg0_shadow[idx] = value;
+               mpic->isu_reg0_shadow[src_no] =
+                       value & ~(MPIC_VECPRI_MASK | MPIC_VECPRI_ACTIVITY);
 #endif
 }
 
index 3485288dce31bc6e0b4ad79aa96444ce57bf9afb..8e7a7767dd5c4eacb82be33953df8845126e1d71 100644 (file)
@@ -105,14 +105,14 @@ static int qe_gpio_dir_out(struct gpio_chip *gc, unsigned int gpio, int val)
        struct qe_gpio_chip *qe_gc = to_qe_gpio_chip(mm_gc);
        unsigned long flags;
 
+       qe_gpio_set(gc, gpio, val);
+
        spin_lock_irqsave(&qe_gc->lock, flags);
 
        __par_io_config_pin(mm_gc->regs, gpio, QE_PIO_DIR_OUT, 0, 0, 0);
 
        spin_unlock_irqrestore(&qe_gc->lock, flags);
 
-       qe_gpio_set(gc, gpio, val);
-
        return 0;
 }
 
index 074905c3ee5a94d80fb3e0daa86e88b8f77f9650..3faa42e03a85af05a379efaa2f103093b6d5fb9a 100644 (file)
@@ -339,8 +339,10 @@ void __init qe_ic_init(struct device_node *node, unsigned int flags,
 
        qe_ic->irqhost = irq_alloc_host(node, IRQ_HOST_MAP_LINEAR,
                                        NR_QE_IC_INTS, &qe_ic_host_ops, 0);
-       if (qe_ic->irqhost == NULL)
+       if (qe_ic->irqhost == NULL) {
+               kfree(qe_ic);
                return;
+       }
 
        qe_ic->regs = ioremap(res.start, res.end - res.start + 1);
 
@@ -352,6 +354,7 @@ void __init qe_ic_init(struct device_node *node, unsigned int flags,
 
        if (qe_ic->virq_low == NO_IRQ) {
                printk(KERN_ERR "Failed to map QE_IC low IRQ\n");
+               kfree(qe_ic);
                return;
        }
 
index 85ab97ab840a19172662b712f1f345850918a090..faa81b6a66126531c87f94897f33d2affc7c43f3 100644 (file)
@@ -2,6 +2,8 @@
 
 subdir-ccflags-$(CONFIG_PPC_WERROR) := -Werror
 
+GCOV_PROFILE := n
+
 ifdef CONFIG_PPC64
 EXTRA_CFLAGS += -mno-minimal-toc
 endif
index e1f33a81e5e1f130cf3c1e0b82b4d9d751cf904b..0e09a45ac79a633c83a8e0ed282876397db64750 100644 (file)
@@ -2570,7 +2570,7 @@ static void xmon_print_symbol(unsigned long address, const char *mid,
        printf("%s", after);
 }
 
-#ifdef CONFIG_PPC64
+#ifdef CONFIG_PPC_BOOK3S_64
 static void dump_slb(void)
 {
        int i;
index 408d60b4f75bc779a5bf356d13c1624ba209ce25..f7ad8719d02dcd211bc18c39806d86a5dceb985a 100644 (file)
@@ -1,37 +1,21 @@
 #ifndef __ARCH_S390_PERCPU__
 #define __ARCH_S390_PERCPU__
 
-#include <linux/compiler.h>
-#include <asm/lowcore.h>
-
 /*
  * s390 uses its own implementation for per cpu data, the offset of
  * the cpu local data area is cached in the cpu's lowcore memory.
- * For 64 bit module code s390 forces the use of a GOT slot for the
- * address of the per cpu variable. This is needed because the module
- * may be more than 4G above the per cpu area.
  */
-#if defined(__s390x__) && defined(MODULE)
-
-#define SHIFT_PERCPU_PTR(ptr,offset) (({                       \
-       extern int simple_identifier_##var(void);       \
-       unsigned long *__ptr;                           \
-       asm ( "larl %0, %1@GOTENT"              \
-           : "=a" (__ptr) : "X" (ptr) );               \
-       (typeof(ptr))((*__ptr) + (offset));     }))
-
-#else
-
-#define SHIFT_PERCPU_PTR(ptr, offset) (({                              \
-       extern int simple_identifier_##var(void);               \
-       unsigned long __ptr;                                    \
-       asm ( "" : "=a" (__ptr) : "0" (ptr) );                  \
-       (typeof(ptr)) (__ptr + (offset)); }))
+#define __my_cpu_offset S390_lowcore.percpu_offset
 
+/*
+ * For 64 bit module code, the module may be more than 4G above the
+ * per cpu area, use weak definitions to force the compiler to
+ * generate external references.
+ */
+#if defined(CONFIG_SMP) && defined(__s390x__) && defined(MODULE)
+#define ARCH_NEEDS_WEAK_PER_CPU
 #endif
 
-#define __my_cpu_offset S390_lowcore.percpu_offset
-
 #include <asm-generic/percpu.h>
 
 #endif /* __ARCH_S390_PERCPU__ */
index 7315f9e67e1db1ff9397e31fc667712244e42520..bc15ef93e6568b9094ee5620128a8cad95883a60 100644 (file)
@@ -84,13 +84,10 @@ SECTIONS
 
        _end = . ;
 
-       /* Sections to be discarded */
-       /DISCARD/ : {
-               EXIT_DATA
-               *(.exitcall.exit)
-       }
-
        /* Debugging sections.  */
        STABS_DEBUG
        DWARF_DEBUG
+
+       /* Sections to be discarded */
+       DISCARDS
 }
index f53c76acaede2f1af80aaec431e53308c4681bee..0ce254bca92fc5ce2541ec4e0080df97c17c97ed 100644 (file)
@@ -163,16 +163,14 @@ SECTIONS
                _end = . ;
        }
 
+       STABS_DEBUG
+       DWARF_DEBUG
+
        /*
         * When something in the kernel is NOT compiled as a module, the
         * module cleanup code and data are put into these segments. Both
         * can then be thrown away, as cleanup code is never called unless
         * it's a module.
         */
-       /DISCARD/ : {
-               *(.exitcall.exit)
-       }
-
-       STABS_DEBUG
-       DWARF_DEBUG
+       DISCARDS
 }
index 2bd5c287538a7b674348679b57244c515a4c2d0b..86b82348b97c05c3709f02cda2826065deb72cf0 100644 (file)
@@ -99,7 +99,7 @@ config AUDIT_ARCH
 config HAVE_SETUP_PER_CPU_AREA
        def_bool y if SPARC64
 
-config HAVE_DYNAMIC_PER_CPU_AREA
+config NEED_PER_CPU_EMBED_FIRST_CHUNK
        def_bool y if SPARC64
 
 config GENERIC_HARDIRQS_NO__DO_IRQ
index c2456870b05c6c298aba695cd433c15b854a12ee..70f52c1661bc11b4f7c9de697fb6a67fecfa8a97 100644 (file)
@@ -7,10 +7,6 @@
 #define unmap_page_from_agp(page)
 #define flush_agp_cache() mb()
 
-/* Convert a physical address to an address suitable for the GART. */
-#define phys_to_gart(x) (x)
-#define gart_to_phys(x) (x)
-
 /* GATT allocation. Returns/accepts GATT kernel virtual address. */
 #define alloc_gatt_pages(order)                \
        ((char *)__get_free_pages(GFP_KERNEL, (order)))
index 3691907a43b4cdb245f540f2df15dc387a171d16..ff68373ce6d67615f4ad0bf88061bd04730a1673 100644 (file)
@@ -1389,8 +1389,8 @@ void smp_send_stop(void)
  * RETURNS:
  * Pointer to the allocated area on success, NULL on failure.
  */
-static void * __init pcpu_alloc_bootmem(unsigned int cpu, unsigned long size,
-                                       unsigned long align)
+static void * __init pcpu_alloc_bootmem(unsigned int cpu, size_t size,
+                                       size_t align)
 {
        const unsigned long goal = __pa(MAX_DMA_ADDRESS);
 #ifdef CONFIG_NEED_MULTIPLE_NODES
@@ -1415,127 +1415,35 @@ static void * __init pcpu_alloc_bootmem(unsigned int cpu, unsigned long size,
 #endif
 }
 
-static size_t pcpur_size __initdata;
-static void **pcpur_ptrs __initdata;
-
-static struct page * __init pcpur_get_page(unsigned int cpu, int pageno)
+static void __init pcpu_free_bootmem(void *ptr, size_t size)
 {
-       size_t off = (size_t)pageno << PAGE_SHIFT;
-
-       if (off >= pcpur_size)
-               return NULL;
-
-       return virt_to_page(pcpur_ptrs[cpu] + off);
+       free_bootmem(__pa(ptr), size);
 }
 
-#define PCPU_CHUNK_SIZE (4UL * 1024UL * 1024UL)
-
-static void __init pcpu_map_range(unsigned long start, unsigned long end,
-                                 struct page *page)
+static int pcpu_cpu_distance(unsigned int from, unsigned int to)
 {
-       unsigned long pfn = page_to_pfn(page);
-       unsigned long pte_base;
-
-       BUG_ON((pfn<<PAGE_SHIFT)&(PCPU_CHUNK_SIZE - 1UL));
-
-       pte_base = (_PAGE_VALID | _PAGE_SZ4MB_4U |
-                   _PAGE_CP_4U | _PAGE_CV_4U |
-                   _PAGE_P_4U | _PAGE_W_4U);
-       if (tlb_type == hypervisor)
-               pte_base = (_PAGE_VALID | _PAGE_SZ4MB_4V |
-                           _PAGE_CP_4V | _PAGE_CV_4V |
-                           _PAGE_P_4V | _PAGE_W_4V);
-
-       while (start < end) {
-               pgd_t *pgd = pgd_offset_k(start);
-               unsigned long this_end;
-               pud_t *pud;
-               pmd_t *pmd;
-               pte_t *pte;
-
-               pud = pud_offset(pgd, start);
-               if (pud_none(*pud)) {
-                       pmd_t *new;
-
-                       new = __alloc_bootmem(PAGE_SIZE, PAGE_SIZE, PAGE_SIZE);
-                       pud_populate(&init_mm, pud, new);
-               }
-
-               pmd = pmd_offset(pud, start);
-               if (!pmd_present(*pmd)) {
-                       pte_t *new;
-
-                       new = __alloc_bootmem(PAGE_SIZE, PAGE_SIZE, PAGE_SIZE);
-                       pmd_populate_kernel(&init_mm, pmd, new);
-               }
-
-               pte = pte_offset_kernel(pmd, start);
-               this_end = (start + PMD_SIZE) & PMD_MASK;
-               if (this_end > end)
-                       this_end = end;
-
-               while (start < this_end) {
-                       unsigned long paddr = pfn << PAGE_SHIFT;
-
-                       pte_val(*pte) = (paddr | pte_base);
-
-                       start += PAGE_SIZE;
-                       pte++;
-                       pfn++;
-               }
-       }
+       if (cpu_to_node(from) == cpu_to_node(to))
+               return LOCAL_DISTANCE;
+       else
+               return REMOTE_DISTANCE;
 }
 
 void __init setup_per_cpu_areas(void)
 {
-       size_t dyn_size, static_size = __per_cpu_end - __per_cpu_start;
-       static struct vm_struct vm;
-       unsigned long delta, cpu;
-       size_t pcpu_unit_size;
-       size_t ptrs_size;
-
-       pcpur_size = PFN_ALIGN(static_size + PERCPU_MODULE_RESERVE +
-                              PERCPU_DYNAMIC_RESERVE);
-       dyn_size = pcpur_size - static_size - PERCPU_MODULE_RESERVE;
-
+       unsigned long delta;
+       unsigned int cpu;
+       int rc;
 
-       ptrs_size = PFN_ALIGN(nr_cpu_ids * sizeof(pcpur_ptrs[0]));
-       pcpur_ptrs = alloc_bootmem(ptrs_size);
-
-       for_each_possible_cpu(cpu) {
-               pcpur_ptrs[cpu] = pcpu_alloc_bootmem(cpu, PCPU_CHUNK_SIZE,
-                                                    PCPU_CHUNK_SIZE);
-
-               free_bootmem(__pa(pcpur_ptrs[cpu] + pcpur_size),
-                            PCPU_CHUNK_SIZE - pcpur_size);
-
-               memcpy(pcpur_ptrs[cpu], __per_cpu_load, static_size);
-       }
-
-       /* allocate address and map */
-       vm.flags = VM_ALLOC;
-       vm.size = nr_cpu_ids * PCPU_CHUNK_SIZE;
-       vm_area_register_early(&vm, PCPU_CHUNK_SIZE);
-
-       for_each_possible_cpu(cpu) {
-               unsigned long start = (unsigned long) vm.addr;
-               unsigned long end;
-
-               start += cpu * PCPU_CHUNK_SIZE;
-               end = start + PCPU_CHUNK_SIZE;
-               pcpu_map_range(start, end, virt_to_page(pcpur_ptrs[cpu]));
-       }
-
-       pcpu_unit_size = pcpu_setup_first_chunk(pcpur_get_page, static_size,
-                                               PERCPU_MODULE_RESERVE, dyn_size,
-                                               PCPU_CHUNK_SIZE, vm.addr, NULL);
-
-       free_bootmem(__pa(pcpur_ptrs), ptrs_size);
+       rc = pcpu_embed_first_chunk(PERCPU_MODULE_RESERVE,
+                                   PERCPU_DYNAMIC_RESERVE, 4 << 20,
+                                   pcpu_cpu_distance, pcpu_alloc_bootmem,
+                                   pcpu_free_bootmem);
+       if (rc)
+               panic("failed to initialize first chunk (%d)", rc);
 
        delta = (unsigned long)pcpu_base_addr - (unsigned long)__per_cpu_start;
-       for_each_possible_cpu(cpu) {
-               __per_cpu_offset(cpu) = delta + cpu * pcpu_unit_size;
-       }
+       for_each_possible_cpu(cpu)
+               __per_cpu_offset(cpu) = delta + pcpu_unit_offsets[cpu];
 
        /* Setup %g5 for the boot cpu.  */
        __local_per_cpu_offset = __per_cpu_offset(smp_processor_id());
index fcbbd000ec08408725997c3cd07db77a6d2684ac..866390feb6833002efc399a4f9cc6d7f32b31a3e 100644 (file)
@@ -171,12 +171,8 @@ SECTIONS
        }
        _end = . ;
 
-       /DISCARD/ : {
-               EXIT_TEXT
-               EXIT_DATA
-               *(.exitcall.exit)
-       }
-
        STABS_DEBUG
        DWARF_DEBUG
+
+       DISCARDS
 }
index cb0248616d49d75ef1ef255210ac393b84b44018..37ecc5577a9ae8f406d64a9323d0fb0771c76dc7 100644 (file)
        __initramfs_end = .;
   }
 
-  /* Sections to be discarded */
-  /DISCARD/ : {
-       *(.exitcall.exit)
-  }
-
index 9975e1ab44fb38aa71c720e70170eceee8c91198..715a188c04729ca16f952ae312ec83015869ce76 100644 (file)
@@ -156,4 +156,6 @@ SECTIONS
   STABS_DEBUG
 
   DWARF_DEBUG
+
+  DISCARDS
 }
index 11b835248b865338f025a88d40a2c276ad3b7d88..2ebd39765db85cee4db7331ec7841253f096ddea 100644 (file)
@@ -100,4 +100,6 @@ SECTIONS
   STABS_DEBUG
 
   DWARF_DEBUG
+
+  DISCARDS
 }
index fc20fdc0f7f2c637fba6b24b4197738995130f1d..e98e81a04971f1c953533982f6b127573e4058c1 100644 (file)
@@ -150,7 +150,10 @@ config ARCH_HAS_CACHE_LINE_SIZE
 config HAVE_SETUP_PER_CPU_AREA
        def_bool y
 
-config HAVE_DYNAMIC_PER_CPU_AREA
+config NEED_PER_CPU_EMBED_FIRST_CHUNK
+       def_bool y
+
+config NEED_PER_CPU_PAGE_FIRST_CHUNK
        def_bool y
 
 config HAVE_CPUMASK_OF_CPU_MAP
@@ -179,6 +182,10 @@ config ARCH_SUPPORTS_OPTIMIZED_INLINING
 config ARCH_SUPPORTS_DEBUG_PAGEALLOC
        def_bool y
 
+config HAVE_INTEL_TXT
+       def_bool y
+       depends on EXPERIMENTAL && DMAR && ACPI
+
 # Use the generic interrupt handling code in kernel/irq/:
 config GENERIC_HARDIRQS
        bool
@@ -1413,6 +1420,10 @@ config X86_PAT
 
          If unsure, say Y.
 
+config ARCH_USES_PG_UNCACHED
+       def_bool y
+       depends on X86_PAT
+
 config EFI
        bool "EFI runtime service support"
        depends on ACPI
index 9825cd64c9b6e7126432e14c0ee6aebd804a799c..eec2a70d4376ec98832937471bf701ae67db3e28 100644 (file)
  */
 #define flush_agp_cache() wbinvd()
 
-/* Convert a physical address to an address suitable for the GART. */
-#define phys_to_gart(x) (x)
-#define gart_to_phys(x) (x)
-
 /* GATT allocation. Returns/accepts GATT kernel virtual address. */
 #define alloc_gatt_pages(order)                \
        ((char *)__get_free_pages(GFP_KERNEL, (order)))
index 1724e8de317c59518daebdb305f75b23bb4fcaf6..6ca20218dd7211063c68ddfbede68eb2fba4c777 100644 (file)
@@ -85,7 +85,8 @@ struct efi_info {
 struct boot_params {
        struct screen_info screen_info;                 /* 0x000 */
        struct apm_bios_info apm_bios_info;             /* 0x040 */
-       __u8  _pad2[12];                                /* 0x054 */
+       __u8  _pad2[4];                                 /* 0x054 */
+       __u64  tboot_addr;                              /* 0x058 */
        struct ist_info ist_info;                       /* 0x060 */
        __u8  _pad3[16];                                /* 0x070 */
        __u8  hd0_info[16];     /* obsolete! */         /* 0x080 */
index e55dfc1ad453be7b84215a6016a444b497656034..b54f6afe7ec4e2fb8406c8ac16fd48b6bb82ff6d 100644 (file)
@@ -43,8 +43,58 @@ static inline void copy_from_user_page(struct vm_area_struct *vma,
        memcpy(dst, src, len);
 }
 
-#define PG_non_WB                              PG_arch_1
-PAGEFLAG(NonWB, non_WB)
+#define PG_WC                          PG_arch_1
+PAGEFLAG(WC, WC)
+
+#ifdef CONFIG_X86_PAT
+/*
+ * X86 PAT uses page flags WC and Uncached together to keep track of
+ * memory type of pages that have backing page struct. X86 PAT supports 3
+ * different memory types, _PAGE_CACHE_WB, _PAGE_CACHE_WC and
+ * _PAGE_CACHE_UC_MINUS and fourth state where page's memory type has not
+ * been changed from its default (value of -1 used to denote this).
+ * Note we do not support _PAGE_CACHE_UC here.
+ *
+ * Caller must hold memtype_lock for atomicity.
+ */
+static inline unsigned long get_page_memtype(struct page *pg)
+{
+       if (!PageUncached(pg) && !PageWC(pg))
+               return -1;
+       else if (!PageUncached(pg) && PageWC(pg))
+               return _PAGE_CACHE_WC;
+       else if (PageUncached(pg) && !PageWC(pg))
+               return _PAGE_CACHE_UC_MINUS;
+       else
+               return _PAGE_CACHE_WB;
+}
+
+static inline void set_page_memtype(struct page *pg, unsigned long memtype)
+{
+       switch (memtype) {
+       case _PAGE_CACHE_WC:
+               ClearPageUncached(pg);
+               SetPageWC(pg);
+               break;
+       case _PAGE_CACHE_UC_MINUS:
+               SetPageUncached(pg);
+               ClearPageWC(pg);
+               break;
+       case _PAGE_CACHE_WB:
+               SetPageUncached(pg);
+               SetPageWC(pg);
+               break;
+       default:
+       case -1:
+               ClearPageUncached(pg);
+               ClearPageWC(pg);
+               break;
+       }
+}
+#else
+static inline unsigned long get_page_memtype(struct page *pg) { return -1; }
+static inline void set_page_memtype(struct page *pg, unsigned long memtype) { }
+#endif
 
 /*
  * The set_memory_* API can be used to change various attributes of a virtual
index 7b2d71df39a6ac42fc631628239f4f41c1be243b..14f9890eb495a31a203fa780b3caf16b018d68ef 100644 (file)
@@ -131,6 +131,9 @@ enum fixed_addresses {
 #endif
 #ifdef CONFIG_X86_32
        FIX_WP_TEST,
+#endif
+#ifdef CONFIG_INTEL_TXT
+       FIX_TBOOT_BASE,
 #endif
        __end_of_fixed_addresses
 };
index 0e9fe1d9d9715db6a2fb952eff4b917465c3d64b..f35eb45d6576258e7dba242934d76376380b531c 100644 (file)
 #include <asm/pgtable.h>
 #include <asm/tlbflush.h>
 
-int
-is_io_mapping_possible(resource_size_t base, unsigned long size);
-
 void *
 iomap_atomic_prot_pfn(unsigned long pfn, enum km_type type, pgprot_t prot);
 
 void
 iounmap_atomic(void *kvaddr, enum km_type type);
 
+int
+iomap_create_wc(resource_size_t base, unsigned long size, pgprot_t *prot);
+
+void
+iomap_free(resource_size_t base, unsigned long size);
+
 #endif /* _ASM_X86_IOMAP_H */
index a51ada8467de36ddcf729b7f099455225842d28a..4365ffdb461f52b946b8e71c5ffa6c250d7f12be 100644 (file)
@@ -121,6 +121,9 @@ extern int mtrr_del_page(int reg, unsigned long base, unsigned long size);
 extern void mtrr_centaur_report_mcr(int mcr, u32 lo, u32 hi);
 extern void mtrr_ap_init(void);
 extern void mtrr_bp_init(void);
+extern void set_mtrr_aps_delayed_init(void);
+extern void mtrr_aps_init(void);
+extern void mtrr_bp_restore(void);
 extern int mtrr_trim_uncached_memory(unsigned long end_pfn);
 extern int amd_special_default_mtrr(void);
 #  else
@@ -161,6 +164,9 @@ static inline void mtrr_centaur_report_mcr(int mcr, u32 lo, u32 hi)
 
 #define mtrr_ap_init() do {} while (0)
 #define mtrr_bp_init() do {} while (0)
+#define set_mtrr_aps_delayed_init() do {} while (0)
+#define mtrr_aps_init() do {} while (0)
+#define mtrr_bp_restore() do {} while (0)
 #  endif
 
 #ifdef CONFIG_COMPAT
index 7af14e512f97b5c4a002b2c56bba24536ed88cb7..e2c1668dde7ae099e4232e89ccef2be2e69223f0 100644 (file)
@@ -19,4 +19,9 @@ extern int free_memtype(u64 start, u64 end);
 extern int kernel_map_sync_memtype(u64 base, unsigned long size,
                unsigned long flag);
 
+int io_reserve_memtype(resource_size_t start, resource_size_t end,
+                       unsigned long *type);
+
+void io_free_memtype(resource_size_t start, resource_size_t end);
+
 #endif /* _ASM_X86_PAT_H */
index 04eacefcfd26035d588f44c08a3114f6097f5c62..b65a36defeb737434f8823c21c625f14db8e6347 100644 (file)
@@ -168,15 +168,6 @@ do {                                                       \
 /* We can use this directly for local CPU (faster). */
 DECLARE_PER_CPU(unsigned long, this_cpu_off);
 
-#ifdef CONFIG_NEED_MULTIPLE_NODES
-void *pcpu_lpage_remapped(void *kaddr);
-#else
-static inline void *pcpu_lpage_remapped(void *kaddr)
-{
-       return NULL;
-}
-#endif
-
 #endif /* !__ASSEMBLY__ */
 
 #ifdef CONFIG_SMP
index 430d5b24af7b210faf695f0c3619a1d66ae8acf5..832cb838cb48baa4279303bb87cc7d4cedfde859 100644 (file)
@@ -52,6 +52,7 @@ obj-$(CONFIG_X86_DS_SELFTEST)         += ds_selftest.o
 obj-$(CONFIG_X86_32)           += tls.o
 obj-$(CONFIG_IA32_EMULATION)   += tls.o
 obj-y                          += step.o
+obj-$(CONFIG_INTEL_TXT)                += tboot.o
 obj-$(CONFIG_STACKTRACE)       += stacktrace.o
 obj-y                          += cpu/
 obj-y                          += acpi/
index 6b2a52dd040398f36374926956875078c3e48f95..dca325c0399960c4bdacc7659d3f04dbfbbdd541 100644 (file)
@@ -30,8 +30,8 @@
 #include <asm/apic.h>
 #include <asm/desc.h>
 
-static DEFINE_PER_CPU(struct cpu_cpuX_base, cpu_arr[CPU_REG_ALL_BIT]);
-static DEFINE_PER_CPU(struct cpu_private *, priv_arr[MAX_CPU_FILES]);
+static DEFINE_PER_CPU(struct cpu_cpuX_base [CPU_REG_ALL_BIT], cpu_arr);
+static DEFINE_PER_CPU(struct cpu_private * [MAX_CPU_FILES], priv_arr);
 static DEFINE_PER_CPU(int, cpu_priv_count);
 
 static DEFINE_MUTEX(cpu_debug_lock);
index 9bfe9d2ea61570e54f28cccae5f66b1ed5cf63bd..fdd51b554355049298ed2474fc7e5f1468c558fc 100644 (file)
@@ -1101,7 +1101,7 @@ void mce_log_therm_throt_event(__u64 status)
  */
 static int check_interval = 5 * 60; /* 5 minutes */
 
-static DEFINE_PER_CPU(int, next_interval); /* in jiffies */
+static DEFINE_PER_CPU(int, mce_next_interval); /* in jiffies */
 static DEFINE_PER_CPU(struct timer_list, mce_timer);
 
 static void mcheck_timer(unsigned long data)
@@ -1120,7 +1120,7 @@ static void mcheck_timer(unsigned long data)
         * Alert userspace if needed.  If we logged an MCE, reduce the
         * polling interval, otherwise increase the polling interval.
         */
-       n = &__get_cpu_var(next_interval);
+       n = &__get_cpu_var(mce_next_interval);
        if (mce_notify_irq())
                *n = max(*n/2, HZ/100);
        else
@@ -1335,7 +1335,7 @@ static void mce_cpu_features(struct cpuinfo_x86 *c)
 static void mce_init_timer(void)
 {
        struct timer_list *t = &__get_cpu_var(mce_timer);
-       int *n = &__get_cpu_var(next_interval);
+       int *n = &__get_cpu_var(mce_next_interval);
 
        if (mce_ignore_ce)
                return;
@@ -1935,7 +1935,7 @@ mce_cpu_callback(struct notifier_block *nfb, unsigned long action, void *hcpu)
        case CPU_DOWN_FAILED:
        case CPU_DOWN_FAILED_FROZEN:
                t->expires = round_jiffies(jiffies +
-                                               __get_cpu_var(next_interval));
+                                          __get_cpu_var(mce_next_interval));
                add_timer_on(t, cpu);
                smp_call_function_single(cpu, mce_reenable_cpu, &action, 1);
                break;
index 1fecba404fd8167ecc810bede9c08b3e1be0812f..8cd5224943b5d00cb42c41c93bd1d6e6ce1d48df 100644 (file)
@@ -69,7 +69,7 @@ struct threshold_bank {
        struct threshold_block  *blocks;
        cpumask_var_t           cpus;
 };
-static DEFINE_PER_CPU(struct threshold_bank *, threshold_banks[NR_BANKS]);
+static DEFINE_PER_CPU(struct threshold_bank * [NR_BANKS], threshold_banks);
 
 #ifdef CONFIG_SMP
 static unsigned char shared_bank[NR_BANKS] = {
index 7af0f88a41630bb67bb78ecf476870fa70b5ed1d..84e83de54575c5a1da65e77feabd3c8b240ac95e 100644 (file)
@@ -58,6 +58,7 @@ unsigned int mtrr_usage_table[MTRR_MAX_VAR_RANGES];
 static DEFINE_MUTEX(mtrr_mutex);
 
 u64 size_or_mask, size_and_mask;
+static bool mtrr_aps_delayed_init;
 
 static struct mtrr_ops *mtrr_ops[X86_VENDOR_NUM];
 
@@ -163,7 +164,10 @@ static void ipi_handler(void *info)
        if (data->smp_reg != ~0U) {
                mtrr_if->set(data->smp_reg, data->smp_base,
                             data->smp_size, data->smp_type);
-       } else {
+       } else if (mtrr_aps_delayed_init) {
+               /*
+                * Initialize the MTRRs inaddition to the synchronisation.
+                */
                mtrr_if->set_all();
        }
 
@@ -265,6 +269,8 @@ set_mtrr(unsigned int reg, unsigned long base, unsigned long size, mtrr_type typ
         */
        if (reg != ~0U)
                mtrr_if->set(reg, base, size, type);
+       else if (!mtrr_aps_delayed_init)
+               mtrr_if->set_all();
 
        /* Wait for the others */
        while (atomic_read(&data.count))
@@ -721,9 +727,7 @@ void __init mtrr_bp_init(void)
 
 void mtrr_ap_init(void)
 {
-       unsigned long flags;
-
-       if (!mtrr_if || !use_intel())
+       if (!use_intel() || mtrr_aps_delayed_init)
                return;
        /*
         * Ideally we should hold mtrr_mutex here to avoid mtrr entries
@@ -738,11 +742,7 @@ void mtrr_ap_init(void)
         *   2. cpu hotadd time. We let mtrr_add/del_page hold cpuhotplug
         *      lock to prevent mtrr entry changes
         */
-       local_irq_save(flags);
-
-       mtrr_if->set_all();
-
-       local_irq_restore(flags);
+       set_mtrr(~0U, 0, 0, 0);
 }
 
 /**
@@ -753,6 +753,34 @@ void mtrr_save_state(void)
        smp_call_function_single(0, mtrr_save_fixed_ranges, NULL, 1);
 }
 
+void set_mtrr_aps_delayed_init(void)
+{
+       if (!use_intel())
+               return;
+
+       mtrr_aps_delayed_init = true;
+}
+
+/*
+ * MTRR initialization for all AP's
+ */
+void mtrr_aps_init(void)
+{
+       if (!use_intel())
+               return;
+
+       set_mtrr(~0U, 0, 0, 0);
+       mtrr_aps_delayed_init = false;
+}
+
+void mtrr_bp_restore(void)
+{
+       if (!use_intel())
+               return;
+
+       mtrr_if->set_all();
+}
+
 static int __init mtrr_init_finialize(void)
 {
        if (!mtrr_if)
index f9cd0849bd4281384b0497b2584fa7dafe00fffd..2732e2c1e4d340257e10a072fd7f4e2dbaa0a0a3 100644 (file)
@@ -1211,7 +1211,7 @@ amd_pmu_disable_counter(struct hw_perf_counter *hwc, int idx)
        x86_pmu_disable_counter(hwc, idx);
 }
 
-static DEFINE_PER_CPU(u64, prev_left[X86_PMC_IDX_MAX]);
+static DEFINE_PER_CPU(u64 [X86_PMC_IDX_MAX], pmc_prev_left);
 
 /*
  * Set the next IRQ period, based on the hwc->period_left value.
@@ -1253,7 +1253,7 @@ x86_perf_counter_set_period(struct perf_counter *counter,
        if (left > x86_pmu.max_period)
                left = x86_pmu.max_period;
 
-       per_cpu(prev_left[idx], smp_processor_id()) = left;
+       per_cpu(pmc_prev_left[idx], smp_processor_id()) = left;
 
        /*
         * The hw counter starts counting from this counter offset,
@@ -1470,7 +1470,7 @@ void perf_counter_print_debug(void)
                rdmsrl(x86_pmu.eventsel + idx, pmc_ctrl);
                rdmsrl(x86_pmu.perfctr  + idx, pmc_count);
 
-               prev_left = per_cpu(prev_left[idx], cpu);
+               prev_left = per_cpu(pmc_prev_left[idx], cpu);
 
                pr_info("CPU#%d:   gen-PMC%d ctrl:  %016llx\n",
                        cpu, idx, pmc_ctrl);
@@ -2110,8 +2110,8 @@ void callchain_store(struct perf_callchain_entry *entry, u64 ip)
                entry->ip[entry->nr++] = ip;
 }
 
-static DEFINE_PER_CPU(struct perf_callchain_entry, irq_entry);
-static DEFINE_PER_CPU(struct perf_callchain_entry, nmi_entry);
+static DEFINE_PER_CPU(struct perf_callchain_entry, pmc_irq_entry);
+static DEFINE_PER_CPU(struct perf_callchain_entry, pmc_nmi_entry);
 static DEFINE_PER_CPU(int, in_nmi_frame);
 
 
@@ -2264,9 +2264,9 @@ struct perf_callchain_entry *perf_callchain(struct pt_regs *regs)
        struct perf_callchain_entry *entry;
 
        if (in_nmi())
-               entry = &__get_cpu_var(nmi_entry);
+               entry = &__get_cpu_var(pmc_nmi_entry);
        else
-               entry = &__get_cpu_var(irq_entry);
+               entry = &__get_cpu_var(pmc_irq_entry);
 
        entry->nr = 0;
 
index a06e8d1018449dd70e4aac4b1098b6b06c4b9bd1..27349f92a6d79078bca5bce37cfcf23f490ab84a 100644 (file)
@@ -4,6 +4,7 @@
 #include <linux/pm.h>
 #include <linux/efi.h>
 #include <linux/dmi.h>
+#include <linux/tboot.h>
 #include <acpi/reboot.h>
 #include <asm/io.h>
 #include <asm/apic.h>
@@ -508,6 +509,8 @@ static void native_machine_emergency_restart(void)
        if (reboot_emergency)
                emergency_vmx_disable_all();
 
+       tboot_shutdown(TB_SHUTDOWN_REBOOT);
+
        /* Tell the BIOS if we want cold or warm reboot */
        *((unsigned short *)__va(0x472)) = reboot_mode;
 
@@ -634,6 +637,8 @@ static void native_machine_halt(void)
        /* stop other cpus and apics */
        machine_shutdown();
 
+       tboot_shutdown(TB_SHUTDOWN_HALT);
+
        /* stop this cpu */
        stop_this_cpu(NULL);
 }
@@ -645,6 +650,8 @@ static void native_machine_power_off(void)
                        machine_shutdown();
                pm_power_off();
        }
+       /* a fallback in case there is no PM info available */
+       tboot_shutdown(TB_SHUTDOWN_HALT);
 }
 
 struct machine_ops machine_ops = {
index 63f32d220ef22e2d681078ec556698e15ff7645f..19f15c4076fb6f3f57afa01ddc211dbdce1ae202 100644 (file)
@@ -66,6 +66,7 @@
 
 #include <linux/percpu.h>
 #include <linux/crash_dump.h>
+#include <linux/tboot.h>
 
 #include <video/edid.h>
 
@@ -711,6 +712,21 @@ void __init setup_arch(char **cmdline_p)
        printk(KERN_INFO "Command line: %s\n", boot_command_line);
 #endif
 
+       strlcpy(command_line, boot_command_line, COMMAND_LINE_SIZE);
+       *cmdline_p = command_line;
+
+#ifdef CONFIG_X86_64
+       /*
+        * Must call this twice: Once just to detect whether hardware doesn't
+        * support NX (so that the early EHCI debug console setup can safely
+        * call set_fixmap(), and then again after parsing early parameters to
+        * honor the respective command line option.
+        */
+       check_efer();
+#endif
+
+       parse_early_param();
+
        /* VMI may relocate the fixmap; do this before touching ioremap area */
        vmi_init();
 
@@ -793,11 +809,6 @@ void __init setup_arch(char **cmdline_p)
 #endif
 #endif
 
-       strlcpy(command_line, boot_command_line, COMMAND_LINE_SIZE);
-       *cmdline_p = command_line;
-
-       parse_early_param();
-
 #ifdef CONFIG_X86_64
        check_efer();
 #endif
@@ -977,6 +988,8 @@ void __init setup_arch(char **cmdline_p)
        paravirt_pagetable_setup_done(swapper_pg_dir);
        paravirt_post_allocator_init();
 
+       tboot_probe();
+
 #ifdef CONFIG_X86_64
        map_vsyscall();
 #endif
index 07d81916f2120f5a55ad0116620630288682bd74..d559af913e1f89c40de010c1a936cdeab15f9751 100644 (file)
@@ -55,6 +55,7 @@ EXPORT_SYMBOL(__per_cpu_offset);
 #define PERCPU_FIRST_CHUNK_RESERVE     0
 #endif
 
+#ifdef CONFIG_X86_32
 /**
  * pcpu_need_numa - determine percpu allocation needs to consider NUMA
  *
@@ -83,6 +84,7 @@ static bool __init pcpu_need_numa(void)
 #endif
        return false;
 }
+#endif
 
 /**
  * pcpu_alloc_bootmem - NUMA friendly alloc_bootmem wrapper for percpu
@@ -124,308 +126,35 @@ static void * __init pcpu_alloc_bootmem(unsigned int cpu, unsigned long size,
 }
 
 /*
- * Large page remap allocator
- *
- * This allocator uses PMD page as unit.  A PMD page is allocated for
- * each cpu and each is remapped into vmalloc area using PMD mapping.
- * As PMD page is quite large, only part of it is used for the first
- * chunk.  Unused part is returned to the bootmem allocator.
- *
- * So, the PMD pages are mapped twice - once to the physical mapping
- * and to the vmalloc area for the first percpu chunk.  The double
- * mapping does add one more PMD TLB entry pressure but still is much
- * better than only using 4k mappings while still being NUMA friendly.
+ * Helpers for first chunk memory allocation
  */
-#ifdef CONFIG_NEED_MULTIPLE_NODES
-struct pcpul_ent {
-       unsigned int    cpu;
-       void            *ptr;
-};
-
-static size_t pcpul_size;
-static struct pcpul_ent *pcpul_map;
-static struct vm_struct pcpul_vm;
-
-static struct page * __init pcpul_get_page(unsigned int cpu, int pageno)
+static void * __init pcpu_fc_alloc(unsigned int cpu, size_t size, size_t align)
 {
-       size_t off = (size_t)pageno << PAGE_SHIFT;
-
-       if (off >= pcpul_size)
-               return NULL;
-
-       return virt_to_page(pcpul_map[cpu].ptr + off);
+       return pcpu_alloc_bootmem(cpu, size, align);
 }
 
-static ssize_t __init setup_pcpu_lpage(size_t static_size, bool chosen)
+static void __init pcpu_fc_free(void *ptr, size_t size)
 {
-       size_t map_size, dyn_size;
-       unsigned int cpu;
-       int i, j;
-       ssize_t ret;
-
-       if (!chosen) {
-               size_t vm_size = VMALLOC_END - VMALLOC_START;
-               size_t tot_size = nr_cpu_ids * PMD_SIZE;
-
-               /* on non-NUMA, embedding is better */
-               if (!pcpu_need_numa())
-                       return -EINVAL;
-
-               /* don't consume more than 20% of vmalloc area */
-               if (tot_size > vm_size / 5) {
-                       pr_info("PERCPU: too large chunk size %zuMB for "
-                               "large page remap\n", tot_size >> 20);
-                       return -EINVAL;
-               }
-       }
-
-       /* need PSE */
-       if (!cpu_has_pse) {
-               pr_warning("PERCPU: lpage allocator requires PSE\n");
-               return -EINVAL;
-       }
-
-       /*
-        * Currently supports only single page.  Supporting multiple
-        * pages won't be too difficult if it ever becomes necessary.
-        */
-       pcpul_size = PFN_ALIGN(static_size + PERCPU_MODULE_RESERVE +
-                              PERCPU_DYNAMIC_RESERVE);
-       if (pcpul_size > PMD_SIZE) {
-               pr_warning("PERCPU: static data is larger than large page, "
-                          "can't use large page\n");
-               return -EINVAL;
-       }
-       dyn_size = pcpul_size - static_size - PERCPU_FIRST_CHUNK_RESERVE;
-
-       /* allocate pointer array and alloc large pages */
-       map_size = PFN_ALIGN(nr_cpu_ids * sizeof(pcpul_map[0]));
-       pcpul_map = alloc_bootmem(map_size);
-
-       for_each_possible_cpu(cpu) {
-               pcpul_map[cpu].cpu = cpu;
-               pcpul_map[cpu].ptr = pcpu_alloc_bootmem(cpu, PMD_SIZE,
-                                                       PMD_SIZE);
-               if (!pcpul_map[cpu].ptr) {
-                       pr_warning("PERCPU: failed to allocate large page "
-                                  "for cpu%u\n", cpu);
-                       goto enomem;
-               }
-
-               /*
-                * Only use pcpul_size bytes and give back the rest.
-                *
-                * Ingo: The 2MB up-rounding bootmem is needed to make
-                * sure the partial 2MB page is still fully RAM - it's
-                * not well-specified to have a PAT-incompatible area
-                * (unmapped RAM, device memory, etc.) in that hole.
-                */
-               free_bootmem(__pa(pcpul_map[cpu].ptr + pcpul_size),
-                            PMD_SIZE - pcpul_size);
-
-               memcpy(pcpul_map[cpu].ptr, __per_cpu_load, static_size);
-       }
-
-       /* allocate address and map */
-       pcpul_vm.flags = VM_ALLOC;
-       pcpul_vm.size = nr_cpu_ids * PMD_SIZE;
-       vm_area_register_early(&pcpul_vm, PMD_SIZE);
-
-       for_each_possible_cpu(cpu) {
-               pmd_t *pmd, pmd_v;
-
-               pmd = populate_extra_pmd((unsigned long)pcpul_vm.addr +
-                                        cpu * PMD_SIZE);
-               pmd_v = pfn_pmd(page_to_pfn(virt_to_page(pcpul_map[cpu].ptr)),
-                               PAGE_KERNEL_LARGE);
-               set_pmd(pmd, pmd_v);
-       }
-
-       /* we're ready, commit */
-       pr_info("PERCPU: Remapped at %p with large pages, static data "
-               "%zu bytes\n", pcpul_vm.addr, static_size);
-
-       ret = pcpu_setup_first_chunk(pcpul_get_page, static_size,
-                                    PERCPU_FIRST_CHUNK_RESERVE, dyn_size,
-                                    PMD_SIZE, pcpul_vm.addr, NULL);
-
-       /* sort pcpul_map array for pcpu_lpage_remapped() */
-       for (i = 0; i < nr_cpu_ids - 1; i++)
-               for (j = i + 1; j < nr_cpu_ids; j++)
-                       if (pcpul_map[i].ptr > pcpul_map[j].ptr) {
-                               struct pcpul_ent tmp = pcpul_map[i];
-                               pcpul_map[i] = pcpul_map[j];
-                               pcpul_map[j] = tmp;
-                       }
-
-       return ret;
-
-enomem:
-       for_each_possible_cpu(cpu)
-               if (pcpul_map[cpu].ptr)
-                       free_bootmem(__pa(pcpul_map[cpu].ptr), pcpul_size);
-       free_bootmem(__pa(pcpul_map), map_size);
-       return -ENOMEM;
+       free_bootmem(__pa(ptr), size);
 }
 
-/**
- * pcpu_lpage_remapped - determine whether a kaddr is in pcpul recycled area
- * @kaddr: the kernel address in question
- *
- * Determine whether @kaddr falls in the pcpul recycled area.  This is
- * used by pageattr to detect VM aliases and break up the pcpu PMD
- * mapping such that the same physical page is not mapped under
- * different attributes.
- *
- * The recycled area is always at the tail of a partially used PMD
- * page.
- *
- * RETURNS:
- * Address of corresponding remapped pcpu address if match is found;
- * otherwise, NULL.
- */
-void *pcpu_lpage_remapped(void *kaddr)
+static int __init pcpu_cpu_distance(unsigned int from, unsigned int to)
 {
-       void *pmd_addr = (void *)((unsigned long)kaddr & PMD_MASK);
-       unsigned long offset = (unsigned long)kaddr & ~PMD_MASK;
-       int left = 0, right = nr_cpu_ids - 1;
-       int pos;
-
-       /* pcpul in use at all? */
-       if (!pcpul_map)
-               return NULL;
-
-       /* okay, perform binary search */
-       while (left <= right) {
-               pos = (left + right) / 2;
-
-               if (pcpul_map[pos].ptr < pmd_addr)
-                       left = pos + 1;
-               else if (pcpul_map[pos].ptr > pmd_addr)
-                       right = pos - 1;
-               else {
-                       /* it shouldn't be in the area for the first chunk */
-                       WARN_ON(offset < pcpul_size);
-
-                       return pcpul_vm.addr +
-                               pcpul_map[pos].cpu * PMD_SIZE + offset;
-               }
-       }
-
-       return NULL;
-}
+#ifdef CONFIG_NEED_MULTIPLE_NODES
+       if (early_cpu_to_node(from) == early_cpu_to_node(to))
+               return LOCAL_DISTANCE;
+       else
+               return REMOTE_DISTANCE;
 #else
-static ssize_t __init setup_pcpu_lpage(size_t static_size, bool chosen)
-{
-       return -EINVAL;
-}
+       return LOCAL_DISTANCE;
 #endif
-
-/*
- * Embedding allocator
- *
- * The first chunk is sized to just contain the static area plus
- * module and dynamic reserves and embedded into linear physical
- * mapping so that it can use PMD mapping without additional TLB
- * pressure.
- */
-static ssize_t __init setup_pcpu_embed(size_t static_size, bool chosen)
-{
-       size_t reserve = PERCPU_MODULE_RESERVE + PERCPU_DYNAMIC_RESERVE;
-
-       /*
-        * If large page isn't supported, there's no benefit in doing
-        * this.  Also, embedding allocation doesn't play well with
-        * NUMA.
-        */
-       if (!chosen && (!cpu_has_pse || pcpu_need_numa()))
-               return -EINVAL;
-
-       return pcpu_embed_first_chunk(static_size, PERCPU_FIRST_CHUNK_RESERVE,
-                                     reserve - PERCPU_FIRST_CHUNK_RESERVE, -1);
 }
 
-/*
- * 4k page allocator
- *
- * This is the basic allocator.  Static percpu area is allocated
- * page-by-page and most of initialization is done by the generic
- * setup function.
- */
-static struct page **pcpu4k_pages __initdata;
-static int pcpu4k_nr_static_pages __initdata;
-
-static struct page * __init pcpu4k_get_page(unsigned int cpu, int pageno)
-{
-       if (pageno < pcpu4k_nr_static_pages)
-               return pcpu4k_pages[cpu * pcpu4k_nr_static_pages + pageno];
-       return NULL;
-}
-
-static void __init pcpu4k_populate_pte(unsigned long addr)
+static void __init pcpup_populate_pte(unsigned long addr)
 {
        populate_extra_pte(addr);
 }
 
-static ssize_t __init setup_pcpu_4k(size_t static_size)
-{
-       size_t pages_size;
-       unsigned int cpu;
-       int i, j;
-       ssize_t ret;
-
-       pcpu4k_nr_static_pages = PFN_UP(static_size);
-
-       /* unaligned allocations can't be freed, round up to page size */
-       pages_size = PFN_ALIGN(pcpu4k_nr_static_pages * nr_cpu_ids
-                              * sizeof(pcpu4k_pages[0]));
-       pcpu4k_pages = alloc_bootmem(pages_size);
-
-       /* allocate and copy */
-       j = 0;
-       for_each_possible_cpu(cpu)
-               for (i = 0; i < pcpu4k_nr_static_pages; i++) {
-                       void *ptr;
-
-                       ptr = pcpu_alloc_bootmem(cpu, PAGE_SIZE, PAGE_SIZE);
-                       if (!ptr) {
-                               pr_warning("PERCPU: failed to allocate "
-                                          "4k page for cpu%u\n", cpu);
-                               goto enomem;
-                       }
-
-                       memcpy(ptr, __per_cpu_load + i * PAGE_SIZE, PAGE_SIZE);
-                       pcpu4k_pages[j++] = virt_to_page(ptr);
-               }
-
-       /* we're ready, commit */
-       pr_info("PERCPU: Allocated %d 4k pages, static data %zu bytes\n",
-               pcpu4k_nr_static_pages, static_size);
-
-       ret = pcpu_setup_first_chunk(pcpu4k_get_page, static_size,
-                                    PERCPU_FIRST_CHUNK_RESERVE, -1,
-                                    -1, NULL, pcpu4k_populate_pte);
-       goto out_free_ar;
-
-enomem:
-       while (--j >= 0)
-               free_bootmem(__pa(page_address(pcpu4k_pages[j])), PAGE_SIZE);
-       ret = -ENOMEM;
-out_free_ar:
-       free_bootmem(__pa(pcpu4k_pages), pages_size);
-       return ret;
-}
-
-/* for explicit first chunk allocator selection */
-static char pcpu_chosen_alloc[16] __initdata;
-
-static int __init percpu_alloc_setup(char *str)
-{
-       strncpy(pcpu_chosen_alloc, str, sizeof(pcpu_chosen_alloc) - 1);
-       return 0;
-}
-early_param("percpu_alloc", percpu_alloc_setup);
-
 static inline void setup_percpu_segment(int cpu)
 {
 #ifdef CONFIG_X86_32
@@ -441,52 +170,49 @@ static inline void setup_percpu_segment(int cpu)
 
 void __init setup_per_cpu_areas(void)
 {
-       size_t static_size = __per_cpu_end - __per_cpu_start;
        unsigned int cpu;
        unsigned long delta;
-       size_t pcpu_unit_size;
-       ssize_t ret;
+       int rc;
 
        pr_info("NR_CPUS:%d nr_cpumask_bits:%d nr_cpu_ids:%d nr_node_ids:%d\n",
                NR_CPUS, nr_cpumask_bits, nr_cpu_ids, nr_node_ids);
 
        /*
-        * Allocate percpu area.  If PSE is supported, try to make use
-        * of large page mappings.  Please read comments on top of
-        * each allocator for details.
+        * Allocate percpu area.  Embedding allocator is our favorite;
+        * however, on NUMA configurations, it can result in very
+        * sparse unit mapping and vmalloc area isn't spacious enough
+        * on 32bit.  Use page in that case.
         */
-       ret = -EINVAL;
-       if (strlen(pcpu_chosen_alloc)) {
-               if (strcmp(pcpu_chosen_alloc, "4k")) {
-                       if (!strcmp(pcpu_chosen_alloc, "lpage"))
-                               ret = setup_pcpu_lpage(static_size, true);
-                       else if (!strcmp(pcpu_chosen_alloc, "embed"))
-                               ret = setup_pcpu_embed(static_size, true);
-                       else
-                               pr_warning("PERCPU: unknown allocator %s "
-                                          "specified\n", pcpu_chosen_alloc);
-                       if (ret < 0)
-                               pr_warning("PERCPU: %s allocator failed (%zd), "
-                                          "falling back to 4k\n",
-                                          pcpu_chosen_alloc, ret);
-               }
-       } else {
-               ret = setup_pcpu_lpage(static_size, false);
-               if (ret < 0)
-                       ret = setup_pcpu_embed(static_size, false);
+#ifdef CONFIG_X86_32
+       if (pcpu_chosen_fc == PCPU_FC_AUTO && pcpu_need_numa())
+               pcpu_chosen_fc = PCPU_FC_PAGE;
+#endif
+       rc = -EINVAL;
+       if (pcpu_chosen_fc != PCPU_FC_PAGE) {
+               const size_t atom_size = cpu_has_pse ? PMD_SIZE : PAGE_SIZE;
+               const size_t dyn_size = PERCPU_MODULE_RESERVE +
+                       PERCPU_DYNAMIC_RESERVE - PERCPU_FIRST_CHUNK_RESERVE;
+
+               rc = pcpu_embed_first_chunk(PERCPU_FIRST_CHUNK_RESERVE,
+                                           dyn_size, atom_size,
+                                           pcpu_cpu_distance,
+                                           pcpu_fc_alloc, pcpu_fc_free);
+               if (rc < 0)
+                       pr_warning("PERCPU: %s allocator failed (%d), "
+                                  "falling back to page size\n",
+                                  pcpu_fc_names[pcpu_chosen_fc], rc);
        }
-       if (ret < 0)
-               ret = setup_pcpu_4k(static_size);
-       if (ret < 0)
-               panic("cannot allocate static percpu area (%zu bytes, err=%zd)",
-                     static_size, ret);
-
-       pcpu_unit_size = ret;
+       if (rc < 0)
+               rc = pcpu_page_first_chunk(PERCPU_FIRST_CHUNK_RESERVE,
+                                          pcpu_fc_alloc, pcpu_fc_free,
+                                          pcpup_populate_pte);
+       if (rc < 0)
+               panic("cannot initialize percpu area (err=%d)", rc);
 
        /* alrighty, percpu areas up and running */
        delta = (unsigned long)pcpu_base_addr - (unsigned long)__per_cpu_start;
        for_each_possible_cpu(cpu) {
-               per_cpu_offset(cpu) = delta + cpu * pcpu_unit_size;
+               per_cpu_offset(cpu) = delta + pcpu_unit_offsets[cpu];
                per_cpu(this_cpu_off, cpu) = per_cpu_offset(cpu);
                per_cpu(cpu_number, cpu) = cpu;
                setup_percpu_segment(cpu);
index c36cc1452cdc751f77165d43b8ad7ba0c9b83088..a25eeec00080b5f9801e30c08e2d4a5f65ae904e 100644 (file)
@@ -47,6 +47,7 @@
 #include <linux/bootmem.h>
 #include <linux/err.h>
 #include <linux/nmi.h>
+#include <linux/tboot.h>
 
 #include <asm/acpi.h>
 #include <asm/desc.h>
@@ -1117,9 +1118,22 @@ void __init native_smp_prepare_cpus(unsigned int max_cpus)
 
        if (is_uv_system())
                uv_system_init();
+
+       set_mtrr_aps_delayed_init();
 out:
        preempt_enable();
 }
+
+void arch_enable_nonboot_cpus_begin(void)
+{
+       set_mtrr_aps_delayed_init();
+}
+
+void arch_enable_nonboot_cpus_end(void)
+{
+       mtrr_aps_init();
+}
+
 /*
  * Early setup to make printk work.
  */
@@ -1141,6 +1155,7 @@ void __init native_smp_cpus_done(unsigned int max_cpus)
        setup_ioapic_dest();
 #endif
        check_nmi_watchdog();
+       mtrr_aps_init();
 }
 
 static int __initdata setup_possible_cpus = -1;
@@ -1318,6 +1333,7 @@ void play_dead_common(void)
 void native_play_dead(void)
 {
        play_dead_common();
+       tboot_shutdown(TB_SHUTDOWN_WFS);
        wbinvd_halt();
 }
 
diff --git a/arch/x86/kernel/tboot.c b/arch/x86/kernel/tboot.c
new file mode 100644 (file)
index 0000000..86c9f91
--- /dev/null
@@ -0,0 +1,447 @@
+/*
+ * tboot.c: main implementation of helper functions used by kernel for
+ *          runtime support of Intel(R) Trusted Execution Technology
+ *
+ * Copyright (c) 2006-2009, Intel Corporation
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope 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.,
+ * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ */
+
+#include <linux/dma_remapping.h>
+#include <linux/init_task.h>
+#include <linux/spinlock.h>
+#include <linux/delay.h>
+#include <linux/sched.h>
+#include <linux/init.h>
+#include <linux/dmar.h>
+#include <linux/cpu.h>
+#include <linux/pfn.h>
+#include <linux/mm.h>
+#include <linux/tboot.h>
+
+#include <asm/trampoline.h>
+#include <asm/processor.h>
+#include <asm/bootparam.h>
+#include <asm/pgtable.h>
+#include <asm/pgalloc.h>
+#include <asm/fixmap.h>
+#include <asm/proto.h>
+#include <asm/setup.h>
+#include <asm/e820.h>
+#include <asm/io.h>
+
+#include "acpi/realmode/wakeup.h"
+
+/* Global pointer to shared data; NULL means no measured launch. */
+struct tboot *tboot __read_mostly;
+
+/* timeout for APs (in secs) to enter wait-for-SIPI state during shutdown */
+#define AP_WAIT_TIMEOUT                1
+
+#undef pr_fmt
+#define pr_fmt(fmt)    "tboot: " fmt
+
+static u8 tboot_uuid[16] __initdata = TBOOT_UUID;
+
+void __init tboot_probe(void)
+{
+       /* Look for valid page-aligned address for shared page. */
+       if (!boot_params.tboot_addr)
+               return;
+       /*
+        * also verify that it is mapped as we expect it before calling
+        * set_fixmap(), to reduce chance of garbage value causing crash
+        */
+       if (!e820_any_mapped(boot_params.tboot_addr,
+                            boot_params.tboot_addr, E820_RESERVED)) {
+               pr_warning("non-0 tboot_addr but it is not of type E820_RESERVED\n");
+               return;
+       }
+
+       /* only a natively booted kernel should be using TXT */
+       if (paravirt_enabled()) {
+               pr_warning("non-0 tboot_addr but pv_ops is enabled\n");
+               return;
+       }
+
+       /* Map and check for tboot UUID. */
+       set_fixmap(FIX_TBOOT_BASE, boot_params.tboot_addr);
+       tboot = (struct tboot *)fix_to_virt(FIX_TBOOT_BASE);
+       if (memcmp(&tboot_uuid, &tboot->uuid, sizeof(tboot->uuid))) {
+               pr_warning("tboot at 0x%llx is invalid\n",
+                          boot_params.tboot_addr);
+               tboot = NULL;
+               return;
+       }
+       if (tboot->version < 5) {
+               pr_warning("tboot version is invalid: %u\n", tboot->version);
+               tboot = NULL;
+               return;
+       }
+
+       pr_info("found shared page at phys addr 0x%llx:\n",
+               boot_params.tboot_addr);
+       pr_debug("version: %d\n", tboot->version);
+       pr_debug("log_addr: 0x%08x\n", tboot->log_addr);
+       pr_debug("shutdown_entry: 0x%x\n", tboot->shutdown_entry);
+       pr_debug("tboot_base: 0x%08x\n", tboot->tboot_base);
+       pr_debug("tboot_size: 0x%x\n", tboot->tboot_size);
+}
+
+static pgd_t *tboot_pg_dir;
+static struct mm_struct tboot_mm = {
+       .mm_rb          = RB_ROOT,
+       .pgd            = swapper_pg_dir,
+       .mm_users       = ATOMIC_INIT(2),
+       .mm_count       = ATOMIC_INIT(1),
+       .mmap_sem       = __RWSEM_INITIALIZER(init_mm.mmap_sem),
+       .page_table_lock =  __SPIN_LOCK_UNLOCKED(init_mm.page_table_lock),
+       .mmlist         = LIST_HEAD_INIT(init_mm.mmlist),
+       .cpu_vm_mask    = CPU_MASK_ALL,
+};
+
+static inline void switch_to_tboot_pt(void)
+{
+       write_cr3(virt_to_phys(tboot_pg_dir));
+}
+
+static int map_tboot_page(unsigned long vaddr, unsigned long pfn,
+                         pgprot_t prot)
+{
+       pgd_t *pgd;
+       pud_t *pud;
+       pmd_t *pmd;
+       pte_t *pte;
+
+       pgd = pgd_offset(&tboot_mm, vaddr);
+       pud = pud_alloc(&tboot_mm, pgd, vaddr);
+       if (!pud)
+               return -1;
+       pmd = pmd_alloc(&tboot_mm, pud, vaddr);
+       if (!pmd)
+               return -1;
+       pte = pte_alloc_map(&tboot_mm, pmd, vaddr);
+       if (!pte)
+               return -1;
+       set_pte_at(&tboot_mm, vaddr, pte, pfn_pte(pfn, prot));
+       pte_unmap(pte);
+       return 0;
+}
+
+static int map_tboot_pages(unsigned long vaddr, unsigned long start_pfn,
+                          unsigned long nr)
+{
+       /* Reuse the original kernel mapping */
+       tboot_pg_dir = pgd_alloc(&tboot_mm);
+       if (!tboot_pg_dir)
+               return -1;
+
+       for (; nr > 0; nr--, vaddr += PAGE_SIZE, start_pfn++) {
+               if (map_tboot_page(vaddr, start_pfn, PAGE_KERNEL_EXEC))
+                       return -1;
+       }
+
+       return 0;
+}
+
+static void tboot_create_trampoline(void)
+{
+       u32 map_base, map_size;
+
+       /* Create identity map for tboot shutdown code. */
+       map_base = PFN_DOWN(tboot->tboot_base);
+       map_size = PFN_UP(tboot->tboot_size);
+       if (map_tboot_pages(map_base << PAGE_SHIFT, map_base, map_size))
+               panic("tboot: Error mapping tboot pages (mfns) @ 0x%x, 0x%x\n",
+                     map_base, map_size);
+}
+
+#ifdef CONFIG_ACPI_SLEEP
+
+static void add_mac_region(phys_addr_t start, unsigned long size)
+{
+       struct tboot_mac_region *mr;
+       phys_addr_t end = start + size;
+
+       if (start && size) {
+               mr = &tboot->mac_regions[tboot->num_mac_regions++];
+               mr->start = round_down(start, PAGE_SIZE);
+               mr->size  = round_up(end, PAGE_SIZE) - mr->start;
+       }
+}
+
+static int tboot_setup_sleep(void)
+{
+       tboot->num_mac_regions = 0;
+
+       /* S3 resume code */
+       add_mac_region(acpi_wakeup_address, WAKEUP_SIZE);
+
+#ifdef CONFIG_X86_TRAMPOLINE
+       /* AP trampoline code */
+       add_mac_region(virt_to_phys(trampoline_base), TRAMPOLINE_SIZE);
+#endif
+
+       /* kernel code + data + bss */
+       add_mac_region(virt_to_phys(_text), _end - _text);
+
+       tboot->acpi_sinfo.kernel_s3_resume_vector = acpi_wakeup_address;
+
+       return 0;
+}
+
+#else /* no CONFIG_ACPI_SLEEP */
+
+static int tboot_setup_sleep(void)
+{
+       /* S3 shutdown requested, but S3 not supported by the kernel... */
+       BUG();
+       return -1;
+}
+
+#endif
+
+void tboot_shutdown(u32 shutdown_type)
+{
+       void (*shutdown)(void);
+
+       if (!tboot_enabled())
+               return;
+
+       /*
+        * if we're being called before the 1:1 mapping is set up then just
+        * return and let the normal shutdown happen; this should only be
+        * due to very early panic()
+        */
+       if (!tboot_pg_dir)
+               return;
+
+       /* if this is S3 then set regions to MAC */
+       if (shutdown_type == TB_SHUTDOWN_S3)
+               if (tboot_setup_sleep())
+                       return;
+
+       tboot->shutdown_type = shutdown_type;
+
+       switch_to_tboot_pt();
+
+       shutdown = (void(*)(void))(unsigned long)tboot->shutdown_entry;
+       shutdown();
+
+       /* should not reach here */
+       while (1)
+               halt();
+}
+
+static void tboot_copy_fadt(const struct acpi_table_fadt *fadt)
+{
+#define TB_COPY_GAS(tbg, g)                    \
+       tbg.space_id     = g.space_id;          \
+       tbg.bit_width    = g.bit_width;         \
+       tbg.bit_offset   = g.bit_offset;        \
+       tbg.access_width = g.access_width;      \
+       tbg.address      = g.address;
+
+       TB_COPY_GAS(tboot->acpi_sinfo.pm1a_cnt_blk, fadt->xpm1a_control_block);
+       TB_COPY_GAS(tboot->acpi_sinfo.pm1b_cnt_blk, fadt->xpm1b_control_block);
+       TB_COPY_GAS(tboot->acpi_sinfo.pm1a_evt_blk, fadt->xpm1a_event_block);
+       TB_COPY_GAS(tboot->acpi_sinfo.pm1b_evt_blk, fadt->xpm1b_event_block);
+
+       /*
+        * We need phys addr of waking vector, but can't use virt_to_phys() on
+        * &acpi_gbl_FACS because it is ioremap'ed, so calc from FACS phys
+        * addr.
+        */
+       tboot->acpi_sinfo.wakeup_vector = fadt->facs +
+               offsetof(struct acpi_table_facs, firmware_waking_vector);
+}
+
+void tboot_sleep(u8 sleep_state, u32 pm1a_control, u32 pm1b_control)
+{
+       static u32 acpi_shutdown_map[ACPI_S_STATE_COUNT] = {
+               /* S0,1,2: */ -1, -1, -1,
+               /* S3: */ TB_SHUTDOWN_S3,
+               /* S4: */ TB_SHUTDOWN_S4,
+               /* S5: */ TB_SHUTDOWN_S5 };
+
+       if (!tboot_enabled())
+               return;
+
+       tboot_copy_fadt(&acpi_gbl_FADT);
+       tboot->acpi_sinfo.pm1a_cnt_val = pm1a_control;
+       tboot->acpi_sinfo.pm1b_cnt_val = pm1b_control;
+       /* we always use the 32b wakeup vector */
+       tboot->acpi_sinfo.vector_width = 32;
+
+       if (sleep_state >= ACPI_S_STATE_COUNT ||
+           acpi_shutdown_map[sleep_state] == -1) {
+               pr_warning("unsupported sleep state 0x%x\n", sleep_state);
+               return;
+       }
+
+       tboot_shutdown(acpi_shutdown_map[sleep_state]);
+}
+
+static atomic_t ap_wfs_count;
+
+static int tboot_wait_for_aps(int num_aps)
+{
+       unsigned long timeout;
+
+       timeout = AP_WAIT_TIMEOUT*HZ;
+       while (atomic_read((atomic_t *)&tboot->num_in_wfs) != num_aps &&
+              timeout) {
+               mdelay(1);
+               timeout--;
+       }
+
+       if (timeout)
+               pr_warning("tboot wait for APs timeout\n");
+
+       return !(atomic_read((atomic_t *)&tboot->num_in_wfs) == num_aps);
+}
+
+static int __cpuinit tboot_cpu_callback(struct notifier_block *nfb,
+                       unsigned long action, void *hcpu)
+{
+       switch (action) {
+       case CPU_DYING:
+               atomic_inc(&ap_wfs_count);
+               if (num_online_cpus() == 1)
+                       if (tboot_wait_for_aps(atomic_read(&ap_wfs_count)))
+                               return NOTIFY_BAD;
+               break;
+       }
+       return NOTIFY_OK;
+}
+
+static struct notifier_block tboot_cpu_notifier __cpuinitdata =
+{
+       .notifier_call = tboot_cpu_callback,
+};
+
+static __init int tboot_late_init(void)
+{
+       if (!tboot_enabled())
+               return 0;
+
+       tboot_create_trampoline();
+
+       atomic_set(&ap_wfs_count, 0);
+       register_hotcpu_notifier(&tboot_cpu_notifier);
+       return 0;
+}
+
+late_initcall(tboot_late_init);
+
+/*
+ * TXT configuration registers (offsets from TXT_{PUB, PRIV}_CONFIG_REGS_BASE)
+ */
+
+#define TXT_PUB_CONFIG_REGS_BASE       0xfed30000
+#define TXT_PRIV_CONFIG_REGS_BASE      0xfed20000
+
+/* # pages for each config regs space - used by fixmap */
+#define NR_TXT_CONFIG_PAGES     ((TXT_PUB_CONFIG_REGS_BASE -                \
+                                 TXT_PRIV_CONFIG_REGS_BASE) >> PAGE_SHIFT)
+
+/* offsets from pub/priv config space */
+#define TXTCR_HEAP_BASE             0x0300
+#define TXTCR_HEAP_SIZE             0x0308
+
+#define SHA1_SIZE      20
+
+struct sha1_hash {
+       u8 hash[SHA1_SIZE];
+};
+
+struct sinit_mle_data {
+       u32               version;             /* currently 6 */
+       struct sha1_hash  bios_acm_id;
+       u32               edx_senter_flags;
+       u64               mseg_valid;
+       struct sha1_hash  sinit_hash;
+       struct sha1_hash  mle_hash;
+       struct sha1_hash  stm_hash;
+       struct sha1_hash  lcp_policy_hash;
+       u32               lcp_policy_control;
+       u32               rlp_wakeup_addr;
+       u32               reserved;
+       u32               num_mdrs;
+       u32               mdrs_off;
+       u32               num_vtd_dmars;
+       u32               vtd_dmars_off;
+} __packed;
+
+struct acpi_table_header *tboot_get_dmar_table(struct acpi_table_header *dmar_tbl)
+{
+       void *heap_base, *heap_ptr, *config;
+
+       if (!tboot_enabled())
+               return dmar_tbl;
+
+       /*
+        * ACPI tables may not be DMA protected by tboot, so use DMAR copy
+        * SINIT saved in SinitMleData in TXT heap (which is DMA protected)
+        */
+
+       /* map config space in order to get heap addr */
+       config = ioremap(TXT_PUB_CONFIG_REGS_BASE, NR_TXT_CONFIG_PAGES *
+                        PAGE_SIZE);
+       if (!config)
+               return NULL;
+
+       /* now map TXT heap */
+       heap_base = ioremap(*(u64 *)(config + TXTCR_HEAP_BASE),
+                           *(u64 *)(config + TXTCR_HEAP_SIZE));
+       iounmap(config);
+       if (!heap_base)
+               return NULL;
+
+       /* walk heap to SinitMleData */
+       /* skip BiosData */
+       heap_ptr = heap_base + *(u64 *)heap_base;
+       /* skip OsMleData */
+       heap_ptr += *(u64 *)heap_ptr;
+       /* skip OsSinitData */
+       heap_ptr += *(u64 *)heap_ptr;
+       /* now points to SinitMleDataSize; set to SinitMleData */
+       heap_ptr += sizeof(u64);
+       /* get addr of DMAR table */
+       dmar_tbl = (struct acpi_table_header *)(heap_ptr +
+                  ((struct sinit_mle_data *)heap_ptr)->vtd_dmars_off -
+                  sizeof(u64));
+
+       /* don't unmap heap because dmar.c needs access to this */
+
+       return dmar_tbl;
+}
+
+int tboot_force_iommu(void)
+{
+       if (!tboot_enabled())
+               return 0;
+
+       if (no_iommu || swiotlb || dmar_disabled)
+               pr_warning("Forcing Intel-IOMMU to enabled\n");
+
+       dmar_disabled = 0;
+#ifdef CONFIG_SWIOTLB
+       swiotlb = 0;
+#endif
+       no_iommu = 0;
+
+       return 1;
+}
index 9fc178255c0465e01c35c3d5439fb54866eacaf1..0ccb57d5ee35fc6c7242e435e6780e27bdfff75f 100644 (file)
@@ -348,15 +348,12 @@ SECTIONS
                _end = .;
        }
 
-       /* Sections to be discarded */
-       /DISCARD/ : {
-               *(.exitcall.exit)
-               *(.eh_frame)
-               *(.discard)
-       }
-
         STABS_DEBUG
         DWARF_DEBUG
+
+       /* Sections to be discarded */
+       DISCARDS
+       /DISCARD/ : { *(.eh_frame) }
 }
 
 
index fe6f84ca121ee072d2be8014e2b9b7e959e5abbd..84e236ce76ba9a8afd624cfc4c506ebaa654b926 100644 (file)
@@ -21,7 +21,7 @@
 #include <linux/module.h>
 #include <linux/highmem.h>
 
-int is_io_mapping_possible(resource_size_t base, unsigned long size)
+static int is_io_mapping_possible(resource_size_t base, unsigned long size)
 {
 #if !defined(CONFIG_X86_PAE) && defined(CONFIG_PHYS_ADDR_T_64BIT)
        /* There is no way to map greater than 1 << 32 address without PAE */
@@ -30,7 +30,30 @@ int is_io_mapping_possible(resource_size_t base, unsigned long size)
 #endif
        return 1;
 }
-EXPORT_SYMBOL_GPL(is_io_mapping_possible);
+
+int iomap_create_wc(resource_size_t base, unsigned long size, pgprot_t *prot)
+{
+       unsigned long flag = _PAGE_CACHE_WC;
+       int ret;
+
+       if (!is_io_mapping_possible(base, size))
+               return -EINVAL;
+
+       ret = io_reserve_memtype(base, base + size, &flag);
+       if (ret)
+               return ret;
+
+       *prot = __pgprot(__PAGE_KERNEL | flag);
+       return 0;
+}
+EXPORT_SYMBOL_GPL(iomap_create_wc);
+
+void
+iomap_free(resource_size_t base, unsigned long size)
+{
+       io_free_memtype(base, base + size);
+}
+EXPORT_SYMBOL_GPL(iomap_free);
 
 void *kmap_atomic_prot_pfn(unsigned long pfn, enum km_type type, pgprot_t prot)
 {
index 04e1ad60c63a23a3527960a01cf6e2cff091d959..334e63ca7b2b468d096828cd56684604ca3ab0c4 100644 (file)
@@ -158,24 +158,14 @@ static void __iomem *__ioremap_caller(resource_size_t phys_addr,
        retval = reserve_memtype(phys_addr, (u64)phys_addr + size,
                                                prot_val, &new_prot_val);
        if (retval) {
-               pr_debug("Warning: reserve_memtype returned %d\n", retval);
+               printk(KERN_ERR "ioremap reserve_memtype failed %d\n", retval);
                return NULL;
        }
 
        if (prot_val != new_prot_val) {
-               /*
-                * Do not fallback to certain memory types with certain
-                * requested type:
-                * - request is uc-, return cannot be write-back
-                * - request is uc-, return cannot be write-combine
-                * - request is write-combine, return cannot be write-back
-                */
-               if ((prot_val == _PAGE_CACHE_UC_MINUS &&
-                    (new_prot_val == _PAGE_CACHE_WB ||
-                     new_prot_val == _PAGE_CACHE_WC)) ||
-                   (prot_val == _PAGE_CACHE_WC &&
-                    new_prot_val == _PAGE_CACHE_WB)) {
-                       pr_debug(
+               if (!is_new_memtype_allowed(phys_addr, size,
+                                           prot_val, new_prot_val)) {
+                       printk(KERN_ERR
                "ioremap error for 0x%llx-0x%llx, requested 0x%lx, got 0x%lx\n",
                                (unsigned long long)phys_addr,
                                (unsigned long long)(phys_addr + size),
index 7e600c1962db0c77d2dcb66559b75aff79672580..24952fdc7e407a7cd2f9fe1237012c1c265da11a 100644 (file)
@@ -12,6 +12,7 @@
 #include <linux/seq_file.h>
 #include <linux/debugfs.h>
 #include <linux/pfn.h>
+#include <linux/percpu.h>
 
 #include <asm/e820.h>
 #include <asm/processor.h>
@@ -686,7 +687,7 @@ static int cpa_process_alias(struct cpa_data *cpa)
 {
        struct cpa_data alias_cpa;
        unsigned long laddr = (unsigned long)__va(cpa->pfn << PAGE_SHIFT);
-       unsigned long vaddr, remapped;
+       unsigned long vaddr;
        int ret;
 
        if (cpa->pfn >= max_pfn_mapped)
@@ -744,24 +745,6 @@ static int cpa_process_alias(struct cpa_data *cpa)
        }
 #endif
 
-       /*
-        * If the PMD page was partially used for per-cpu remapping,
-        * the recycled area needs to be split and modified.  Because
-        * the area is always proper subset of a PMD page
-        * cpa->numpages is guaranteed to be 1 for these areas, so
-        * there's no need to loop over and check for further remaps.
-        */
-       remapped = (unsigned long)pcpu_lpage_remapped((void *)laddr);
-       if (remapped) {
-               WARN_ON(cpa->numpages > 1);
-               alias_cpa = *cpa;
-               alias_cpa.vaddr = &remapped;
-               alias_cpa.flags &= ~(CPA_PAGES_ARRAY | CPA_ARRAY);
-               ret = __change_page_attr_set_clr(&alias_cpa, 0);
-               if (ret)
-                       return ret;
-       }
-
        return 0;
 }
 
@@ -822,6 +805,7 @@ static int change_page_attr_set_clr(unsigned long *addr, int numpages,
 {
        struct cpa_data cpa;
        int ret, cache, checkalias;
+       unsigned long baddr = 0;
 
        /*
         * Check, if we are requested to change a not supported
@@ -853,6 +837,11 @@ static int change_page_attr_set_clr(unsigned long *addr, int numpages,
                         */
                        WARN_ON_ONCE(1);
                }
+               /*
+                * Save address for cache flush. *addr is modified in the call
+                * to __change_page_attr_set_clr() below.
+                */
+               baddr = *addr;
        }
 
        /* Must avoid aliasing mappings in the highmem code */
@@ -900,7 +889,7 @@ static int change_page_attr_set_clr(unsigned long *addr, int numpages,
                        cpa_flush_array(addr, numpages, cache,
                                        cpa.flags, pages);
                } else
-                       cpa_flush_range(*addr, numpages, cache);
+                       cpa_flush_range(baddr, numpages, cache);
        } else
                cpa_flush_all(cache);
 
index b2f7d3e59b86b656d49993a5870e9e47651e3d7c..d7ebc3a10f2f1aa96aa00913e4b3f2472149facc 100644 (file)
@@ -15,6 +15,7 @@
 #include <linux/gfp.h>
 #include <linux/mm.h>
 #include <linux/fs.h>
+#include <linux/rbtree.h>
 
 #include <asm/cacheflush.h>
 #include <asm/processor.h>
@@ -148,11 +149,10 @@ static char *cattr_name(unsigned long flags)
  * areas). All the aliases have the same cache attributes of course.
  * Zero attributes are represented as holes.
  *
- * Currently the data structure is a list because the number of mappings
- * are expected to be relatively small. If this should be a problem
- * it could be changed to a rbtree or similar.
+ * The data structure is a list that is also organized as an rbtree
+ * sorted on the start address of memtype range.
  *
- * memtype_lock protects the whole list.
+ * memtype_lock protects both the linear list and rbtree.
  */
 
 struct memtype {
@@ -160,11 +160,53 @@ struct memtype {
        u64                     end;
        unsigned long           type;
        struct list_head        nd;
+       struct rb_node          rb;
 };
 
+static struct rb_root memtype_rbroot = RB_ROOT;
 static LIST_HEAD(memtype_list);
 static DEFINE_SPINLOCK(memtype_lock);  /* protects memtype list */
 
+static struct memtype *memtype_rb_search(struct rb_root *root, u64 start)
+{
+       struct rb_node *node = root->rb_node;
+       struct memtype *last_lower = NULL;
+
+       while (node) {
+               struct memtype *data = container_of(node, struct memtype, rb);
+
+               if (data->start < start) {
+                       last_lower = data;
+                       node = node->rb_right;
+               } else if (data->start > start) {
+                       node = node->rb_left;
+               } else
+                       return data;
+       }
+
+       /* Will return NULL if there is no entry with its start <= start */
+       return last_lower;
+}
+
+static void memtype_rb_insert(struct rb_root *root, struct memtype *data)
+{
+       struct rb_node **new = &(root->rb_node);
+       struct rb_node *parent = NULL;
+
+       while (*new) {
+               struct memtype *this = container_of(*new, struct memtype, rb);
+
+               parent = *new;
+               if (data->start <= this->start)
+                       new = &((*new)->rb_left);
+               else if (data->start > this->start)
+                       new = &((*new)->rb_right);
+       }
+
+       rb_link_node(&data->rb, parent, new);
+       rb_insert_color(&data->rb, root);
+}
+
 /*
  * Does intersection of PAT memory type and MTRR memory type and returns
  * the resulting memory type as PAT understands it.
@@ -218,9 +260,6 @@ chk_conflict(struct memtype *new, struct memtype *entry, unsigned long *type)
        return -EBUSY;
 }
 
-static struct memtype *cached_entry;
-static u64 cached_start;
-
 static int pat_pagerange_is_ram(unsigned long start, unsigned long end)
 {
        int ram_page = 0, not_rampage = 0;
@@ -249,63 +288,61 @@ static int pat_pagerange_is_ram(unsigned long start, unsigned long end)
 }
 
 /*
- * For RAM pages, mark the pages as non WB memory type using
- * PageNonWB (PG_arch_1). We allow only one set_memory_uc() or
- * set_memory_wc() on a RAM page at a time before marking it as WB again.
- * This is ok, because only one driver will be owning the page and
- * doing set_memory_*() calls.
+ * For RAM pages, we use page flags to mark the pages with appropriate type.
+ * Here we do two pass:
+ * - Find the memtype of all the pages in the range, look for any conflicts
+ * - In case of no conflicts, set the new memtype for pages in the range
  *
- * For now, we use PageNonWB to track that the RAM page is being mapped
- * as non WB. In future, we will have to use one more flag
- * (or some other mechanism in page_struct) to distinguish between
- * UC and WC mapping.
+ * Caller must hold memtype_lock for atomicity.
  */
 static int reserve_ram_pages_type(u64 start, u64 end, unsigned long req_type,
                                  unsigned long *new_type)
 {
        struct page *page;
-       u64 pfn, end_pfn;
+       u64 pfn;
+
+       if (req_type == _PAGE_CACHE_UC) {
+               /* We do not support strong UC */
+               WARN_ON_ONCE(1);
+               req_type = _PAGE_CACHE_UC_MINUS;
+       }
 
        for (pfn = (start >> PAGE_SHIFT); pfn < (end >> PAGE_SHIFT); ++pfn) {
-               page = pfn_to_page(pfn);
-               if (page_mapped(page) || PageNonWB(page))
-                       goto out;
+               unsigned long type;
 
-               SetPageNonWB(page);
+               page = pfn_to_page(pfn);
+               type = get_page_memtype(page);
+               if (type != -1) {
+                       printk(KERN_INFO "reserve_ram_pages_type failed "
+                               "0x%Lx-0x%Lx, track 0x%lx, req 0x%lx\n",
+                               start, end, type, req_type);
+                       if (new_type)
+                               *new_type = type;
+
+                       return -EBUSY;
+               }
        }
-       return 0;
 
-out:
-       end_pfn = pfn;
-       for (pfn = (start >> PAGE_SHIFT); pfn < end_pfn; ++pfn) {
+       if (new_type)
+               *new_type = req_type;
+
+       for (pfn = (start >> PAGE_SHIFT); pfn < (end >> PAGE_SHIFT); ++pfn) {
                page = pfn_to_page(pfn);
-               ClearPageNonWB(page);
+               set_page_memtype(page, req_type);
        }
-
-       return -EINVAL;
+       return 0;
 }
 
 static int free_ram_pages_type(u64 start, u64 end)
 {
        struct page *page;
-       u64 pfn, end_pfn;
+       u64 pfn;
 
        for (pfn = (start >> PAGE_SHIFT); pfn < (end >> PAGE_SHIFT); ++pfn) {
                page = pfn_to_page(pfn);
-               if (page_mapped(page) || !PageNonWB(page))
-                       goto out;
-
-               ClearPageNonWB(page);
+               set_page_memtype(page, -1);
        }
        return 0;
-
-out:
-       end_pfn = pfn;
-       for (pfn = (start >> PAGE_SHIFT); pfn < end_pfn; ++pfn) {
-               page = pfn_to_page(pfn);
-               SetPageNonWB(page);
-       }
-       return -EINVAL;
 }
 
 /*
@@ -339,6 +376,8 @@ int reserve_memtype(u64 start, u64 end, unsigned long req_type,
                if (new_type) {
                        if (req_type == -1)
                                *new_type = _PAGE_CACHE_WB;
+                       else if (req_type == _PAGE_CACHE_WC)
+                               *new_type = _PAGE_CACHE_UC_MINUS;
                        else
                                *new_type = req_type & _PAGE_CACHE_MASK;
                }
@@ -364,11 +403,16 @@ int reserve_memtype(u64 start, u64 end, unsigned long req_type,
                *new_type = actual_type;
 
        is_range_ram = pat_pagerange_is_ram(start, end);
-       if (is_range_ram == 1)
-               return reserve_ram_pages_type(start, end, req_type,
-                                             new_type);
-       else if (is_range_ram < 0)
+       if (is_range_ram == 1) {
+
+               spin_lock(&memtype_lock);
+               err = reserve_ram_pages_type(start, end, req_type, new_type);
+               spin_unlock(&memtype_lock);
+
+               return err;
+       } else if (is_range_ram < 0) {
                return -EINVAL;
+       }
 
        new  = kmalloc(sizeof(struct memtype), GFP_KERNEL);
        if (!new)
@@ -380,17 +424,19 @@ int reserve_memtype(u64 start, u64 end, unsigned long req_type,
 
        spin_lock(&memtype_lock);
 
-       if (cached_entry && start >= cached_start)
-               entry = cached_entry;
-       else
+       entry = memtype_rb_search(&memtype_rbroot, new->start);
+       if (likely(entry != NULL)) {
+               /* To work correctly with list_for_each_entry_continue */
+               entry = list_entry(entry->nd.prev, struct memtype, nd);
+       } else {
                entry = list_entry(&memtype_list, struct memtype, nd);
+       }
 
        /* Search for existing mapping that overlaps the current range */
        where = NULL;
        list_for_each_entry_continue(entry, &memtype_list, nd) {
                if (end <= entry->start) {
                        where = entry->nd.prev;
-                       cached_entry = list_entry(where, struct memtype, nd);
                        break;
                } else if (start <= entry->start) { /* end > entry->start */
                        err = chk_conflict(new, entry, new_type);
@@ -398,8 +444,6 @@ int reserve_memtype(u64 start, u64 end, unsigned long req_type,
                                dprintk("Overlap at 0x%Lx-0x%Lx\n",
                                        entry->start, entry->end);
                                where = entry->nd.prev;
-                               cached_entry = list_entry(where,
-                                                       struct memtype, nd);
                        }
                        break;
                } else if (start < entry->end) { /* start > entry->start */
@@ -407,8 +451,6 @@ int reserve_memtype(u64 start, u64 end, unsigned long req_type,
                        if (!err) {
                                dprintk("Overlap at 0x%Lx-0x%Lx\n",
                                        entry->start, entry->end);
-                               cached_entry = list_entry(entry->nd.prev,
-                                                       struct memtype, nd);
 
                                /*
                                 * Move to right position in the linked
@@ -436,13 +478,13 @@ int reserve_memtype(u64 start, u64 end, unsigned long req_type,
                return err;
        }
 
-       cached_start = start;
-
        if (where)
                list_add(&new->nd, where);
        else
                list_add_tail(&new->nd, &memtype_list);
 
+       memtype_rb_insert(&memtype_rbroot, new);
+
        spin_unlock(&memtype_lock);
 
        dprintk("reserve_memtype added 0x%Lx-0x%Lx, track %s, req %s, ret %s\n",
@@ -454,7 +496,7 @@ int reserve_memtype(u64 start, u64 end, unsigned long req_type,
 
 int free_memtype(u64 start, u64 end)
 {
-       struct memtype *entry;
+       struct memtype *entry, *saved_entry;
        int err = -EINVAL;
        int is_range_ram;
 
@@ -466,23 +508,58 @@ int free_memtype(u64 start, u64 end)
                return 0;
 
        is_range_ram = pat_pagerange_is_ram(start, end);
-       if (is_range_ram == 1)
-               return free_ram_pages_type(start, end);
-       else if (is_range_ram < 0)
+       if (is_range_ram == 1) {
+
+               spin_lock(&memtype_lock);
+               err = free_ram_pages_type(start, end);
+               spin_unlock(&memtype_lock);
+
+               return err;
+       } else if (is_range_ram < 0) {
                return -EINVAL;
+       }
 
        spin_lock(&memtype_lock);
+
+       entry = memtype_rb_search(&memtype_rbroot, start);
+       if (unlikely(entry == NULL))
+               goto unlock_ret;
+
+       /*
+        * Saved entry points to an entry with start same or less than what
+        * we searched for. Now go through the list in both directions to look
+        * for the entry that matches with both start and end, with list stored
+        * in sorted start address
+        */
+       saved_entry = entry;
        list_for_each_entry(entry, &memtype_list, nd) {
                if (entry->start == start && entry->end == end) {
-                       if (cached_entry == entry || cached_start == start)
-                               cached_entry = NULL;
+                       rb_erase(&entry->rb, &memtype_rbroot);
+                       list_del(&entry->nd);
+                       kfree(entry);
+                       err = 0;
+                       break;
+               } else if (entry->start > start) {
+                       break;
+               }
+       }
+
+       if (!err)
+               goto unlock_ret;
 
+       entry = saved_entry;
+       list_for_each_entry_reverse(entry, &memtype_list, nd) {
+               if (entry->start == start && entry->end == end) {
+                       rb_erase(&entry->rb, &memtype_rbroot);
                        list_del(&entry->nd);
                        kfree(entry);
                        err = 0;
                        break;
+               } else if (entry->start < start) {
+                       break;
                }
        }
+unlock_ret:
        spin_unlock(&memtype_lock);
 
        if (err) {
@@ -496,6 +573,101 @@ int free_memtype(u64 start, u64 end)
 }
 
 
+/**
+ * lookup_memtype - Looksup the memory type for a physical address
+ * @paddr: physical address of which memory type needs to be looked up
+ *
+ * Only to be called when PAT is enabled
+ *
+ * Returns _PAGE_CACHE_WB, _PAGE_CACHE_WC, _PAGE_CACHE_UC_MINUS or
+ * _PAGE_CACHE_UC
+ */
+static unsigned long lookup_memtype(u64 paddr)
+{
+       int rettype = _PAGE_CACHE_WB;
+       struct memtype *entry;
+
+       if (is_ISA_range(paddr, paddr + PAGE_SIZE - 1))
+               return rettype;
+
+       if (pat_pagerange_is_ram(paddr, paddr + PAGE_SIZE)) {
+               struct page *page;
+               spin_lock(&memtype_lock);
+               page = pfn_to_page(paddr >> PAGE_SHIFT);
+               rettype = get_page_memtype(page);
+               spin_unlock(&memtype_lock);
+               /*
+                * -1 from get_page_memtype() implies RAM page is in its
+                * default state and not reserved, and hence of type WB
+                */
+               if (rettype == -1)
+                       rettype = _PAGE_CACHE_WB;
+
+               return rettype;
+       }
+
+       spin_lock(&memtype_lock);
+
+       entry = memtype_rb_search(&memtype_rbroot, paddr);
+       if (entry != NULL)
+               rettype = entry->type;
+       else
+               rettype = _PAGE_CACHE_UC_MINUS;
+
+       spin_unlock(&memtype_lock);
+       return rettype;
+}
+
+/**
+ * io_reserve_memtype - Request a memory type mapping for a region of memory
+ * @start: start (physical address) of the region
+ * @end: end (physical address) of the region
+ * @type: A pointer to memtype, with requested type. On success, requested
+ * or any other compatible type that was available for the region is returned
+ *
+ * On success, returns 0
+ * On failure, returns non-zero
+ */
+int io_reserve_memtype(resource_size_t start, resource_size_t end,
+                       unsigned long *type)
+{
+       resource_size_t size = end - start;
+       unsigned long req_type = *type;
+       unsigned long new_type;
+       int ret;
+
+       WARN_ON_ONCE(iomem_map_sanity_check(start, size));
+
+       ret = reserve_memtype(start, end, req_type, &new_type);
+       if (ret)
+               goto out_err;
+
+       if (!is_new_memtype_allowed(start, size, req_type, new_type))
+               goto out_free;
+
+       if (kernel_map_sync_memtype(start, size, new_type) < 0)
+               goto out_free;
+
+       *type = new_type;
+       return 0;
+
+out_free:
+       free_memtype(start, end);
+       ret = -EBUSY;
+out_err:
+       return ret;
+}
+
+/**
+ * io_free_memtype - Release a memory type mapping for a region of memory
+ * @start: start (physical address) of the region
+ * @end: end (physical address) of the region
+ */
+void io_free_memtype(resource_size_t start, resource_size_t end)
+{
+       free_memtype(start, end);
+}
+
 pgprot_t phys_mem_access_prot(struct file *file, unsigned long pfn,
                                unsigned long size, pgprot_t vma_prot)
 {
@@ -577,7 +749,7 @@ int kernel_map_sync_memtype(u64 base, unsigned long size, unsigned long flags)
 {
        unsigned long id_sz;
 
-       if (!pat_enabled || base >= __pa(high_memory))
+       if (base >= __pa(high_memory))
                return 0;
 
        id_sz = (__pa(high_memory) < base + size) ?
@@ -612,11 +784,29 @@ static int reserve_pfn_range(u64 paddr, unsigned long size, pgprot_t *vma_prot,
        is_ram = pat_pagerange_is_ram(paddr, paddr + size);
 
        /*
-        * reserve_pfn_range() doesn't support RAM pages. Maintain the current
-        * behavior with RAM pages by returning success.
+        * reserve_pfn_range() for RAM pages. We do not refcount to keep
+        * track of number of mappings of RAM pages. We can assert that
+        * the type requested matches the type of first page in the range.
         */
-       if (is_ram != 0)
+       if (is_ram) {
+               if (!pat_enabled)
+                       return 0;
+
+               flags = lookup_memtype(paddr);
+               if (want_flags != flags) {
+                       printk(KERN_WARNING
+                       "%s:%d map pfn RAM range req %s for %Lx-%Lx, got %s\n",
+                               current->comm, current->pid,
+                               cattr_name(want_flags),
+                               (unsigned long long)paddr,
+                               (unsigned long long)(paddr + size),
+                               cattr_name(flags));
+                       *vma_prot = __pgprot((pgprot_val(*vma_prot) &
+                                             (~_PAGE_CACHE_MASK)) |
+                                            flags);
+               }
                return 0;
+       }
 
        ret = reserve_memtype(paddr, paddr + size, want_flags, &flags);
        if (ret)
@@ -678,14 +868,6 @@ int track_pfn_vma_copy(struct vm_area_struct *vma)
        unsigned long vma_size = vma->vm_end - vma->vm_start;
        pgprot_t pgprot;
 
-       if (!pat_enabled)
-               return 0;
-
-       /*
-        * For now, only handle remap_pfn_range() vmas where
-        * is_linear_pfn_mapping() == TRUE. Handling of
-        * vm_insert_pfn() is TBD.
-        */
        if (is_linear_pfn_mapping(vma)) {
                /*
                 * reserve the whole chunk covered by vma. We need the
@@ -713,23 +895,24 @@ int track_pfn_vma_copy(struct vm_area_struct *vma)
 int track_pfn_vma_new(struct vm_area_struct *vma, pgprot_t *prot,
                        unsigned long pfn, unsigned long size)
 {
+       unsigned long flags;
        resource_size_t paddr;
        unsigned long vma_size = vma->vm_end - vma->vm_start;
 
-       if (!pat_enabled)
-               return 0;
-
-       /*
-        * For now, only handle remap_pfn_range() vmas where
-        * is_linear_pfn_mapping() == TRUE. Handling of
-        * vm_insert_pfn() is TBD.
-        */
        if (is_linear_pfn_mapping(vma)) {
                /* reserve the whole chunk starting from vm_pgoff */
                paddr = (resource_size_t)vma->vm_pgoff << PAGE_SHIFT;
                return reserve_pfn_range(paddr, vma_size, prot, 0);
        }
 
+       if (!pat_enabled)
+               return 0;
+
+       /* for vm_insert_pfn and friends, we set prot based on lookup */
+       flags = lookup_memtype(pfn << PAGE_SHIFT);
+       *prot = __pgprot((pgprot_val(vma->vm_page_prot) & (~_PAGE_CACHE_MASK)) |
+                        flags);
+
        return 0;
 }
 
@@ -744,14 +927,6 @@ void untrack_pfn_vma(struct vm_area_struct *vma, unsigned long pfn,
        resource_size_t paddr;
        unsigned long vma_size = vma->vm_end - vma->vm_start;
 
-       if (!pat_enabled)
-               return;
-
-       /*
-        * For now, only handle remap_pfn_range() vmas where
-        * is_linear_pfn_mapping() == TRUE. Handling of
-        * vm_insert_pfn() is TBD.
-        */
        if (is_linear_pfn_mapping(vma)) {
                /* free the whole chunk starting from vm_pgoff */
                paddr = (resource_size_t)vma->vm_pgoff << PAGE_SHIFT;
index b3d20b9cac6366922d189572396d7c805c6680b2..417c9f5b4afa700477ec29d26ac41945828eddfb 100644 (file)
@@ -242,7 +242,7 @@ static void __restore_processor_state(struct saved_context *ctxt)
        fix_processor_context();
 
        do_fpu_end();
-       mtrr_ap_init();
+       mtrr_bp_restore();
 
 #ifdef CONFIG_X86_OLD_MCE
        mcheck_init(&boot_cpu_data);
index 41c159cd872f14bb55893c42c7c158cfacb6b6ac..921b6ff3b6450e430f7b6613c139767280b39df9 100644 (file)
@@ -280,15 +280,6 @@ SECTIONS
     *(.ResetVector.text)
   }
 
-  /* Sections to be discarded */
-  /DISCARD/ :
-  {
-       *(.exit.literal)
-       EXIT_TEXT
-       EXIT_DATA
-        *(.exitcall.exit)
-  }
-
   .xt.lit : { *(.xt.lit) }
   .xt.prop : { *(.xt.prop) }
 
@@ -321,4 +312,8 @@ SECTIONS
     *(.xt.lit)
     *(.gnu.linkonce.p*)
   }
+
+  /* Sections to be discarded */
+  DISCARDS
+  /DISCARD/ : { *(.exit.literal) }
 }
index 7a12cf6ee1d35e212a6d26007a1eb2057c189357..ce8ba57c6557b7513caba52e19a46b2de5a4f725 100644 (file)
@@ -146,7 +146,7 @@ enum arq_state {
 #define RQ_STATE(rq)   ((enum arq_state)(rq)->elevator_private2)
 #define RQ_SET_STATE(rq, state)        ((rq)->elevator_private2 = (void *) state)
 
-static DEFINE_PER_CPU(unsigned long, ioc_count);
+static DEFINE_PER_CPU(unsigned long, as_ioc_count);
 static struct completion *ioc_gone;
 static DEFINE_SPINLOCK(ioc_gone_lock);
 
@@ -161,7 +161,7 @@ static void as_antic_stop(struct as_data *ad);
 static void free_as_io_context(struct as_io_context *aic)
 {
        kfree(aic);
-       elv_ioc_count_dec(ioc_count);
+       elv_ioc_count_dec(as_ioc_count);
        if (ioc_gone) {
                /*
                 * AS scheduler is exiting, grab exit lock and check
@@ -169,7 +169,7 @@ static void free_as_io_context(struct as_io_context *aic)
                 * complete ioc_gone and set it back to NULL.
                 */
                spin_lock(&ioc_gone_lock);
-               if (ioc_gone && !elv_ioc_count_read(ioc_count)) {
+               if (ioc_gone && !elv_ioc_count_read(as_ioc_count)) {
                        complete(ioc_gone);
                        ioc_gone = NULL;
                }
@@ -211,7 +211,7 @@ static struct as_io_context *alloc_as_io_context(void)
                ret->seek_total = 0;
                ret->seek_samples = 0;
                ret->seek_mean = 0;
-               elv_ioc_count_inc(ioc_count);
+               elv_ioc_count_inc(as_ioc_count);
        }
 
        return ret;
@@ -1507,7 +1507,7 @@ static void __exit as_exit(void)
        ioc_gone = &all_gone;
        /* ioc_gone's update must be visible before reading ioc_count */
        smp_wmb();
-       if (elv_ioc_count_read(ioc_count))
+       if (elv_ioc_count_read(as_ioc_count))
                wait_for_completion(&all_gone);
        synchronize_rcu();
 }
index 0e3814b662af3f7f1bd7c2f074d95150535ab132..1ca813b16e7840cf10086d79b7e2bb7b0c07005e 100644 (file)
@@ -48,7 +48,7 @@ static int cfq_slice_idle = HZ / 125;
 static struct kmem_cache *cfq_pool;
 static struct kmem_cache *cfq_ioc_pool;
 
-static DEFINE_PER_CPU(unsigned long, ioc_count);
+static DEFINE_PER_CPU(unsigned long, cfq_ioc_count);
 static struct completion *ioc_gone;
 static DEFINE_SPINLOCK(ioc_gone_lock);
 
@@ -1415,7 +1415,7 @@ static void cfq_cic_free_rcu(struct rcu_head *head)
        cic = container_of(head, struct cfq_io_context, rcu_head);
 
        kmem_cache_free(cfq_ioc_pool, cic);
-       elv_ioc_count_dec(ioc_count);
+       elv_ioc_count_dec(cfq_ioc_count);
 
        if (ioc_gone) {
                /*
@@ -1424,7 +1424,7 @@ static void cfq_cic_free_rcu(struct rcu_head *head)
                 * complete ioc_gone and set it back to NULL
                 */
                spin_lock(&ioc_gone_lock);
-               if (ioc_gone && !elv_ioc_count_read(ioc_count)) {
+               if (ioc_gone && !elv_ioc_count_read(cfq_ioc_count)) {
                        complete(ioc_gone);
                        ioc_gone = NULL;
                }
@@ -1550,7 +1550,7 @@ cfq_alloc_io_context(struct cfq_data *cfqd, gfp_t gfp_mask)
                INIT_HLIST_NODE(&cic->cic_list);
                cic->dtor = cfq_free_io_context;
                cic->exit = cfq_exit_io_context;
-               elv_ioc_count_inc(ioc_count);
+               elv_ioc_count_inc(cfq_ioc_count);
        }
 
        return cic;
@@ -2654,7 +2654,7 @@ static void __exit cfq_exit(void)
         * this also protects us from entering cfq_slab_kill() with
         * pending RCU callbacks
         */
-       if (elv_ioc_count_read(ioc_count))
+       if (elv_ioc_count_read(cfq_ioc_count))
                wait_for_completion(&all_gone);
        cfq_slab_kill();
 }
index db307a356f08b02edeb73597cc5893c1d3d45e9e..cc22f9a585b094fba931e775678661ce829ca21e 100644 (file)
@@ -45,6 +45,7 @@
 #include <acpi/acpi.h>
 #include "accommon.h"
 #include "actables.h"
+#include <linux/tboot.h>
 
 #define _COMPONENT          ACPI_HARDWARE
 ACPI_MODULE_NAME("hwsleep")
@@ -342,6 +343,8 @@ acpi_status asmlinkage acpi_enter_sleep_state(u8 sleep_state)
 
        ACPI_FLUSH_CPU_CACHE();
 
+       tboot_sleep(sleep_state, pm1a_control, pm1b_control);
+
        /* Write #2: Write both SLP_TYP + SLP_EN */
 
        status = acpi_hw_write_pm1_control(pm1a_control, pm1b_control);
index 095f97e6066562671eaad46eed57478aa3bafaf7..c8753a9ed290766c84cf3f7cd9da4b096b789270 100644 (file)
@@ -13,8 +13,8 @@
 #include <linux/proc_fs.h>
 #include <linux/seq_file.h>
 
+#include <asm/cell-regs.h>
 #include <asm/firmware.h>
-#include <asm/iommu.h>
 #include <asm/lv1call.h>
 #include <asm/ps3.h>
 #include <asm/ps3gpu.h>
index 178e2e9e9f0902c1f11a0e09ab6a1ff12e5556f7..d6f36c004d9b7edeeea488f77ed9984639de607b 100644 (file)
@@ -107,7 +107,7 @@ struct agp_bridge_driver {
        void (*agp_enable)(struct agp_bridge_data *, u32);
        void (*cleanup)(void);
        void (*tlb_flush)(struct agp_memory *);
-       unsigned long (*mask_memory)(struct agp_bridge_data *, struct page *, int);
+       unsigned long (*mask_memory)(struct agp_bridge_data *, dma_addr_t, int);
        void (*cache_flush)(void);
        int (*create_gatt_table)(struct agp_bridge_data *);
        int (*free_gatt_table)(struct agp_bridge_data *);
@@ -121,6 +121,11 @@ struct agp_bridge_driver {
        void (*agp_destroy_pages)(struct agp_memory *);
        int (*agp_type_to_mask_type) (struct agp_bridge_data *, int);
        void (*chipset_flush)(struct agp_bridge_data *);
+
+       int (*agp_map_page)(struct page *page, dma_addr_t *ret);
+       void (*agp_unmap_page)(struct page *page, dma_addr_t dma);
+       int (*agp_map_memory)(struct agp_memory *mem);
+       void (*agp_unmap_memory)(struct agp_memory *mem);
 };
 
 struct agp_bridge_data {
@@ -134,7 +139,8 @@ struct agp_bridge_data {
        u32 __iomem *gatt_table;
        u32 *gatt_table_real;
        unsigned long scratch_page;
-       unsigned long scratch_page_real;
+       struct page *scratch_page_page;
+       dma_addr_t scratch_page_dma;
        unsigned long gart_bus_addr;
        unsigned long gatt_bus_addr;
        u32 mode;
@@ -291,7 +297,7 @@ int agp_3_5_enable(struct agp_bridge_data *bridge);
 void global_cache_flush(void);
 void get_agp_version(struct agp_bridge_data *bridge);
 unsigned long agp_generic_mask_memory(struct agp_bridge_data *bridge,
-                                     struct page *page, int type);
+                                     dma_addr_t phys, int type);
 int agp_generic_type_to_mask_type(struct agp_bridge_data *bridge,
                                  int type);
 struct agp_bridge_data *agp_generic_find_bridge(struct pci_dev *pdev);
@@ -312,9 +318,6 @@ void agp3_generic_cleanup(void);
 #define AGP_GENERIC_SIZES_ENTRIES 11
 extern const struct aper_size_info_16 agp3_generic_sizes[];
 
-#define virt_to_gart(x) (phys_to_gart(virt_to_phys(x)))
-#define gart_to_virt(x) (phys_to_virt(gart_to_phys(x)))
-
 extern int agp_off;
 extern int agp_try_unsupported_boot;
 
index 201ef3ffd48456b391d609c55377ee0f2ca8091f..d2ce68f27e4b0b478fdf2cb6f70b10e0fc4fac1b 100644 (file)
@@ -152,7 +152,7 @@ static struct page *m1541_alloc_page(struct agp_bridge_data *bridge)
        pci_read_config_dword(agp_bridge->dev, ALI_CACHE_FLUSH_CTRL, &temp);
        pci_write_config_dword(agp_bridge->dev, ALI_CACHE_FLUSH_CTRL,
                        (((temp & ALI_CACHE_FLUSH_ADDR_MASK) |
-                         phys_to_gart(page_to_phys(page))) | ALI_CACHE_FLUSH_EN ));
+                         page_to_phys(page)) | ALI_CACHE_FLUSH_EN ));
        return page;
 }
 
@@ -180,7 +180,7 @@ static void m1541_destroy_page(struct page *page, int flags)
                pci_read_config_dword(agp_bridge->dev, ALI_CACHE_FLUSH_CTRL, &temp);
                pci_write_config_dword(agp_bridge->dev, ALI_CACHE_FLUSH_CTRL,
                                       (((temp & ALI_CACHE_FLUSH_ADDR_MASK) |
-                                        phys_to_gart(page_to_phys(page))) | ALI_CACHE_FLUSH_EN));
+                                        page_to_phys(page)) | ALI_CACHE_FLUSH_EN));
        }
        agp_generic_destroy_page(page, flags);
 }
index ba9bde71eaaff38557bd4f151817b896c5b48b2e..73dbf40c874d956900819ffb6502e620bfcaa917 100644 (file)
@@ -44,7 +44,7 @@ static int amd_create_page_map(struct amd_page_map *page_map)
 #ifndef CONFIG_X86
        SetPageReserved(virt_to_page(page_map->real));
        global_cache_flush();
-       page_map->remapped = ioremap_nocache(virt_to_gart(page_map->real),
+       page_map->remapped = ioremap_nocache(virt_to_phys(page_map->real),
                                            PAGE_SIZE);
        if (page_map->remapped == NULL) {
                ClearPageReserved(virt_to_page(page_map->real));
@@ -160,7 +160,7 @@ static int amd_create_gatt_table(struct agp_bridge_data *bridge)
 
        agp_bridge->gatt_table_real = (u32 *)page_dir.real;
        agp_bridge->gatt_table = (u32 __iomem *)page_dir.remapped;
-       agp_bridge->gatt_bus_addr = virt_to_gart(page_dir.real);
+       agp_bridge->gatt_bus_addr = virt_to_phys(page_dir.real);
 
        /* Get the address for the gart region.
         * This is a bus address even on the alpha, b/c its
@@ -173,7 +173,7 @@ static int amd_create_gatt_table(struct agp_bridge_data *bridge)
 
        /* Calculate the agp offset */
        for (i = 0; i < value->num_entries / 1024; i++, addr += 0x00400000) {
-               writel(virt_to_gart(amd_irongate_private.gatt_pages[i]->real) | 1,
+               writel(virt_to_phys(amd_irongate_private.gatt_pages[i]->real) | 1,
                        page_dir.remapped+GET_PAGE_DIR_OFF(addr));
                readl(page_dir.remapped+GET_PAGE_DIR_OFF(addr));        /* PCI Posting. */
        }
@@ -325,7 +325,9 @@ static int amd_insert_memory(struct agp_memory *mem, off_t pg_start, int type)
                addr = (j * PAGE_SIZE) + agp_bridge->gart_bus_addr;
                cur_gatt = GET_GATT(addr);
                writel(agp_generic_mask_memory(agp_bridge,
-                       mem->pages[i], mem->type), cur_gatt+GET_GATT_OFF(addr));
+                                              page_to_phys(mem->pages[i]),
+                                              mem->type),
+                      cur_gatt+GET_GATT_OFF(addr));
                readl(cur_gatt+GET_GATT_OFF(addr));     /* PCI Posting. */
        }
        amd_irongate_tlbflush(mem);
index 3bf5dda90f4aeaf38b9286bf395518a42cc2b9d1..2fb2e6cc322aab1a36164de3fc99674559dea9ed 100644 (file)
@@ -79,7 +79,8 @@ static int amd64_insert_memory(struct agp_memory *mem, off_t pg_start, int type)
 
        for (i = 0, j = pg_start; i < mem->page_count; i++, j++) {
                tmp = agp_bridge->driver->mask_memory(agp_bridge,
-                       mem->pages[i], mask_type);
+                                                     page_to_phys(mem->pages[i]),
+                                                     mask_type);
 
                BUG_ON(tmp & 0xffffff0000000ffcULL);
                pte = (tmp & 0x000000ff00000000ULL) >> 28;
@@ -177,7 +178,7 @@ static const struct aper_size_info_32 amd_8151_sizes[7] =
 
 static int amd_8151_configure(void)
 {
-       unsigned long gatt_bus = virt_to_gart(agp_bridge->gatt_table_real);
+       unsigned long gatt_bus = virt_to_phys(agp_bridge->gatt_table_real);
        int i;
 
        /* Configure AGP regs in each x86-64 host bridge. */
@@ -557,7 +558,7 @@ static void __devexit agp_amd64_remove(struct pci_dev *pdev)
 {
        struct agp_bridge_data *bridge = pci_get_drvdata(pdev);
 
-       release_mem_region(virt_to_gart(bridge->gatt_table_real),
+       release_mem_region(virt_to_phys(bridge->gatt_table_real),
                           amd64_aperture_sizes[bridge->aperture_size_idx].size);
        agp_remove_bridge(bridge);
        agp_put_bridge(bridge);
index 33656e144cc5ae6b46787c73f7ded99cc87eca9c..3b2ecbe86ebee875bc76057fad264821671d6f2a 100644 (file)
@@ -302,7 +302,8 @@ static int ati_insert_memory(struct agp_memory * mem,
                addr = (j * PAGE_SIZE) + agp_bridge->gart_bus_addr;
                cur_gatt = GET_GATT(addr);
                writel(agp_bridge->driver->mask_memory(agp_bridge,      
-                                                      mem->pages[i], mem->type),
+                                                      page_to_phys(mem->pages[i]),
+                                                      mem->type),
                       cur_gatt+GET_GATT_OFF(addr));
        }
        readl(GET_GATT(agp_bridge->gart_bus_addr)); /* PCI posting */
@@ -359,7 +360,7 @@ static int ati_create_gatt_table(struct agp_bridge_data *bridge)
 
        agp_bridge->gatt_table_real = (u32 *)page_dir.real;
        agp_bridge->gatt_table = (u32 __iomem *) page_dir.remapped;
-       agp_bridge->gatt_bus_addr = virt_to_gart(page_dir.real);
+       agp_bridge->gatt_bus_addr = virt_to_phys(page_dir.real);
 
        /* Write out the size register */
        current_size = A_SIZE_LVL2(agp_bridge->current_size);
@@ -389,7 +390,7 @@ static int ati_create_gatt_table(struct agp_bridge_data *bridge)
 
        /* Calculate the agp offset */
        for (i = 0; i < value->num_entries / 1024; i++, addr += 0x00400000) {
-               writel(virt_to_gart(ati_generic_private.gatt_pages[i]->real) | 1,
+               writel(virt_to_phys(ati_generic_private.gatt_pages[i]->real) | 1,
                        page_dir.remapped+GET_PAGE_DIR_OFF(addr));
                readl(page_dir.remapped+GET_PAGE_DIR_OFF(addr));        /* PCI Posting. */
        }
index cfa5a649dfe766d3d814637a435fb7d83fb80dc2..ad87753f6de44ecb277c2904c214271cd8078d1f 100644 (file)
@@ -149,9 +149,21 @@ static int agp_backend_initialize(struct agp_bridge_data *bridge)
                        return -ENOMEM;
                }
 
-               bridge->scratch_page_real = phys_to_gart(page_to_phys(page));
-               bridge->scratch_page =
-                   bridge->driver->mask_memory(bridge, page, 0);
+               bridge->scratch_page_page = page;
+               if (bridge->driver->agp_map_page) {
+                       if (bridge->driver->agp_map_page(page,
+                                                        &bridge->scratch_page_dma)) {
+                               dev_err(&bridge->dev->dev,
+                                       "unable to dma-map scratch page\n");
+                               rc = -ENOMEM;
+                               goto err_out_nounmap;
+                       }
+               } else {
+                       bridge->scratch_page_dma = page_to_phys(page);
+               }
+
+               bridge->scratch_page = bridge->driver->mask_memory(bridge,
+                                                  bridge->scratch_page_dma, 0);
        }
 
        size_value = bridge->driver->fetch_size();
@@ -191,8 +203,14 @@ static int agp_backend_initialize(struct agp_bridge_data *bridge)
        return 0;
 
 err_out:
+       if (bridge->driver->needs_scratch_page &&
+           bridge->driver->agp_unmap_page) {
+               bridge->driver->agp_unmap_page(bridge->scratch_page_page,
+                                              bridge->scratch_page_dma);
+       }
+err_out_nounmap:
        if (bridge->driver->needs_scratch_page) {
-               void *va = gart_to_virt(bridge->scratch_page_real);
+               void *va = page_address(bridge->scratch_page_page);
 
                bridge->driver->agp_destroy_page(va, AGP_PAGE_DESTROY_UNMAP);
                bridge->driver->agp_destroy_page(va, AGP_PAGE_DESTROY_FREE);
@@ -219,7 +237,11 @@ static void agp_backend_cleanup(struct agp_bridge_data *bridge)
 
        if (bridge->driver->agp_destroy_page &&
            bridge->driver->needs_scratch_page) {
-               void *va = gart_to_virt(bridge->scratch_page_real);
+               void *va = page_address(bridge->scratch_page_page);
+
+               if (bridge->driver->agp_unmap_page)
+                       bridge->driver->agp_unmap_page(bridge->scratch_page_page,
+                                                      bridge->scratch_page_dma);
 
                bridge->driver->agp_destroy_page(va, AGP_PAGE_DESTROY_UNMAP);
                bridge->driver->agp_destroy_page(va, AGP_PAGE_DESTROY_FREE);
index 35d50f2861b61a37c1ae105040a6938d1483d3bf..793f39ea96189a80fb5c6849b57099a11952a760 100644 (file)
@@ -67,7 +67,7 @@ static const struct gatt_mask efficeon_generic_masks[] =
 /* This function does the same thing as mask_memory() for this chipset... */
 static inline unsigned long efficeon_mask_memory(struct page *page)
 {
-       unsigned long addr = phys_to_gart(page_to_phys(page));
+       unsigned long addr = page_to_phys(page);
        return addr | 0x00000001;
 }
 
@@ -226,7 +226,7 @@ static int efficeon_create_gatt_table(struct agp_bridge_data *bridge)
 
                efficeon_private.l1_table[index] = page;
 
-               value = virt_to_gart((unsigned long *)page) | pati | present | index;
+               value = virt_to_phys((unsigned long *)page) | pati | present | index;
 
                pci_write_config_dword(agp_bridge->dev,
                        EFFICEON_ATTPAGE, value);
index 1e8b461b91f1a5026454623dcb5984e3bf64bf5f..c50543966eb22deaf622ff991f888a61e587910a 100644 (file)
@@ -437,6 +437,12 @@ int agp_bind_memory(struct agp_memory *curr, off_t pg_start)
                curr->bridge->driver->cache_flush();
                curr->is_flushed = true;
        }
+
+       if (curr->bridge->driver->agp_map_memory) {
+               ret_val = curr->bridge->driver->agp_map_memory(curr);
+               if (ret_val)
+                       return ret_val;
+       }
        ret_val = curr->bridge->driver->insert_memory(curr, pg_start, curr->type);
 
        if (ret_val != 0)
@@ -478,6 +484,9 @@ int agp_unbind_memory(struct agp_memory *curr)
        if (ret_val != 0)
                return ret_val;
 
+       if (curr->bridge->driver->agp_unmap_memory)
+               curr->bridge->driver->agp_unmap_memory(curr);
+
        curr->is_bound = false;
        curr->pg_start = 0;
        spin_lock(&curr->bridge->mapped_lock);
@@ -979,7 +988,7 @@ int agp_generic_create_gatt_table(struct agp_bridge_data *bridge)
        set_memory_uc((unsigned long)table, 1 << page_order);
        bridge->gatt_table = (void *)table;
 #else
-       bridge->gatt_table = ioremap_nocache(virt_to_gart(table),
+       bridge->gatt_table = ioremap_nocache(virt_to_phys(table),
                                        (PAGE_SIZE * (1 << page_order)));
        bridge->driver->cache_flush();
 #endif
@@ -992,7 +1001,7 @@ int agp_generic_create_gatt_table(struct agp_bridge_data *bridge)
 
                return -ENOMEM;
        }
-       bridge->gatt_bus_addr = virt_to_gart(bridge->gatt_table_real);
+       bridge->gatt_bus_addr = virt_to_phys(bridge->gatt_table_real);
 
        /* AK: bogus, should encode addresses > 4GB */
        for (i = 0; i < num_entries; i++) {
@@ -1132,7 +1141,9 @@ int agp_generic_insert_memory(struct agp_memory * mem, off_t pg_start, int type)
        }
 
        for (i = 0, j = pg_start; i < mem->page_count; i++, j++) {
-               writel(bridge->driver->mask_memory(bridge, mem->pages[i], mask_type),
+               writel(bridge->driver->mask_memory(bridge,
+                                                  page_to_phys(mem->pages[i]),
+                                                  mask_type),
                       bridge->gatt_table+j);
        }
        readl(bridge->gatt_table+j-1);  /* PCI Posting. */
@@ -1347,9 +1358,8 @@ void global_cache_flush(void)
 EXPORT_SYMBOL(global_cache_flush);
 
 unsigned long agp_generic_mask_memory(struct agp_bridge_data *bridge,
-                                     struct page *page, int type)
+                                     dma_addr_t addr, int type)
 {
-       unsigned long addr = phys_to_gart(page_to_phys(page));
        /* memory type is ignored in the generic routine */
        if (bridge->driver->masks)
                return addr | bridge->driver->masks[0].mask;
index 8f3d4c184914accd9dc4a934b905808f795472ce..501e293e5ad0a1117f5b647f220a002799cef4c3 100644 (file)
@@ -107,7 +107,7 @@ static int __init hp_zx1_ioc_shared(void)
        hp->gart_size = HP_ZX1_GART_SIZE;
        hp->gatt_entries = hp->gart_size / hp->io_page_size;
 
-       hp->io_pdir = gart_to_virt(readq(hp->ioc_regs+HP_ZX1_PDIR_BASE));
+       hp->io_pdir = phys_to_virt(readq(hp->ioc_regs+HP_ZX1_PDIR_BASE));
        hp->gatt = &hp->io_pdir[HP_ZX1_IOVA_TO_PDIR(hp->gart_base)];
 
        if (hp->gatt[0] != HP_ZX1_SBA_IOMMU_COOKIE) {
@@ -246,7 +246,7 @@ hp_zx1_configure (void)
        agp_bridge->mode = readl(hp->lba_regs+hp->lba_cap_offset+PCI_AGP_STATUS);
 
        if (hp->io_pdir_owner) {
-               writel(virt_to_gart(hp->io_pdir), hp->ioc_regs+HP_ZX1_PDIR_BASE);
+               writel(virt_to_phys(hp->io_pdir), hp->ioc_regs+HP_ZX1_PDIR_BASE);
                readl(hp->ioc_regs+HP_ZX1_PDIR_BASE);
                writel(hp->io_tlb_ps, hp->ioc_regs+HP_ZX1_TCNFG);
                readl(hp->ioc_regs+HP_ZX1_TCNFG);
@@ -394,10 +394,8 @@ hp_zx1_remove_memory (struct agp_memory *mem, off_t pg_start, int type)
 }
 
 static unsigned long
-hp_zx1_mask_memory (struct agp_bridge_data *bridge,
-                   struct page *page, int type)
+hp_zx1_mask_memory (struct agp_bridge_data *bridge, dma_addr_t addr, int type)
 {
-       unsigned long addr = phys_to_gart(page_to_phys(page));
        return HP_ZX1_PDIR_VALID_BIT | addr;
 }
 
index 60cc35bb5db7eaebe48510b439bac92b4254c7f7..e763d3312ce7774b2f17dda9aabe72a48c00aa4f 100644 (file)
@@ -61,7 +61,7 @@
 #define WR_FLUSH_GATT(index)   RD_GATT(index)
 
 static unsigned long i460_mask_memory (struct agp_bridge_data *bridge,
-                                      unsigned long addr, int type);
+                                      dma_addr_t addr, int type);
 
 static struct {
        void *gatt;                             /* ioremap'd GATT area */
@@ -325,7 +325,7 @@ static int i460_insert_memory_small_io_page (struct agp_memory *mem,
 
        io_page_size = 1UL << I460_IO_PAGE_SHIFT;
        for (i = 0, j = io_pg_start; i < mem->page_count; i++) {
-               paddr = phys_to_gart(page_to_phys(mem->pages[i]));
+               paddr = page_to_phys(mem->pages[i]);
                for (k = 0; k < I460_IOPAGES_PER_KPAGE; k++, j++, paddr += io_page_size)
                        WR_GATT(j, i460_mask_memory(agp_bridge, paddr, mem->type));
        }
@@ -382,7 +382,7 @@ static int i460_alloc_large_page (struct lp_desc *lp)
                return -ENOMEM;
        }
 
-       lp->paddr = phys_to_gart(page_to_phys(lp->page));
+       lp->paddr = page_to_phys(lp->page);
        lp->refcount = 0;
        atomic_add(I460_KPAGES_PER_IOPAGE, &agp_bridge->current_memory_agp);
        return 0;
@@ -546,20 +546,13 @@ static void i460_destroy_page (struct page *page, int flags)
 #endif /* I460_LARGE_IO_PAGES */
 
 static unsigned long i460_mask_memory (struct agp_bridge_data *bridge,
-                                      unsigned long addr, int type)
+                                      dma_addr_t addr, int type)
 {
        /* Make sure the returned address is a valid GATT entry */
        return bridge->driver->masks[0].mask
                | (((addr & ~((1 << I460_IO_PAGE_SHIFT) - 1)) & 0xfffff000) >> 12);
 }
 
-static unsigned long i460_page_mask_memory(struct agp_bridge_data *bridge,
-                                          struct page *page, int type)
-{
-       unsigned long addr = phys_to_gart(page_to_phys(page));
-       return i460_mask_memory(bridge, addr, type);
-}
-
 const struct agp_bridge_driver intel_i460_driver = {
        .owner                  = THIS_MODULE,
        .aperture_sizes         = i460_sizes,
@@ -569,7 +562,7 @@ const struct agp_bridge_driver intel_i460_driver = {
        .fetch_size             = i460_fetch_size,
        .cleanup                = i460_cleanup,
        .tlb_flush              = i460_tlb_flush,
-       .mask_memory            = i460_page_mask_memory,
+       .mask_memory            = i460_mask_memory,
        .masks                  = i460_masks,
        .agp_enable             = agp_generic_enable,
        .cache_flush            = global_cache_flush,
index c58557790585dfe6a0d56dba70fabb3764a3e2c6..1540e693d91ebf3f886ad650eb067e6a297b4e3e 100644 (file)
 #include <linux/agp_backend.h>
 #include "agp.h"
 
+/*
+ * If we have Intel graphics, we're not going to have anything other than
+ * an Intel IOMMU. So make the correct use of the PCI DMA API contingent
+ * on the Intel IOMMU support (CONFIG_DMAR).
+ * Only newer chipsets need to bother with this, of course.
+ */
+#ifdef CONFIG_DMAR
+#define USE_PCI_DMA_API 1
+#endif
+
 #define PCI_DEVICE_ID_INTEL_E7221_HB   0x2588
 #define PCI_DEVICE_ID_INTEL_E7221_IG   0x258a
 #define PCI_DEVICE_ID_INTEL_82946GZ_HB      0x2970
@@ -172,6 +182,123 @@ static struct _intel_private {
        int resource_valid;
 } intel_private;
 
+#ifdef USE_PCI_DMA_API
+static int intel_agp_map_page(struct page *page, dma_addr_t *ret)
+{
+       *ret = pci_map_page(intel_private.pcidev, page, 0,
+                           PAGE_SIZE, PCI_DMA_BIDIRECTIONAL);
+       if (pci_dma_mapping_error(intel_private.pcidev, *ret))
+               return -EINVAL;
+       return 0;
+}
+
+static void intel_agp_unmap_page(struct page *page, dma_addr_t dma)
+{
+       pci_unmap_page(intel_private.pcidev, dma,
+                      PAGE_SIZE, PCI_DMA_BIDIRECTIONAL);
+}
+
+static void intel_agp_free_sglist(struct agp_memory *mem)
+{
+       struct sg_table st;
+
+       st.sgl = mem->sg_list;
+       st.orig_nents = st.nents = mem->page_count;
+
+       sg_free_table(&st);
+
+       mem->sg_list = NULL;
+       mem->num_sg = 0;
+}
+
+static int intel_agp_map_memory(struct agp_memory *mem)
+{
+       struct sg_table st;
+       struct scatterlist *sg;
+       int i;
+
+       DBG("try mapping %lu pages\n", (unsigned long)mem->page_count);
+
+       if (sg_alloc_table(&st, mem->page_count, GFP_KERNEL))
+               return -ENOMEM;
+
+       mem->sg_list = sg = st.sgl;
+
+       for (i = 0 ; i < mem->page_count; i++, sg = sg_next(sg))
+               sg_set_page(sg, mem->pages[i], PAGE_SIZE, 0);
+
+       mem->num_sg = pci_map_sg(intel_private.pcidev, mem->sg_list,
+                                mem->page_count, PCI_DMA_BIDIRECTIONAL);
+       if (unlikely(!mem->num_sg)) {
+               intel_agp_free_sglist(mem);
+               return -ENOMEM;
+       }
+       return 0;
+}
+
+static void intel_agp_unmap_memory(struct agp_memory *mem)
+{
+       DBG("try unmapping %lu pages\n", (unsigned long)mem->page_count);
+
+       pci_unmap_sg(intel_private.pcidev, mem->sg_list,
+                    mem->page_count, PCI_DMA_BIDIRECTIONAL);
+       intel_agp_free_sglist(mem);
+}
+
+static void intel_agp_insert_sg_entries(struct agp_memory *mem,
+                                       off_t pg_start, int mask_type)
+{
+       struct scatterlist *sg;
+       int i, j;
+
+       j = pg_start;
+
+       WARN_ON(!mem->num_sg);
+
+       if (mem->num_sg == mem->page_count) {
+               for_each_sg(mem->sg_list, sg, mem->page_count, i) {
+                       writel(agp_bridge->driver->mask_memory(agp_bridge,
+                                       sg_dma_address(sg), mask_type),
+                                       intel_private.gtt+j);
+                       j++;
+               }
+       } else {
+               /* sg may merge pages, but we have to seperate
+                * per-page addr for GTT */
+               unsigned int len, m;
+
+               for_each_sg(mem->sg_list, sg, mem->num_sg, i) {
+                       len = sg_dma_len(sg) / PAGE_SIZE;
+                       for (m = 0; m < len; m++) {
+                               writel(agp_bridge->driver->mask_memory(agp_bridge,
+                                                                      sg_dma_address(sg) + m * PAGE_SIZE,
+                                                                      mask_type),
+                                      intel_private.gtt+j);
+                               j++;
+                       }
+               }
+       }
+       readl(intel_private.gtt+j-1);
+}
+
+#else
+
+static void intel_agp_insert_sg_entries(struct agp_memory *mem,
+                                       off_t pg_start, int mask_type)
+{
+       int i, j;
+
+       for (i = 0, j = pg_start; i < mem->page_count; i++, j++) {
+               writel(agp_bridge->driver->mask_memory(agp_bridge,
+                               page_to_phys(mem->pages[i]), mask_type),
+                      intel_private.gtt+j);
+       }
+
+       readl(intel_private.gtt+j-1);
+}
+
+#endif
+
 static int intel_i810_fetch_size(void)
 {
        u32 smram_miscc;
@@ -345,8 +472,7 @@ static int intel_i810_insert_entries(struct agp_memory *mem, off_t pg_start,
                        global_cache_flush();
                for (i = 0, j = pg_start; i < mem->page_count; i++, j++) {
                        writel(agp_bridge->driver->mask_memory(agp_bridge,
-                                                              mem->pages[i],
-                                                              mask_type),
+                                       page_to_phys(mem->pages[i]), mask_type),
                               intel_private.registers+I810_PTE_BASE+(j*4));
                }
                readl(intel_private.registers+I810_PTE_BASE+((j-1)*4));
@@ -463,9 +589,8 @@ static void intel_i810_free_by_type(struct agp_memory *curr)
 }
 
 static unsigned long intel_i810_mask_memory(struct agp_bridge_data *bridge,
-                                           struct page *page, int type)
+                                           dma_addr_t addr, int type)
 {
-       unsigned long addr = phys_to_gart(page_to_phys(page));
        /* Type checking must be done elsewhere */
        return addr | bridge->driver->masks[type].mask;
 }
@@ -853,7 +978,7 @@ static int intel_i830_insert_entries(struct agp_memory *mem, off_t pg_start,
 
        for (i = 0, j = pg_start; i < mem->page_count; i++, j++) {
                writel(agp_bridge->driver->mask_memory(agp_bridge,
-                                                      mem->pages[i], mask_type),
+                               page_to_phys(mem->pages[i]), mask_type),
                       intel_private.registers+I810_PTE_BASE+(j*4));
        }
        readl(intel_private.registers+I810_PTE_BASE+((j-1)*4));
@@ -1017,6 +1142,12 @@ static int intel_i915_configure(void)
 
        intel_i9xx_setup_flush();
 
+#ifdef USE_PCI_DMA_API 
+       if (pci_set_dma_mask(intel_private.pcidev, DMA_BIT_MASK(36)))
+               dev_err(&intel_private.pcidev->dev,
+                       "set gfx device dma mask 36bit failed!\n");
+#endif
+
        return 0;
 }
 
@@ -1041,7 +1172,7 @@ static void intel_i915_chipset_flush(struct agp_bridge_data *bridge)
 static int intel_i915_insert_entries(struct agp_memory *mem, off_t pg_start,
                                     int type)
 {
-       int i, j, num_entries;
+       int num_entries;
        void *temp;
        int ret = -EINVAL;
        int mask_type;
@@ -1065,7 +1196,7 @@ static int intel_i915_insert_entries(struct agp_memory *mem, off_t pg_start,
        if ((pg_start + mem->page_count) > num_entries)
                goto out_err;
 
-       /* The i915 can't check the GTT for entries since its read only,
+       /* The i915 can't check the GTT for entries since it's read only;
         * depend on the caller to make the correct offset decisions.
         */
 
@@ -1081,12 +1212,7 @@ static int intel_i915_insert_entries(struct agp_memory *mem, off_t pg_start,
        if (!mem->is_flushed)
                global_cache_flush();
 
-       for (i = 0, j = pg_start; i < mem->page_count; i++, j++) {
-               writel(agp_bridge->driver->mask_memory(agp_bridge,
-                                                      mem->pages[i], mask_type), intel_private.gtt+j);
-       }
-
-       readl(intel_private.gtt+j-1);
+       intel_agp_insert_sg_entries(mem, pg_start, mask_type);
        agp_bridge->driver->tlb_flush(mem);
 
  out:
@@ -1198,9 +1324,8 @@ static int intel_i915_create_gatt_table(struct agp_bridge_data *bridge)
  * this conditional.
  */
 static unsigned long intel_i965_mask_memory(struct agp_bridge_data *bridge,
-                                           struct page *page, int type)
+                                           dma_addr_t addr, int type)
 {
-       dma_addr_t addr = phys_to_gart(page_to_phys(page));
        /* Shift high bits down */
        addr |= (addr >> 28) & 0xf0;
 
@@ -2006,6 +2131,12 @@ static const struct agp_bridge_driver intel_915_driver = {
        .agp_destroy_pages      = agp_generic_destroy_pages,
        .agp_type_to_mask_type  = intel_i830_type_to_mask_type,
        .chipset_flush          = intel_i915_chipset_flush,
+#ifdef USE_PCI_DMA_API
+       .agp_map_page           = intel_agp_map_page,
+       .agp_unmap_page         = intel_agp_unmap_page,
+       .agp_map_memory         = intel_agp_map_memory,
+       .agp_unmap_memory       = intel_agp_unmap_memory,
+#endif
 };
 
 static const struct agp_bridge_driver intel_i965_driver = {
@@ -2034,6 +2165,12 @@ static const struct agp_bridge_driver intel_i965_driver = {
        .agp_destroy_pages      = agp_generic_destroy_pages,
        .agp_type_to_mask_type  = intel_i830_type_to_mask_type,
        .chipset_flush          = intel_i915_chipset_flush,
+#ifdef USE_PCI_DMA_API
+       .agp_map_page           = intel_agp_map_page,
+       .agp_unmap_page         = intel_agp_unmap_page,
+       .agp_map_memory         = intel_agp_map_memory,
+       .agp_unmap_memory       = intel_agp_unmap_memory,
+#endif
 };
 
 static const struct agp_bridge_driver intel_7505_driver = {
@@ -2088,6 +2225,12 @@ static const struct agp_bridge_driver intel_g33_driver = {
        .agp_destroy_pages      = agp_generic_destroy_pages,
        .agp_type_to_mask_type  = intel_i830_type_to_mask_type,
        .chipset_flush          = intel_i915_chipset_flush,
+#ifdef USE_PCI_DMA_API
+       .agp_map_page           = intel_agp_map_page,
+       .agp_unmap_page         = intel_agp_unmap_page,
+       .agp_map_memory         = intel_agp_map_memory,
+       .agp_unmap_memory       = intel_agp_unmap_memory,
+#endif
 };
 
 static int find_gmch(u16 device)
@@ -2313,15 +2456,6 @@ static int agp_intel_resume(struct pci_dev *pdev)
        struct agp_bridge_data *bridge = pci_get_drvdata(pdev);
        int ret_val;
 
-       pci_restore_state(pdev);
-
-       /* We should restore our graphics device's config space,
-        * as host bridge (00:00) resumes before graphics device (02:00),
-        * then our access to its pci space can work right.
-        */
-       if (intel_private.pcidev)
-               pci_restore_state(intel_private.pcidev);
-
        if (bridge->driver == &intel_generic_driver)
                intel_configure();
        else if (bridge->driver == &intel_850_driver)
index 263d71dd441c70016d622434661306fe437a2605..7e36d2b4f9d4fc863bc5392d588b152a69d8614c 100644 (file)
@@ -225,7 +225,7 @@ static int nvidia_insert_memory(struct agp_memory *mem, off_t pg_start, int type
        }
        for (i = 0, j = pg_start; i < mem->page_count; i++, j++) {
                writel(agp_bridge->driver->mask_memory(agp_bridge,
-                       mem->pages[i], mask_type),
+                              page_to_phys(mem->pages[i]), mask_type),
                        agp_bridge->gatt_table+nvidia_private.pg_offset+j);
        }
 
index e077701ae3d91ab2af0c40d3e99e3f0480610f5f..60ab75104da93b4aae627ee292cf2aff2a231686 100644 (file)
@@ -32,7 +32,7 @@
 #define AGP8X_MODE             (1 << AGP8X_MODE_BIT)
 
 static unsigned long
-parisc_agp_mask_memory(struct agp_bridge_data *bridge, unsigned long addr,
+parisc_agp_mask_memory(struct agp_bridge_data *bridge, dma_addr_t addr,
                       int type);
 
 static struct _parisc_agp_info {
@@ -189,20 +189,12 @@ parisc_agp_remove_memory(struct agp_memory *mem, off_t pg_start, int type)
 }
 
 static unsigned long
-parisc_agp_mask_memory(struct agp_bridge_data *bridge, unsigned long addr,
+parisc_agp_mask_memory(struct agp_bridge_data *bridge, dma_addr_t addr,
                       int type)
 {
        return SBA_PDIR_VALID_BIT | addr;
 }
 
-static unsigned long
-parisc_agp_page_mask_memory(struct agp_bridge_data *bridge, struct page *page,
-                           int type)
-{
-       unsigned long addr = phys_to_gart(page_to_phys(page));
-       return SBA_PDIR_VALID_BIT | addr;
-}
-
 static void
 parisc_agp_enable(struct agp_bridge_data *bridge, u32 mode)
 {
index d3ea2e4226b5fec50719df51e5e63eab14a798e6..0d426ae39c850adaa86e379a764ee315767f992f 100644 (file)
@@ -70,10 +70,9 @@ static void sgi_tioca_tlbflush(struct agp_memory *mem)
  * entry.
  */
 static unsigned long
-sgi_tioca_mask_memory(struct agp_bridge_data *bridge,
-                     struct page *page, int type)
+sgi_tioca_mask_memory(struct agp_bridge_data *bridge, dma_addr_t addr,
+                     int type)
 {
-       unsigned long addr = phys_to_gart(page_to_phys(page));
        return tioca_physpage_to_gart(addr);
 }
 
@@ -190,7 +189,8 @@ static int sgi_tioca_insert_memory(struct agp_memory *mem, off_t pg_start,
 
        for (i = 0, j = pg_start; i < mem->page_count; i++, j++) {
                table[j] =
-                   bridge->driver->mask_memory(bridge, mem->pages[i],
+                   bridge->driver->mask_memory(bridge,
+                                               page_to_phys(mem->pages[i]),
                                                mem->type);
        }
 
index b964a2199329202b887a08a8a988f58602bb7352..13acaaf64edb6f2878d145075ada2c3707c17150 100644 (file)
@@ -155,7 +155,7 @@ static int serverworks_create_gatt_table(struct agp_bridge_data *bridge)
        /* Create a fake scratch directory */
        for (i = 0; i < 1024; i++) {
                writel(agp_bridge->scratch_page, serverworks_private.scratch_dir.remapped+i);
-               writel(virt_to_gart(serverworks_private.scratch_dir.real) | 1, page_dir.remapped+i);
+               writel(virt_to_phys(serverworks_private.scratch_dir.real) | 1, page_dir.remapped+i);
        }
 
        retval = serverworks_create_gatt_pages(value->num_entries / 1024);
@@ -167,7 +167,7 @@ static int serverworks_create_gatt_table(struct agp_bridge_data *bridge)
 
        agp_bridge->gatt_table_real = (u32 *)page_dir.real;
        agp_bridge->gatt_table = (u32 __iomem *)page_dir.remapped;
-       agp_bridge->gatt_bus_addr = virt_to_gart(page_dir.real);
+       agp_bridge->gatt_bus_addr = virt_to_phys(page_dir.real);
 
        /* Get the address for the gart region.
         * This is a bus address even on the alpha, b/c its
@@ -179,7 +179,7 @@ static int serverworks_create_gatt_table(struct agp_bridge_data *bridge)
 
        /* Calculate the agp offset */
        for (i = 0; i < value->num_entries / 1024; i++)
-               writel(virt_to_gart(serverworks_private.gatt_pages[i]->real)|1, page_dir.remapped+i);
+               writel(virt_to_phys(serverworks_private.gatt_pages[i]->real)|1, page_dir.remapped+i);
 
        return 0;
 }
@@ -349,7 +349,9 @@ static int serverworks_insert_memory(struct agp_memory *mem,
        for (i = 0, j = pg_start; i < mem->page_count; i++, j++) {
                addr = (j * PAGE_SIZE) + agp_bridge->gart_bus_addr;
                cur_gatt = SVRWRKS_GET_GATT(addr);
-               writel(agp_bridge->driver->mask_memory(agp_bridge, mem->pages[i], mem->type), cur_gatt+GET_GATT_OFF(addr));
+               writel(agp_bridge->driver->mask_memory(agp_bridge, 
+                               page_to_phys(mem->pages[i]), mem->type),
+                      cur_gatt+GET_GATT_OFF(addr));
        }
        serverworks_tlbflush(mem);
        return 0;
index f192c3b9ad41d627109e9dcb497d4b77c01fb8ea..20ef1bf5e726070103e70beb9b71be5424c42dcd 100644 (file)
@@ -7,6 +7,7 @@
 #include <linux/pagemap.h>
 #include <linux/agp_backend.h>
 #include <linux/delay.h>
+#include <linux/vmalloc.h>
 #include <asm/uninorth.h>
 #include <asm/pci-bridge.h>
 #include <asm/prom.h>
@@ -27,6 +28,8 @@
 static int uninorth_rev;
 static int is_u3;
 
+#define DEFAULT_APERTURE_SIZE 256
+#define DEFAULT_APERTURE_STRING "256"
 static char *aperture = NULL;
 
 static int uninorth_fetch_size(void)
@@ -55,7 +58,7 @@ static int uninorth_fetch_size(void)
 
        if (!size) {
                for (i = 0; i < agp_bridge->driver->num_aperture_sizes; i++)
-                       if (values[i].size == 32)
+                       if (values[i].size == DEFAULT_APERTURE_SIZE)
                                break;
        }
 
@@ -135,7 +138,7 @@ static int uninorth_configure(void)
        if (is_u3) {
                pci_write_config_dword(agp_bridge->dev,
                                       UNI_N_CFG_GART_DUMMY_PAGE,
-                                      agp_bridge->scratch_page_real >> 12);
+                                      page_to_phys(agp_bridge->scratch_page_page) >> 12);
        }
 
        return 0;
@@ -179,8 +182,6 @@ static int uninorth_insert_memory(struct agp_memory *mem, off_t pg_start,
        }
        (void)in_le32((volatile u32*)&agp_bridge->gatt_table[pg_start]);
        mb();
-       flush_dcache_range((unsigned long)&agp_bridge->gatt_table[pg_start],
-               (unsigned long)&agp_bridge->gatt_table[pg_start + mem->page_count]);
 
        uninorth_tlbflush(mem);
        return 0;
@@ -224,7 +225,6 @@ static int u3_insert_memory(struct agp_memory *mem, off_t pg_start, int type)
                                   (unsigned long)__va(page_to_phys(mem->pages[i]))+0x1000);
        }
        mb();
-       flush_dcache_range((unsigned long)gp, (unsigned long) &gp[i]);
        uninorth_tlbflush(mem);
 
        return 0;
@@ -243,7 +243,6 @@ int u3_remove_memory(struct agp_memory *mem, off_t pg_start, int type)
        for (i = 0; i < mem->page_count; ++i)
                gp[i] = 0;
        mb();
-       flush_dcache_range((unsigned long)gp, (unsigned long) &gp[i]);
        uninorth_tlbflush(mem);
 
        return 0;
@@ -396,6 +395,7 @@ static int uninorth_create_gatt_table(struct agp_bridge_data *bridge)
        int i;
        void *temp;
        struct page *page;
+       struct page **pages;
 
        /* We can't handle 2 level gatt's */
        if (bridge->driver->size_type == LVL2_APER_SIZE)
@@ -424,21 +424,39 @@ static int uninorth_create_gatt_table(struct agp_bridge_data *bridge)
        if (table == NULL)
                return -ENOMEM;
 
+       pages = kmalloc((1 << page_order) * sizeof(struct page*), GFP_KERNEL);
+       if (pages == NULL)
+               goto enomem;
+
        table_end = table + ((PAGE_SIZE * (1 << page_order)) - 1);
 
-       for (page = virt_to_page(table); page <= virt_to_page(table_end); page++)
+       for (page = virt_to_page(table), i = 0; page <= virt_to_page(table_end);
+            page++, i++) {
                SetPageReserved(page);
+               pages[i] = page;
+       }
 
        bridge->gatt_table_real = (u32 *) table;
-       bridge->gatt_table = (u32 *)table;
-       bridge->gatt_bus_addr = virt_to_gart(table);
+       /* Need to clear out any dirty data still sitting in caches */
+       flush_dcache_range((unsigned long)table,
+                          (unsigned long)(table_end + PAGE_SIZE));
+       bridge->gatt_table = vmap(pages, (1 << page_order), 0, PAGE_KERNEL_NCG);
+
+       if (bridge->gatt_table == NULL)
+               goto enomem;
+
+       bridge->gatt_bus_addr = virt_to_phys(table);
 
        for (i = 0; i < num_entries; i++)
                bridge->gatt_table[i] = 0;
 
-       flush_dcache_range((unsigned long)table, (unsigned long)table_end);
-
        return 0;
+
+enomem:
+       kfree(pages);
+       if (table)
+               free_pages((unsigned long)table, page_order);
+       return -ENOMEM;
 }
 
 static int uninorth_free_gatt_table(struct agp_bridge_data *bridge)
@@ -456,6 +474,7 @@ static int uninorth_free_gatt_table(struct agp_bridge_data *bridge)
         * from the table.
         */
 
+       vunmap(bridge->gatt_table);
        table = (char *) bridge->gatt_table_real;
        table_end = table + ((PAGE_SIZE * (1 << page_order)) - 1);
 
@@ -474,13 +493,11 @@ void null_cache_flush(void)
 
 /* Setup function */
 
-static const struct aper_size_info_32 uninorth_sizes[7] =
+static const struct aper_size_info_32 uninorth_sizes[] =
 {
-#if 0 /* Not sure uninorth supports that high aperture sizes */
        {256, 65536, 6, 64},
        {128, 32768, 5, 32},
        {64, 16384, 4, 16},
-#endif
        {32, 8192, 3, 8},
        {16, 4096, 2, 4},
        {8, 2048, 1, 2},
@@ -491,7 +508,7 @@ static const struct aper_size_info_32 uninorth_sizes[7] =
  * Not sure that u3 supports that high aperture sizes but it
  * would strange if it did not :)
  */
-static const struct aper_size_info_32 u3_sizes[8] =
+static const struct aper_size_info_32 u3_sizes[] =
 {
        {512, 131072, 7, 128},
        {256, 65536, 6, 64},
@@ -507,7 +524,7 @@ const struct agp_bridge_driver uninorth_agp_driver = {
        .owner                  = THIS_MODULE,
        .aperture_sizes         = (void *)uninorth_sizes,
        .size_type              = U32_APER_SIZE,
-       .num_aperture_sizes     = 4,
+       .num_aperture_sizes     = ARRAY_SIZE(uninorth_sizes),
        .configure              = uninorth_configure,
        .fetch_size             = uninorth_fetch_size,
        .cleanup                = uninorth_cleanup,
@@ -534,7 +551,7 @@ const struct agp_bridge_driver u3_agp_driver = {
        .owner                  = THIS_MODULE,
        .aperture_sizes         = (void *)u3_sizes,
        .size_type              = U32_APER_SIZE,
-       .num_aperture_sizes     = 8,
+       .num_aperture_sizes     = ARRAY_SIZE(u3_sizes),
        .configure              = uninorth_configure,
        .fetch_size             = uninorth_fetch_size,
        .cleanup                = uninorth_cleanup,
@@ -717,7 +734,7 @@ module_param(aperture, charp, 0);
 MODULE_PARM_DESC(aperture,
                 "Aperture size, must be power of two between 4MB and an\n"
                 "\t\tupper limit specific to the UniNorth revision.\n"
-                "\t\tDefault: 32M");
+                "\t\tDefault: " DEFAULT_APERTURE_STRING "M");
 
 MODULE_AUTHOR("Ben Herrenschmidt & Paul Mackerras");
 MODULE_LICENSE("GPL");
index a00869c650d5b31a67f0c8d2675435dd6eeb1ebe..ef31738c2cbed6484748038bec890fe8a797fdd8 100644 (file)
@@ -2,7 +2,7 @@
  * Generic /dev/nvram driver for architectures providing some
  * "generic" hooks, that is :
  *
- * nvram_read_byte, nvram_write_byte, nvram_sync
+ * nvram_read_byte, nvram_write_byte, nvram_sync, nvram_get_size
  *
  * Note that an additional hook is supported for PowerMac only
  * for getting the nvram "partition" informations
@@ -28,6 +28,8 @@
 
 #define NVRAM_SIZE     8192
 
+static ssize_t nvram_len;
+
 static loff_t nvram_llseek(struct file *file, loff_t offset, int origin)
 {
        lock_kernel();
@@ -36,7 +38,7 @@ static loff_t nvram_llseek(struct file *file, loff_t offset, int origin)
                offset += file->f_pos;
                break;
        case 2:
-               offset += NVRAM_SIZE;
+               offset += nvram_len;
                break;
        }
        if (offset < 0) {
@@ -56,9 +58,9 @@ static ssize_t read_nvram(struct file *file, char __user *buf,
 
        if (!access_ok(VERIFY_WRITE, buf, count))
                return -EFAULT;
-       if (*ppos >= NVRAM_SIZE)
+       if (*ppos >= nvram_len)
                return 0;
-       for (i = *ppos; count > 0 && i < NVRAM_SIZE; ++i, ++p, --count)
+       for (i = *ppos; count > 0 && i < nvram_len; ++i, ++p, --count)
                if (__put_user(nvram_read_byte(i), p))
                        return -EFAULT;
        *ppos = i;
@@ -74,9 +76,9 @@ static ssize_t write_nvram(struct file *file, const char __user *buf,
 
        if (!access_ok(VERIFY_READ, buf, count))
                return -EFAULT;
-       if (*ppos >= NVRAM_SIZE)
+       if (*ppos >= nvram_len)
                return 0;
-       for (i = *ppos; count > 0 && i < NVRAM_SIZE; ++i, ++p, --count) {
+       for (i = *ppos; count > 0 && i < nvram_len; ++i, ++p, --count) {
                if (__get_user(c, p))
                        return -EFAULT;
                nvram_write_byte(c, i);
@@ -133,9 +135,20 @@ static struct miscdevice nvram_dev = {
 
 int __init nvram_init(void)
 {
+       int ret = 0;
+
        printk(KERN_INFO "Generic non-volatile memory driver v%s\n",
                NVRAM_VERSION);
-       return misc_register(&nvram_dev);
+       ret = misc_register(&nvram_dev);
+       if (ret != 0)
+               goto out;
+
+       nvram_len = nvram_get_size();
+       if (nvram_len < 0)
+               nvram_len = NVRAM_SIZE;
+
+out:
+       return ret;
 }
 
 void __exit nvram_cleanup(void)
index d97779ef72cb2846dabe8487ebf4cc0b4c7c6bf3..25ce15bb1c08f3cdc4aaec59c3f34384e081782f 100644 (file)
@@ -516,8 +516,6 @@ static void hvc_set_winsz(struct work_struct *work)
        struct winsize ws;
 
        hp = container_of(work, struct hvc_struct, tty_resize);
-       if (!hp)
-               return;
 
        spin_lock_irqsave(&hp->lock, hvc_flags);
        if (!hp->tty) {
index c72b994652ace78b816b4e3041e86825c01ff348..10be343d6ae75127c1aa980c1667fe518bbbb0ab 100644 (file)
@@ -120,7 +120,7 @@ static struct vio_driver hvc_vio_driver = {
        }
 };
 
-static int hvc_vio_init(void)
+static int __init hvc_vio_init(void)
 {
        int rc;
 
@@ -134,7 +134,7 @@ static int hvc_vio_init(void)
 }
 module_init(hvc_vio_init); /* after drivers/char/hvc_console.c */
 
-static void hvc_vio_exit(void)
+static void __exit hvc_vio_exit(void)
 {
        vio_unregister_driver(&hvc_vio_driver);
 }
index 2989056a9e39bb1766bd8707c9a155be84613a8e..793b236c92662999ee7aeaf1a4bf8bef253ecc44 100644 (file)
@@ -1230,11 +1230,12 @@ static struct tty_driver *hvsi_console_device(struct console *console,
 
 static int __init hvsi_console_setup(struct console *console, char *options)
 {
-       struct hvsi_struct *hp = &hvsi_ports[console->index];
+       struct hvsi_struct *hp;
        int ret;
 
        if (console->index < 0 || console->index >= hvsi_count)
                return -1;
+       hp = &hvsi_ports[console->index];
 
        /* give the FSP a chance to change the baud rate when we re-open */
        hvsi_close_protocol(hp);
index bdea7e2f94baa9c6f3743a1bdefc84ba44376822..bc33ddc9c97cddd9e29eedc1a2737dee7e5cf5f7 100644 (file)
@@ -71,7 +71,7 @@ struct cpu_dbs_info_s {
         */
        struct mutex timer_mutex;
 };
-static DEFINE_PER_CPU(struct cpu_dbs_info_s, cpu_dbs_info);
+static DEFINE_PER_CPU(struct cpu_dbs_info_s, cs_cpu_dbs_info);
 
 static unsigned int dbs_enable;        /* number of CPUs using this policy */
 
@@ -137,7 +137,7 @@ dbs_cpufreq_notifier(struct notifier_block *nb, unsigned long val,
                     void *data)
 {
        struct cpufreq_freqs *freq = data;
-       struct cpu_dbs_info_s *this_dbs_info = &per_cpu(cpu_dbs_info,
+       struct cpu_dbs_info_s *this_dbs_info = &per_cpu(cs_cpu_dbs_info,
                                                        freq->cpu);
 
        struct cpufreq_policy *policy;
@@ -297,7 +297,7 @@ static ssize_t store_ignore_nice_load(struct cpufreq_policy *policy,
        /* we need to re-evaluate prev_cpu_idle */
        for_each_online_cpu(j) {
                struct cpu_dbs_info_s *dbs_info;
-               dbs_info = &per_cpu(cpu_dbs_info, j);
+               dbs_info = &per_cpu(cs_cpu_dbs_info, j);
                dbs_info->prev_cpu_idle = get_cpu_idle_time(j,
                                                &dbs_info->prev_cpu_wall);
                if (dbs_tuners_ins.ignore_nice)
@@ -387,7 +387,7 @@ static void dbs_check_cpu(struct cpu_dbs_info_s *this_dbs_info)
                cputime64_t cur_wall_time, cur_idle_time;
                unsigned int idle_time, wall_time;
 
-               j_dbs_info = &per_cpu(cpu_dbs_info, j);
+               j_dbs_info = &per_cpu(cs_cpu_dbs_info, j);
 
                cur_idle_time = get_cpu_idle_time(j, &cur_wall_time);
 
@@ -521,7 +521,7 @@ static int cpufreq_governor_dbs(struct cpufreq_policy *policy,
        unsigned int j;
        int rc;
 
-       this_dbs_info = &per_cpu(cpu_dbs_info, cpu);
+       this_dbs_info = &per_cpu(cs_cpu_dbs_info, cpu);
 
        switch (event) {
        case CPUFREQ_GOV_START:
@@ -538,7 +538,7 @@ static int cpufreq_governor_dbs(struct cpufreq_policy *policy,
 
                for_each_cpu(j, policy->cpus) {
                        struct cpu_dbs_info_s *j_dbs_info;
-                       j_dbs_info = &per_cpu(cpu_dbs_info, j);
+                       j_dbs_info = &per_cpu(cs_cpu_dbs_info, j);
                        j_dbs_info->cur_policy = policy;
 
                        j_dbs_info->prev_cpu_idle = get_cpu_idle_time(j,
index d6ba14276bb1b0fda545cfab00367403d9b17408..d7a528c80de87f3280b344d3ea9f09ed37b3b673 100644 (file)
@@ -78,7 +78,7 @@ struct cpu_dbs_info_s {
         */
        struct mutex timer_mutex;
 };
-static DEFINE_PER_CPU(struct cpu_dbs_info_s, cpu_dbs_info);
+static DEFINE_PER_CPU(struct cpu_dbs_info_s, od_cpu_dbs_info);
 
 static unsigned int dbs_enable;        /* number of CPUs using this policy */
 
@@ -149,7 +149,8 @@ static unsigned int powersave_bias_target(struct cpufreq_policy *policy,
        unsigned int freq_hi, freq_lo;
        unsigned int index = 0;
        unsigned int jiffies_total, jiffies_hi, jiffies_lo;
-       struct cpu_dbs_info_s *dbs_info = &per_cpu(cpu_dbs_info, policy->cpu);
+       struct cpu_dbs_info_s *dbs_info = &per_cpu(od_cpu_dbs_info,
+                                                  policy->cpu);
 
        if (!dbs_info->freq_table) {
                dbs_info->freq_lo = 0;
@@ -192,7 +193,7 @@ static unsigned int powersave_bias_target(struct cpufreq_policy *policy,
 
 static void ondemand_powersave_bias_init_cpu(int cpu)
 {
-       struct cpu_dbs_info_s *dbs_info = &per_cpu(cpu_dbs_info, cpu);
+       struct cpu_dbs_info_s *dbs_info = &per_cpu(od_cpu_dbs_info, cpu);
        dbs_info->freq_table = cpufreq_frequency_get_table(cpu);
        dbs_info->freq_lo = 0;
 }
@@ -297,7 +298,7 @@ static ssize_t store_ignore_nice_load(struct cpufreq_policy *policy,
        /* we need to re-evaluate prev_cpu_idle */
        for_each_online_cpu(j) {
                struct cpu_dbs_info_s *dbs_info;
-               dbs_info = &per_cpu(cpu_dbs_info, j);
+               dbs_info = &per_cpu(od_cpu_dbs_info, j);
                dbs_info->prev_cpu_idle = get_cpu_idle_time(j,
                                                &dbs_info->prev_cpu_wall);
                if (dbs_tuners_ins.ignore_nice)
@@ -388,7 +389,7 @@ static void dbs_check_cpu(struct cpu_dbs_info_s *this_dbs_info)
                unsigned int load, load_freq;
                int freq_avg;
 
-               j_dbs_info = &per_cpu(cpu_dbs_info, j);
+               j_dbs_info = &per_cpu(od_cpu_dbs_info, j);
 
                cur_idle_time = get_cpu_idle_time(j, &cur_wall_time);
 
@@ -535,7 +536,7 @@ static int cpufreq_governor_dbs(struct cpufreq_policy *policy,
        unsigned int j;
        int rc;
 
-       this_dbs_info = &per_cpu(cpu_dbs_info, cpu);
+       this_dbs_info = &per_cpu(od_cpu_dbs_info, cpu);
 
        switch (event) {
        case CPUFREQ_GOV_START:
@@ -553,7 +554,7 @@ static int cpufreq_governor_dbs(struct cpufreq_policy *policy,
                dbs_enable++;
                for_each_cpu(j, policy->cpus) {
                        struct cpu_dbs_info_s *j_dbs_info;
-                       j_dbs_info = &per_cpu(cpu_dbs_info, j);
+                       j_dbs_info = &per_cpu(od_cpu_dbs_info, j);
                        j_dbs_info->cur_policy = policy;
 
                        j_dbs_info->prev_cpu_idle = get_cpu_idle_time(j,
index dbfeda42b940ea1064b6b4ba1301528d05b1ef8a..248219a89a68cdbf25bce00b93ec51075a47c393 100644 (file)
@@ -29,9 +29,7 @@
 
 #include <mach/board.h>
 #include <mach/gpio.h>
-#include <mach/at91sam9263.h>
 #include <mach/at91sam9_smc.h>
-#include <mach/at91sam9263_matrix.h>
 
 #define DRV_NAME "at91_ide"
 
index 6a9a769bffc1993736064c54570aeeeef0c1b989..b79ca419d8d99f5ad65197adb41462c39ed44bcc 100644 (file)
@@ -30,6 +30,7 @@
 #include <linux/kernel.h>
 #include <linux/delay.h>
 #include <linux/timer.h>
+#include <linux/seq_file.h>
 #include <linux/slab.h>
 #include <linux/interrupt.h>
 #include <linux/errno.h>
@@ -1146,8 +1147,8 @@ void ide_cdrom_update_speed(ide_drive_t *drive, u8 *buf)
        ide_debug_log(IDE_DBG_PROBE, "curspeed: %u, maxspeed: %u",
                                     curspeed, maxspeed);
 
-       cd->current_speed = (curspeed + (176/2)) / 176;
-       cd->max_speed = (maxspeed + (176/2)) / 176;
+       cd->current_speed = DIV_ROUND_CLOSEST(curspeed, 176);
+       cd->max_speed = DIV_ROUND_CLOSEST(maxspeed, 176);
 }
 
 #define IDE_CD_CAPABILITIES \
@@ -1389,19 +1390,30 @@ static sector_t ide_cdrom_capacity(ide_drive_t *drive)
        return capacity * sectors_per_frame;
 }
 
-static int proc_idecd_read_capacity(char *page, char **start, off_t off,
-                                       int count, int *eof, void *data)
+static int idecd_capacity_proc_show(struct seq_file *m, void *v)
 {
-       ide_drive_t *drive = data;
-       int len;
+       ide_drive_t *drive = m->private;
 
-       len = sprintf(page, "%llu\n", (long long)ide_cdrom_capacity(drive));
-       PROC_IDE_READ_RETURN(page, start, off, count, eof, len);
+       seq_printf(m, "%llu\n", (long long)ide_cdrom_capacity(drive));
+       return 0;
+}
+
+static int idecd_capacity_proc_open(struct inode *inode, struct file *file)
+{
+       return single_open(file, idecd_capacity_proc_show, PDE(inode)->data);
 }
 
+static const struct file_operations idecd_capacity_proc_fops = {
+       .owner          = THIS_MODULE,
+       .open           = idecd_capacity_proc_open,
+       .read           = seq_read,
+       .llseek         = seq_lseek,
+       .release        = single_release,
+};
+
 static ide_proc_entry_t idecd_proc[] = {
-       { "capacity", S_IFREG|S_IRUGO, proc_idecd_read_capacity, NULL },
-       { NULL, 0, NULL, NULL }
+       { "capacity", S_IFREG|S_IRUGO, &idecd_capacity_proc_fops },
+       {}
 };
 
 static ide_proc_entry_t *ide_cd_proc_entries(ide_drive_t *drive)
index 19f263bf0a9e22bffe02437a5b167c149792f201..60b0590ccc9cf16be3128ba62e8a4aee6df5f37c 100644 (file)
@@ -1,5 +1,6 @@
 #include <linux/kernel.h>
 #include <linux/ide.h>
+#include <linux/seq_file.h>
 
 #include "ide-disk.h"
 
@@ -37,77 +38,117 @@ static int get_smart_data(ide_drive_t *drive, u8 *buf, u8 sub_cmd)
        return ide_raw_taskfile(drive, &cmd, buf, 1);
 }
 
-static int proc_idedisk_read_cache
-       (char *page, char **start, off_t off, int count, int *eof, void *data)
+static int idedisk_cache_proc_show(struct seq_file *m, void *v)
 {
-       ide_drive_t     *drive = (ide_drive_t *) data;
-       char            *out = page;
-       int             len;
+       ide_drive_t     *drive = (ide_drive_t *) m->private;
 
        if (drive->dev_flags & IDE_DFLAG_ID_READ)
-               len = sprintf(out, "%i\n", drive->id[ATA_ID_BUF_SIZE] / 2);
+               seq_printf(m, "%i\n", drive->id[ATA_ID_BUF_SIZE] / 2);
        else
-               len = sprintf(out, "(none)\n");
+               seq_printf(m, "(none)\n");
+       return 0;
+}
 
-       PROC_IDE_READ_RETURN(page, start, off, count, eof, len);
+static int idedisk_cache_proc_open(struct inode *inode, struct file *file)
+{
+       return single_open(file, idedisk_cache_proc_show, PDE(inode)->data);
 }
 
-static int proc_idedisk_read_capacity
-       (char *page, char **start, off_t off, int count, int *eof, void *data)
+static const struct file_operations idedisk_cache_proc_fops = {
+       .owner          = THIS_MODULE,
+       .open           = idedisk_cache_proc_open,
+       .read           = seq_read,
+       .llseek         = seq_lseek,
+       .release        = single_release,
+};
+
+static int idedisk_capacity_proc_show(struct seq_file *m, void *v)
 {
-       ide_drive_t*drive = (ide_drive_t *)data;
-       int len;
+       ide_drive_t*drive = (ide_drive_t *)m->private;
 
-       len = sprintf(page, "%llu\n", (long long)ide_gd_capacity(drive));
+       seq_printf(m, "%llu\n", (long long)ide_gd_capacity(drive));
+       return 0;
+}
 
-       PROC_IDE_READ_RETURN(page, start, off, count, eof, len);
+static int idedisk_capacity_proc_open(struct inode *inode, struct file *file)
+{
+       return single_open(file, idedisk_capacity_proc_show, PDE(inode)->data);
 }
 
-static int proc_idedisk_read_smart(char *page, char **start, off_t off,
-                                  int count, int *eof, void *data, u8 sub_cmd)
+static const struct file_operations idedisk_capacity_proc_fops = {
+       .owner          = THIS_MODULE,
+       .open           = idedisk_capacity_proc_open,
+       .read           = seq_read,
+       .llseek         = seq_lseek,
+       .release        = single_release,
+};
+
+static int __idedisk_proc_show(struct seq_file *m, ide_drive_t *drive, u8 sub_cmd)
 {
-       ide_drive_t     *drive = (ide_drive_t *)data;
-       int             len = 0, i = 0;
+       u8 *buf;
+
+       buf = kmalloc(SECTOR_SIZE, GFP_KERNEL);
+       if (!buf)
+               return -ENOMEM;
 
        (void)smart_enable(drive);
 
-       if (get_smart_data(drive, page, sub_cmd) == 0) {
-               unsigned short *val = (unsigned short *) page;
-               char *out = (char *)val + SECTOR_SIZE;
-
-               page = out;
-               do {
-                       out += sprintf(out, "%04x%c", le16_to_cpu(*val),
-                                      (++i & 7) ? ' ' : '\n');
-                       val += 1;
-               } while (i < SECTOR_SIZE / 2);
-               len = out - page;
+       if (get_smart_data(drive, buf, sub_cmd) == 0) {
+               __le16 *val = (__le16 *)buf;
+               int i;
+
+               for (i = 0; i < SECTOR_SIZE / 2; i++) {
+                       seq_printf(m, "%04x%c", le16_to_cpu(val[i]),
+                                       (i % 8) == 7 ? '\n' : ' ');
+               }
        }
+       kfree(buf);
+       return 0;
+}
 
-       PROC_IDE_READ_RETURN(page, start, off, count, eof, len);
+static int idedisk_sv_proc_show(struct seq_file *m, void *v)
+{
+       return __idedisk_proc_show(m, m->private, ATA_SMART_READ_VALUES);
 }
 
-static int proc_idedisk_read_sv
-       (char *page, char **start, off_t off, int count, int *eof, void *data)
+static int idedisk_sv_proc_open(struct inode *inode, struct file *file)
 {
-       return proc_idedisk_read_smart(page, start, off, count, eof, data,
-                                      ATA_SMART_READ_VALUES);
+       return single_open(file, idedisk_sv_proc_show, PDE(inode)->data);
 }
 
-static int proc_idedisk_read_st
-       (char *page, char **start, off_t off, int count, int *eof, void *data)
+static const struct file_operations idedisk_sv_proc_fops = {
+       .owner          = THIS_MODULE,
+       .open           = idedisk_sv_proc_open,
+       .read           = seq_read,
+       .llseek         = seq_lseek,
+       .release        = single_release,
+};
+
+static int idedisk_st_proc_show(struct seq_file *m, void *v)
 {
-       return proc_idedisk_read_smart(page, start, off, count, eof, data,
-                                      ATA_SMART_READ_THRESHOLDS);
+       return __idedisk_proc_show(m, m->private, ATA_SMART_READ_THRESHOLDS);
 }
 
+static int idedisk_st_proc_open(struct inode *inode, struct file *file)
+{
+       return single_open(file, idedisk_st_proc_show, PDE(inode)->data);
+}
+
+static const struct file_operations idedisk_st_proc_fops = {
+       .owner          = THIS_MODULE,
+       .open           = idedisk_st_proc_open,
+       .read           = seq_read,
+       .llseek         = seq_lseek,
+       .release        = single_release,
+};
+
 ide_proc_entry_t ide_disk_proc[] = {
-       { "cache",        S_IFREG|S_IRUGO, proc_idedisk_read_cache,    NULL },
-       { "capacity",     S_IFREG|S_IRUGO, proc_idedisk_read_capacity, NULL },
-       { "geometry",     S_IFREG|S_IRUGO, proc_ide_read_geometry,     NULL },
-       { "smart_values", S_IFREG|S_IRUSR, proc_idedisk_read_sv,       NULL },
-       { "smart_thresholds", S_IFREG|S_IRUSR, proc_idedisk_read_st,   NULL },
-       { NULL, 0, NULL, NULL }
+       { "cache",        S_IFREG|S_IRUGO, &idedisk_cache_proc_fops     },
+       { "capacity",     S_IFREG|S_IRUGO, &idedisk_capacity_proc_fops  },
+       { "geometry",     S_IFREG|S_IRUGO, &ide_geometry_proc_fops      },
+       { "smart_values", S_IFREG|S_IRUSR, &idedisk_sv_proc_fops        },
+       { "smart_thresholds", S_IFREG|S_IRUSR, &idedisk_st_proc_fops    },
+       {}
 };
 
 ide_devset_rw_field(bios_cyl, bios_cyl);
index fcd4d8153df567f06f00a5cf5b642dc25306af87..d711d9b883dea63124ac11c38907f8ca8a23b36c 100644 (file)
@@ -1,22 +1,34 @@
 #include <linux/kernel.h>
 #include <linux/ide.h>
+#include <linux/seq_file.h>
 
 #include "ide-floppy.h"
 
-static int proc_idefloppy_read_capacity(char *page, char **start, off_t off,
-               int count, int *eof, void *data)
+static int idefloppy_capacity_proc_show(struct seq_file *m, void *v)
 {
-       ide_drive_t*drive = (ide_drive_t *)data;
-       int len;
+       ide_drive_t*drive = (ide_drive_t *)m->private;
 
-       len = sprintf(page, "%llu\n", (long long)ide_gd_capacity(drive));
-       PROC_IDE_READ_RETURN(page, start, off, count, eof, len);
+       seq_printf(m, "%llu\n", (long long)ide_gd_capacity(drive));
+       return 0;
 }
 
+static int idefloppy_capacity_proc_open(struct inode *inode, struct file *file)
+{
+       return single_open(file, idefloppy_capacity_proc_show, PDE(inode)->data);
+}
+
+static const struct file_operations idefloppy_capacity_proc_fops = {
+       .owner          = THIS_MODULE,
+       .open           = idefloppy_capacity_proc_open,
+       .read           = seq_read,
+       .llseek         = seq_lseek,
+       .release        = single_release,
+};
+
 ide_proc_entry_t ide_floppy_proc[] = {
-       { "capacity",   S_IFREG|S_IRUGO, proc_idefloppy_read_capacity,  NULL },
-       { "geometry",   S_IFREG|S_IRUGO, proc_ide_read_geometry,        NULL },
-       { NULL, 0, NULL, NULL }
+       { "capacity",   S_IFREG|S_IRUGO, &idefloppy_capacity_proc_fops  },
+       { "geometry",   S_IFREG|S_IRUGO, &ide_geometry_proc_fops        },
+       {}
 };
 
 ide_devset_rw_field(bios_cyl, bios_cyl);
index e246d3d3fbcc5c280ff520b090c297eb42c05a1e..d3440b5010a5830fc936383b4a65ffd66b4163d6 100644 (file)
@@ -167,6 +167,8 @@ static int ide_cmd_ioctl(ide_drive_t *drive, unsigned long arg)
                        err = -EINVAL;
                        goto abort;
                }
+
+               cmd.tf_flags |= IDE_TFLAG_SET_XFER;
        }
 
        err = ide_raw_taskfile(drive, &cmd, buf, args[3]);
@@ -174,12 +176,6 @@ static int ide_cmd_ioctl(ide_drive_t *drive, unsigned long arg)
        args[0] = tf->status;
        args[1] = tf->error;
        args[2] = tf->nsect;
-
-       if (!err && xfer_rate) {
-               /* active-retuning-calls future */
-               ide_set_xfer_rate(drive, xfer_rate);
-               ide_driveid_update(drive);
-       }
 abort:
        if (copy_to_user((void __user *)arg, &args, 4))
                err = -EFAULT;
index 2892b242bbe1c84feed1a343bdbb6494135f9e9a..222c1ef65fb94f0dbc84e18d64b04feb9cba1285 100644 (file)
@@ -102,8 +102,8 @@ EXPORT_SYMBOL(ide_fixstring);
  * setting a timer to wake up at half second intervals thereafter,
  * until timeout is achieved, before timing out.
  */
-static int __ide_wait_stat(ide_drive_t *drive, u8 good, u8 bad,
-                          unsigned long timeout, u8 *rstat)
+int __ide_wait_stat(ide_drive_t *drive, u8 good, u8 bad,
+                   unsigned long timeout, u8 *rstat)
 {
        ide_hwif_t *hwif = drive->hwif;
        const struct ide_tp_ops *tp_ops = hwif->tp_ops;
@@ -292,6 +292,7 @@ static const char *nien_quirk_list[] = {
        "QUANTUM FIREBALLP KX27.3",
        "QUANTUM FIREBALLP LM20.4",
        "QUANTUM FIREBALLP LM20.5",
+       "FUJITSU MHZ2160BH G2",
        NULL
 };
 
@@ -316,7 +317,7 @@ int ide_driveid_update(ide_drive_t *drive)
                return 0;
 
        SELECT_MASK(drive, 1);
-       rc = ide_dev_read_id(drive, ATA_CMD_ID_ATA, id);
+       rc = ide_dev_read_id(drive, ATA_CMD_ID_ATA, id, 1);
        SELECT_MASK(drive, 0);
 
        if (rc)
@@ -363,14 +364,6 @@ int ide_config_drive_speed(ide_drive_t *drive, u8 speed)
         * this point (lost interrupt).
         */
 
-       /*
-        *      FIXME: we race against the running IRQ here if
-        *      this is called from non IRQ context. If we use
-        *      disable_irq() we hang on the error path. Work
-        *      is needed.
-        */
-       disable_irq_nosync(hwif->irq);
-
        udelay(1);
        tp_ops->dev_select(drive);
        SELECT_MASK(drive, 1);
@@ -394,8 +387,6 @@ int ide_config_drive_speed(ide_drive_t *drive, u8 speed)
 
        SELECT_MASK(drive, 0);
 
-       enable_irq(hwif->irq);
-
        if (error) {
                (void) ide_dump_status(drive, "set_drive_speed_status", stat);
                return error;
index 1bb106f6221a5aad84aa6385158b23d53b9eaa69..8de442cbee948ca7a6fa646654c08c55650d66a4 100644 (file)
@@ -238,6 +238,7 @@ static void do_identify(ide_drive_t *drive, u8 cmd, u16 *id)
  *     @drive: drive to identify
  *     @cmd: command to use
  *     @id: buffer for IDENTIFY data
+ *     @irq_ctx: flag set when called from the IRQ context
  *
  *     Sends an ATA(PI) IDENTIFY request to a drive and waits for a response.
  *
@@ -246,7 +247,7 @@ static void do_identify(ide_drive_t *drive, u8 cmd, u16 *id)
  *                     2  device aborted the command (refused to identify itself)
  */
 
-int ide_dev_read_id(ide_drive_t *drive, u8 cmd, u16 *id)
+int ide_dev_read_id(ide_drive_t *drive, u8 cmd, u16 *id, int irq_ctx)
 {
        ide_hwif_t *hwif = drive->hwif;
        struct ide_io_ports *io_ports = &hwif->io_ports;
@@ -263,7 +264,10 @@ int ide_dev_read_id(ide_drive_t *drive, u8 cmd, u16 *id)
                tp_ops->write_devctl(hwif, ATA_NIEN | ATA_DEVCTL_OBS);
 
        /* take a deep breath */
-       msleep(50);
+       if (irq_ctx)
+               mdelay(50);
+       else
+               msleep(50);
 
        if (io_ports->ctl_addr &&
            (hwif->host_flags & IDE_HFLAG_BROKEN_ALTSTATUS) == 0) {
@@ -295,12 +299,19 @@ int ide_dev_read_id(ide_drive_t *drive, u8 cmd, u16 *id)
 
        timeout = ((cmd == ATA_CMD_ID_ATA) ? WAIT_WORSTCASE : WAIT_PIDENTIFY) / 2;
 
-       if (ide_busy_sleep(drive, timeout, use_altstatus))
-               return 1;
-
        /* wait for IRQ and ATA_DRQ */
-       msleep(50);
-       s = tp_ops->read_status(hwif);
+       if (irq_ctx) {
+               rc = __ide_wait_stat(drive, ATA_DRQ, BAD_R_STAT, timeout, &s);
+               if (rc)
+                       return 1;
+       } else {
+               rc = ide_busy_sleep(drive, timeout, use_altstatus);
+               if (rc)
+                       return 1;
+
+               msleep(50);
+               s = tp_ops->read_status(hwif);
+       }
 
        if (OK_STAT(s, ATA_DRQ, BAD_R_STAT)) {
                /* drive returned ID */
@@ -406,10 +417,10 @@ static int do_probe (ide_drive_t *drive, u8 cmd)
 
        if (OK_STAT(stat, ATA_DRDY, ATA_BUSY) ||
            present || cmd == ATA_CMD_ID_ATAPI) {
-               rc = ide_dev_read_id(drive, cmd, id);
+               rc = ide_dev_read_id(drive, cmd, id, 0);
                if (rc)
                        /* failed: try again */
-                       rc = ide_dev_read_id(drive, cmd, id);
+                       rc = ide_dev_read_id(drive, cmd, id, 0);
 
                stat = tp_ops->read_status(hwif);
 
@@ -424,7 +435,7 @@ static int do_probe (ide_drive_t *drive, u8 cmd)
                        msleep(50);
                        tp_ops->exec_command(hwif, ATA_CMD_DEV_RESET);
                        (void)ide_busy_sleep(drive, WAIT_WORSTCASE, 0);
-                       rc = ide_dev_read_id(drive, cmd, id);
+                       rc = ide_dev_read_id(drive, cmd, id, 0);
                }
 
                /* ensure drive IRQ is clear */
index 3242698832a40c07d02c2dabbd60b338eeb15d69..28d09a5d84500b588ffe862a6cfc0221bb5a3a1e 100644 (file)
 
 static struct proc_dir_entry *proc_ide_root;
 
-static int proc_ide_read_imodel
-       (char *page, char **start, off_t off, int count, int *eof, void *data)
+static int ide_imodel_proc_show(struct seq_file *m, void *v)
 {
-       ide_hwif_t      *hwif = (ide_hwif_t *) data;
-       int             len;
+       ide_hwif_t      *hwif = (ide_hwif_t *) m->private;
        const char      *name;
 
        switch (hwif->chipset) {
@@ -53,63 +51,108 @@ static int proc_ide_read_imodel
        case ide_acorn:         name = "acorn";         break;
        default:                name = "(unknown)";     break;
        }
-       len = sprintf(page, "%s\n", name);
-       PROC_IDE_READ_RETURN(page, start, off, count, eof, len);
+       seq_printf(m, "%s\n", name);
+       return 0;
 }
 
-static int proc_ide_read_mate
-       (char *page, char **start, off_t off, int count, int *eof, void *data)
+static int ide_imodel_proc_open(struct inode *inode, struct file *file)
 {
-       ide_hwif_t      *hwif = (ide_hwif_t *) data;
-       int             len;
+       return single_open(file, ide_imodel_proc_show, PDE(inode)->data);
+}
+
+static const struct file_operations ide_imodel_proc_fops = {
+       .owner          = THIS_MODULE,
+       .open           = ide_imodel_proc_open,
+       .read           = seq_read,
+       .llseek         = seq_lseek,
+       .release        = single_release,
+};
+
+static int ide_mate_proc_show(struct seq_file *m, void *v)
+{
+       ide_hwif_t      *hwif = (ide_hwif_t *) m->private;
 
        if (hwif && hwif->mate)
-               len = sprintf(page, "%s\n", hwif->mate->name);
+               seq_printf(m, "%s\n", hwif->mate->name);
        else
-               len = sprintf(page, "(none)\n");
-       PROC_IDE_READ_RETURN(page, start, off, count, eof, len);
+               seq_printf(m, "(none)\n");
+       return 0;
+}
+
+static int ide_mate_proc_open(struct inode *inode, struct file *file)
+{
+       return single_open(file, ide_mate_proc_show, PDE(inode)->data);
 }
 
-static int proc_ide_read_channel
-       (char *page, char **start, off_t off, int count, int *eof, void *data)
+static const struct file_operations ide_mate_proc_fops = {
+       .owner          = THIS_MODULE,
+       .open           = ide_mate_proc_open,
+       .read           = seq_read,
+       .llseek         = seq_lseek,
+       .release        = single_release,
+};
+
+static int ide_channel_proc_show(struct seq_file *m, void *v)
 {
-       ide_hwif_t      *hwif = (ide_hwif_t *) data;
-       int             len;
+       ide_hwif_t      *hwif = (ide_hwif_t *) m->private;
 
-       page[0] = hwif->channel ? '1' : '0';
-       page[1] = '\n';
-       len = 2;
-       PROC_IDE_READ_RETURN(page, start, off, count, eof, len);
+       seq_printf(m, "%c\n", hwif->channel ? '1' : '0');
+       return 0;
 }
 
-static int proc_ide_read_identify
-       (char *page, char **start, off_t off, int count, int *eof, void *data)
+static int ide_channel_proc_open(struct inode *inode, struct file *file)
 {
-       ide_drive_t     *drive = (ide_drive_t *)data;
-       int             len = 0, i = 0;
-       int             err = 0;
+       return single_open(file, ide_channel_proc_show, PDE(inode)->data);
+}
+
+static const struct file_operations ide_channel_proc_fops = {
+       .owner          = THIS_MODULE,
+       .open           = ide_channel_proc_open,
+       .read           = seq_read,
+       .llseek         = seq_lseek,
+       .release        = single_release,
+};
 
-       len = sprintf(page, "\n");
+static int ide_identify_proc_show(struct seq_file *m, void *v)
+{
+       ide_drive_t *drive = (ide_drive_t *)m->private;
+       u8 *buf;
 
-       if (drive) {
-               __le16 *val = (__le16 *)page;
+       if (!drive) {
+               seq_putc(m, '\n');
+               return 0;
+       }
 
-               err = taskfile_lib_get_identify(drive, page);
-               if (!err) {
-                       char *out = (char *)page + SECTOR_SIZE;
+       buf = kmalloc(SECTOR_SIZE, GFP_KERNEL);
+       if (!buf)
+               return -ENOMEM;
+       if (taskfile_lib_get_identify(drive, buf) == 0) {
+               __le16 *val = (__le16 *)buf;
+               int i;
 
-                       page = out;
-                       do {
-                               out += sprintf(out, "%04x%c",
-                                       le16_to_cpup(val), (++i & 7) ? ' ' : '\n');
-                               val += 1;
-                       } while (i < SECTOR_SIZE / 2);
-                       len = out - page;
+               for (i = 0; i < SECTOR_SIZE / 2; i++) {
+                       seq_printf(m, "%04x%c", le16_to_cpu(val[i]),
+                                       (i % 8) == 7 ? '\n' : ' ');
                }
-       }
-       PROC_IDE_READ_RETURN(page, start, off, count, eof, len);
+       } else
+               seq_putc(m, buf[0]);
+       kfree(buf);
+       return 0;
+}
+
+static int ide_identify_proc_open(struct inode *inode, struct file *file)
+{
+       return single_open(file, ide_identify_proc_show, PDE(inode)->data);
 }
 
+static const struct file_operations ide_identify_proc_fops = {
+       .owner          = THIS_MODULE,
+       .open           = ide_identify_proc_open,
+       .read           = seq_read,
+       .llseek         = seq_lseek,
+       .release        = single_release,
+};
+
 /**
  *     ide_find_setting        -       find a specific setting
  *     @st: setting table pointer
@@ -195,7 +238,6 @@ ide_devset_get(xfer_rate, current_speed);
 static int set_xfer_rate (ide_drive_t *drive, int arg)
 {
        struct ide_cmd cmd;
-       int err;
 
        if (arg < XFER_PIO_0 || arg > XFER_UDMA_6)
                return -EINVAL;
@@ -206,14 +248,9 @@ static int set_xfer_rate (ide_drive_t *drive, int arg)
        cmd.tf.nsect   = (u8)arg;
        cmd.valid.out.tf = IDE_VALID_FEATURE | IDE_VALID_NSECT;
        cmd.valid.in.tf  = IDE_VALID_NSECT;
+       cmd.tf_flags   = IDE_TFLAG_SET_XFER;
 
-       err = ide_no_data_taskfile(drive, &cmd);
-
-       if (!err) {
-               ide_set_xfer_rate(drive, (u8) arg);
-               ide_driveid_update(drive);
-       }
-       return err;
+       return ide_no_data_taskfile(drive, &cmd);
 }
 
 ide_devset_rw(current_speed, xfer_rate);
@@ -246,22 +283,20 @@ static void proc_ide_settings_warn(void)
        warned = 1;
 }
 
-static int proc_ide_read_settings
-       (char *page, char **start, off_t off, int count, int *eof, void *data)
+static int ide_settings_proc_show(struct seq_file *m, void *v)
 {
        const struct ide_proc_devset *setting, *g, *d;
        const struct ide_devset *ds;
-       ide_drive_t     *drive = (ide_drive_t *) data;
-       char            *out = page;
-       int             len, rc, mul_factor, div_factor;
+       ide_drive_t     *drive = (ide_drive_t *) m->private;
+       int             rc, mul_factor, div_factor;
 
        proc_ide_settings_warn();
 
        mutex_lock(&ide_setting_mtx);
        g = ide_generic_settings;
        d = drive->settings;
-       out += sprintf(out, "name\t\t\tvalue\t\tmin\t\tmax\t\tmode\n");
-       out += sprintf(out, "----\t\t\t-----\t\t---\t\t---\t\t----\n");
+       seq_printf(m, "name\t\t\tvalue\t\tmin\t\tmax\t\tmode\n");
+       seq_printf(m, "----\t\t\t-----\t\t---\t\t---\t\t----\n");
        while (g->name || (d && d->name)) {
                /* read settings in the alphabetical order */
                if (g->name && d && d->name) {
@@ -275,31 +310,35 @@ static int proc_ide_read_settings
                        setting = g++;
                mul_factor = setting->mulf ? setting->mulf(drive) : 1;
                div_factor = setting->divf ? setting->divf(drive) : 1;
-               out += sprintf(out, "%-24s", setting->name);
+               seq_printf(m, "%-24s", setting->name);
                rc = ide_read_setting(drive, setting);
                if (rc >= 0)
-                       out += sprintf(out, "%-16d", rc * mul_factor / div_factor);
+                       seq_printf(m, "%-16d", rc * mul_factor / div_factor);
                else
-                       out += sprintf(out, "%-16s", "write-only");
-               out += sprintf(out, "%-16d%-16d", (setting->min * mul_factor + div_factor - 1) / div_factor, setting->max * mul_factor / div_factor);
+                       seq_printf(m, "%-16s", "write-only");
+               seq_printf(m, "%-16d%-16d", (setting->min * mul_factor + div_factor - 1) / div_factor, setting->max * mul_factor / div_factor);
                ds = setting->setting;
                if (ds->get)
-                       out += sprintf(out, "r");
+                       seq_printf(m, "r");
                if (ds->set)
-                       out += sprintf(out, "w");
-               out += sprintf(out, "\n");
+                       seq_printf(m, "w");
+               seq_printf(m, "\n");
        }
-       len = out - page;
        mutex_unlock(&ide_setting_mtx);
-       PROC_IDE_READ_RETURN(page, start, off, count, eof, len);
+       return 0;
+}
+
+static int ide_settings_proc_open(struct inode *inode, struct file *file)
+{
+       return single_open(file, ide_settings_proc_show, PDE(inode)->data);
 }
 
 #define MAX_LEN        30
 
-static int proc_ide_write_settings(struct file *file, const char __user *buffer,
-                                  unsigned long count, void *data)
+static ssize_t ide_settings_proc_write(struct file *file, const char __user *buffer,
+                                      size_t count, loff_t *pos)
 {
-       ide_drive_t     *drive = (ide_drive_t *) data;
+       ide_drive_t     *drive = (ide_drive_t *) PDE(file->f_path.dentry->d_inode)->data;
        char            name[MAX_LEN + 1];
        int             for_real = 0, mul_factor, div_factor;
        unsigned long   n;
@@ -394,63 +433,104 @@ static int proc_ide_write_settings(struct file *file, const char __user *buffer,
        return count;
 parse_error:
        free_page((unsigned long)buf);
-       printk("proc_ide_write_settings(): parse error\n");
+       printk("%s(): parse error\n", __func__);
        return -EINVAL;
 }
 
-int proc_ide_read_capacity
-       (char *page, char **start, off_t off, int count, int *eof, void *data)
+static const struct file_operations ide_settings_proc_fops = {
+       .owner          = THIS_MODULE,
+       .open           = ide_settings_proc_open,
+       .read           = seq_read,
+       .llseek         = seq_lseek,
+       .release        = single_release,
+       .write          = ide_settings_proc_write,
+};
+
+static int ide_capacity_proc_show(struct seq_file *m, void *v)
+{
+       seq_printf(m, "%llu\n", (long long)0x7fffffff);
+       return 0;
+}
+
+static int ide_capacity_proc_open(struct inode *inode, struct file *file)
 {
-       int len = sprintf(page, "%llu\n", (long long)0x7fffffff);
-       PROC_IDE_READ_RETURN(page, start, off, count, eof, len);
+       return single_open(file, ide_capacity_proc_show, NULL);
 }
 
-EXPORT_SYMBOL_GPL(proc_ide_read_capacity);
+const struct file_operations ide_capacity_proc_fops = {
+       .owner          = THIS_MODULE,
+       .open           = ide_capacity_proc_open,
+       .read           = seq_read,
+       .llseek         = seq_lseek,
+       .release        = single_release,
+};
+EXPORT_SYMBOL_GPL(ide_capacity_proc_fops);
 
-int proc_ide_read_geometry
-       (char *page, char **start, off_t off, int count, int *eof, void *data)
+static int ide_geometry_proc_show(struct seq_file *m, void *v)
 {
-       ide_drive_t     *drive = (ide_drive_t *) data;
-       char            *out = page;
-       int             len;
+       ide_drive_t     *drive = (ide_drive_t *) m->private;
 
-       out += sprintf(out, "physical     %d/%d/%d\n",
+       seq_printf(m, "physical     %d/%d/%d\n",
                        drive->cyl, drive->head, drive->sect);
-       out += sprintf(out, "logical      %d/%d/%d\n",
+       seq_printf(m, "logical      %d/%d/%d\n",
                        drive->bios_cyl, drive->bios_head, drive->bios_sect);
+       return 0;
+}
 
-       len = out - page;
-       PROC_IDE_READ_RETURN(page, start, off, count, eof, len);
+static int ide_geometry_proc_open(struct inode *inode, struct file *file)
+{
+       return single_open(file, ide_geometry_proc_show, PDE(inode)->data);
 }
 
-EXPORT_SYMBOL(proc_ide_read_geometry);
+const struct file_operations ide_geometry_proc_fops = {
+       .owner          = THIS_MODULE,
+       .open           = ide_geometry_proc_open,
+       .read           = seq_read,
+       .llseek         = seq_lseek,
+       .release        = single_release,
+};
+EXPORT_SYMBOL(ide_geometry_proc_fops);
 
-static int proc_ide_read_dmodel
-       (char *page, char **start, off_t off, int count, int *eof, void *data)
+static int ide_dmodel_proc_show(struct seq_file *seq, void *v)
 {
-       ide_drive_t     *drive = (ide_drive_t *) data;
+       ide_drive_t     *drive = (ide_drive_t *) seq->private;
        char            *m = (char *)&drive->id[ATA_ID_PROD];
-       int             len;
 
-       len = sprintf(page, "%.40s\n", m[0] ? m : "(none)");
-       PROC_IDE_READ_RETURN(page, start, off, count, eof, len);
+       seq_printf(seq, "%.40s\n", m[0] ? m : "(none)");
+       return 0;
+}
+
+static int ide_dmodel_proc_open(struct inode *inode, struct file *file)
+{
+       return single_open(file, ide_dmodel_proc_show, PDE(inode)->data);
 }
 
-static int proc_ide_read_driver
-       (char *page, char **start, off_t off, int count, int *eof, void *data)
+static const struct file_operations ide_dmodel_proc_fops = {
+       .owner          = THIS_MODULE,
+       .open           = ide_dmodel_proc_open,
+       .read           = seq_read,
+       .llseek         = seq_lseek,
+       .release        = single_release,
+};
+
+static int ide_driver_proc_show(struct seq_file *m, void *v)
 {
-       ide_drive_t             *drive = (ide_drive_t *)data;
+       ide_drive_t             *drive = (ide_drive_t *)m->private;
        struct device           *dev = &drive->gendev;
        struct ide_driver       *ide_drv;
-       int                     len;
 
        if (dev->driver) {
                ide_drv = to_ide_driver(dev->driver);
-               len = sprintf(page, "%s version %s\n",
+               seq_printf(m, "%s version %s\n",
                                dev->driver->name, ide_drv->version);
        } else
-               len = sprintf(page, "ide-default version 0.9.newide\n");
-       PROC_IDE_READ_RETURN(page, start, off, count, eof, len);
+               seq_printf(m, "ide-default version 0.9.newide\n");
+       return 0;
+}
+
+static int ide_driver_proc_open(struct inode *inode, struct file *file)
+{
+       return single_open(file, ide_driver_proc_show, PDE(inode)->data);
 }
 
 static int ide_replace_subdriver(ide_drive_t *drive, const char *driver)
@@ -480,10 +560,10 @@ static int ide_replace_subdriver(ide_drive_t *drive, const char *driver)
        return ret;
 }
 
-static int proc_ide_write_driver
-       (struct file *file, const char __user *buffer, unsigned long count, void *data)
+static ssize_t ide_driver_proc_write(struct file *file, const char __user *buffer,
+                                    size_t count, loff_t *pos)
 {
-       ide_drive_t     *drive = (ide_drive_t *) data;
+       ide_drive_t     *drive = (ide_drive_t *) PDE(file->f_path.dentry->d_inode)->data;
        char name[32];
 
        if (!capable(CAP_SYS_ADMIN))
@@ -498,12 +578,19 @@ static int proc_ide_write_driver
        return count;
 }
 
-static int proc_ide_read_media
-       (char *page, char **start, off_t off, int count, int *eof, void *data)
+static const struct file_operations ide_driver_proc_fops = {
+       .owner          = THIS_MODULE,
+       .open           = ide_driver_proc_open,
+       .read           = seq_read,
+       .llseek         = seq_lseek,
+       .release        = single_release,
+       .write          = ide_driver_proc_write,
+};
+
+static int ide_media_proc_show(struct seq_file *m, void *v)
 {
-       ide_drive_t     *drive = (ide_drive_t *) data;
+       ide_drive_t     *drive = (ide_drive_t *) m->private;
        const char      *media;
-       int             len;
 
        switch (drive->media) {
        case ide_disk:          media = "disk\n";       break;
@@ -513,20 +600,30 @@ static int proc_ide_read_media
        case ide_optical:       media = "optical\n";    break;
        default:                media = "UNKNOWN\n";    break;
        }
-       strcpy(page, media);
-       len = strlen(media);
-       PROC_IDE_READ_RETURN(page, start, off, count, eof, len);
+       seq_puts(m, media);
+       return 0;
+}
+
+static int ide_media_proc_open(struct inode *inode, struct file *file)
+{
+       return single_open(file, ide_media_proc_show, PDE(inode)->data);
 }
 
+static const struct file_operations ide_media_proc_fops = {
+       .owner          = THIS_MODULE,
+       .open           = ide_media_proc_open,
+       .read           = seq_read,
+       .llseek         = seq_lseek,
+       .release        = single_release,
+};
+
 static ide_proc_entry_t generic_drive_entries[] = {
-       { "driver",     S_IFREG|S_IRUGO,         proc_ide_read_driver,
-                                                proc_ide_write_driver },
-       { "identify",   S_IFREG|S_IRUSR,         proc_ide_read_identify, NULL },
-       { "media",      S_IFREG|S_IRUGO,         proc_ide_read_media,    NULL },
-       { "model",      S_IFREG|S_IRUGO,         proc_ide_read_dmodel,   NULL },
-       { "settings",   S_IFREG|S_IRUSR|S_IWUSR, proc_ide_read_settings,
-                                                proc_ide_write_settings },
-       { NULL, 0, NULL, NULL }
+       { "driver",     S_IFREG|S_IRUGO,         &ide_driver_proc_fops  },
+       { "identify",   S_IFREG|S_IRUSR,         &ide_identify_proc_fops},
+       { "media",      S_IFREG|S_IRUGO,         &ide_media_proc_fops   },
+       { "model",      S_IFREG|S_IRUGO,         &ide_dmodel_proc_fops  },
+       { "settings",   S_IFREG|S_IRUSR|S_IWUSR, &ide_settings_proc_fops},
+       {}
 };
 
 static void ide_add_proc_entries(struct proc_dir_entry *dir, ide_proc_entry_t *p, void *data)
@@ -536,11 +633,8 @@ static void ide_add_proc_entries(struct proc_dir_entry *dir, ide_proc_entry_t *p
        if (!dir || !p)
                return;
        while (p->name != NULL) {
-               ent = create_proc_entry(p->name, p->mode, dir);
+               ent = proc_create_data(p->name, p->mode, dir, p->proc_fops, data);
                if (!ent) return;
-               ent->data = data;
-               ent->read_proc = p->read_proc;
-               ent->write_proc = p->write_proc;
                p++;
        }
 }
@@ -623,10 +717,10 @@ void ide_proc_unregister_device(ide_drive_t *drive)
 }
 
 static ide_proc_entry_t hwif_entries[] = {
-       { "channel",    S_IFREG|S_IRUGO,        proc_ide_read_channel,  NULL },
-       { "mate",       S_IFREG|S_IRUGO,        proc_ide_read_mate,     NULL },
-       { "model",      S_IFREG|S_IRUGO,        proc_ide_read_imodel,   NULL },
-       { NULL, 0, NULL, NULL }
+       { "channel",    S_IFREG|S_IRUGO,        &ide_channel_proc_fops  },
+       { "mate",       S_IFREG|S_IRUGO,        &ide_mate_proc_fops     },
+       { "model",      S_IFREG|S_IRUGO,        &ide_imodel_proc_fops   },
+       {}
 };
 
 void ide_proc_register_port(ide_hwif_t *hwif)
index bc5fb12b913c365da7610365c2167b7a7820e4de..9d6f62baac272c94953aec4aa171398cc159f291 100644 (file)
@@ -31,6 +31,7 @@
 #include <linux/major.h>
 #include <linux/errno.h>
 #include <linux/genhd.h>
+#include <linux/seq_file.h>
 #include <linux/slab.h>
 #include <linux/pci.h>
 #include <linux/ide.h>
 #include <asm/unaligned.h>
 #include <linux/mtio.h>
 
-enum {
-       /* output errors only */
-       DBG_ERR =               (1 << 0),
-       /* output all sense key/asc */
-       DBG_SENSE =             (1 << 1),
-       /* info regarding all chrdev-related procedures */
-       DBG_CHRDEV =            (1 << 2),
-       /* all remaining procedures */
-       DBG_PROCS =             (1 << 3),
-};
-
 /* define to see debug info */
-#define IDETAPE_DEBUG_LOG              0
+#undef IDETAPE_DEBUG_LOG
 
-#if IDETAPE_DEBUG_LOG
-#define debug_log(lvl, fmt, args...)                   \
-{                                                      \
-       if (tape->debug_mask & lvl)                     \
-       printk(KERN_INFO "ide-tape: " fmt, ## args);    \
-}
+#ifdef IDETAPE_DEBUG_LOG
+#define ide_debug_log(lvl, fmt, args...) __ide_debug_log(lvl, fmt, ## args)
 #else
-#define debug_log(lvl, fmt, args...) do {} while (0)
+#define ide_debug_log(lvl, fmt, args...) do {} while (0)
 #endif
 
 /**************************** Tunable parameters *****************************/
@@ -170,7 +156,8 @@ typedef struct ide_tape_obj {
         * other device. Note that at most we will have only one DSC (usually
         * data transfer) request in the device request queue.
         */
-       struct request *postponed_rq;
+       bool postponed_rq;
+
        /* The time in which we started polling for DSC */
        unsigned long dsc_polling_start;
        /* Timer used to poll for dsc */
@@ -230,8 +217,6 @@ typedef struct ide_tape_obj {
        char drv_write_prot;
        /* the tape is write protected (hardware or opened as read-only) */
        char write_prot;
-
-       u32 debug_mask;
 } idetape_tape_t;
 
 static DEFINE_MUTEX(idetape_ref_mutex);
@@ -290,8 +275,9 @@ static void idetape_analyze_error(ide_drive_t *drive)
        tape->asc       = sense[12];
        tape->ascq      = sense[13];
 
-       debug_log(DBG_ERR, "pc = %x, sense key = %x, asc = %x, ascq = %x\n",
-                pc->c[0], tape->sense_key, tape->asc, tape->ascq);
+       ide_debug_log(IDE_DBG_FUNC,
+                     "cmd: 0x%x, sense key = %x, asc = %x, ascq = %x",
+                     rq->cmd[0], tape->sense_key, tape->asc, tape->ascq);
 
        /* correct remaining bytes to transfer */
        if (pc->flags & PC_FLAG_DMA_ERROR)
@@ -344,7 +330,8 @@ static int ide_tape_callback(ide_drive_t *drive, int dsc)
        int uptodate = pc->error ? 0 : 1;
        int err = uptodate ? 0 : IDE_DRV_ERROR_GENERAL;
 
-       debug_log(DBG_PROCS, "Enter %s\n", __func__);
+       ide_debug_log(IDE_DBG_FUNC, "cmd: 0x%x, dsc: %d, err: %d", rq->cmd[0],
+                     dsc, err);
 
        if (dsc)
                ide_tape_handle_dsc(drive);
@@ -387,13 +374,14 @@ static int ide_tape_callback(ide_drive_t *drive, int dsc)
  * Postpone the current request so that ide.c will be able to service requests
  * from another device on the same port while we are polling for DSC.
  */
-static void idetape_postpone_request(ide_drive_t *drive)
+static void ide_tape_stall_queue(ide_drive_t *drive)
 {
        idetape_tape_t *tape = drive->driver_data;
 
-       debug_log(DBG_PROCS, "Enter %s\n", __func__);
+       ide_debug_log(IDE_DBG_FUNC, "cmd: 0x%x, dsc_poll_freq: %lu",
+                     drive->hwif->rq->cmd[0], tape->dsc_poll_freq);
 
-       tape->postponed_rq = drive->hwif->rq;
+       tape->postponed_rq = true;
 
        ide_stall_queue(drive, tape->dsc_poll_freq);
 }
@@ -407,7 +395,7 @@ static void ide_tape_handle_dsc(ide_drive_t *drive)
        tape->dsc_poll_freq = IDETAPE_DSC_MA_FAST;
        tape->dsc_timeout = jiffies + IDETAPE_DSC_MA_TIMEOUT;
        /* Allow ide.c to handle other requests */
-       idetape_postpone_request(drive);
+       ide_tape_stall_queue(drive);
 }
 
 /*
@@ -488,7 +476,8 @@ static ide_startstop_t ide_tape_issue_pc(ide_drive_t *drive,
                ide_complete_rq(drive, -EIO, blk_rq_bytes(rq));
                return ide_stopped;
        }
-       debug_log(DBG_SENSE, "Retry #%d, cmd = %02X\n", pc->retries, pc->c[0]);
+       ide_debug_log(IDE_DBG_SENSE, "retry #%d, cmd: 0x%02x", pc->retries,
+                     pc->c[0]);
 
        pc->retries++;
 
@@ -579,12 +568,12 @@ static ide_startstop_t idetape_do_request(ide_drive_t *drive,
        ide_hwif_t *hwif = drive->hwif;
        idetape_tape_t *tape = drive->driver_data;
        struct ide_atapi_pc *pc = NULL;
-       struct request *postponed_rq = tape->postponed_rq;
        struct ide_cmd cmd;
        u8 stat;
 
-       debug_log(DBG_SENSE, "sector: %llu, nr_sectors: %u\n"
-                 (unsigned long long)blk_rq_pos(rq), blk_rq_sectors(rq));
+       ide_debug_log(IDE_DBG_RQ, "cmd: 0x%x, sector: %llu, nr_sectors: %u",
+                     rq->cmd[0], (unsigned long long)blk_rq_pos(rq),
+                     blk_rq_sectors(rq));
 
        BUG_ON(!(blk_special_request(rq) || blk_sense_request(rq)));
 
@@ -594,18 +583,6 @@ static ide_startstop_t idetape_do_request(ide_drive_t *drive,
                goto out;
        }
 
-       if (postponed_rq != NULL)
-               if (rq != postponed_rq) {
-                       printk(KERN_ERR "ide-tape: ide-tape.c bug - "
-                                       "Two DSC requests were queued\n");
-                       drive->failed_pc = NULL;
-                       rq->errors = 0;
-                       ide_complete_rq(drive, 0, blk_rq_bytes(rq));
-                       return ide_stopped;
-               }
-
-       tape->postponed_rq = NULL;
-
        /*
         * If the tape is still busy, postpone our request and service
         * the other device meanwhile.
@@ -623,7 +600,7 @@ static ide_startstop_t idetape_do_request(ide_drive_t *drive,
 
        if (!(drive->atapi_flags & IDE_AFLAG_IGNORE_DSC) &&
            !(stat & ATA_DSC)) {
-               if (postponed_rq == NULL) {
+               if (!tape->postponed_rq) {
                        tape->dsc_polling_start = jiffies;
                        tape->dsc_poll_freq = tape->best_dsc_rw_freq;
                        tape->dsc_timeout = jiffies + IDETAPE_DSC_RW_TIMEOUT;
@@ -640,10 +617,12 @@ static ide_startstop_t idetape_do_request(ide_drive_t *drive,
                                        tape->dsc_polling_start +
                                        IDETAPE_DSC_MA_THRESHOLD))
                        tape->dsc_poll_freq = IDETAPE_DSC_MA_SLOW;
-               idetape_postpone_request(drive);
+               ide_tape_stall_queue(drive);
                return ide_stopped;
-       } else
+       } else {
                drive->atapi_flags &= ~IDE_AFLAG_IGNORE_DSC;
+               tape->postponed_rq = false;
+       }
 
        if (rq->cmd[13] & REQ_IDETAPE_READ) {
                pc = &tape->queued_pc;
@@ -745,7 +724,7 @@ static int ide_tape_read_position(ide_drive_t *drive)
        struct ide_atapi_pc pc;
        u8 buf[20];
 
-       debug_log(DBG_PROCS, "Enter %s\n", __func__);
+       ide_debug_log(IDE_DBG_FUNC, "enter");
 
        /* prep cmd */
        ide_init_pc(&pc);
@@ -756,9 +735,9 @@ static int ide_tape_read_position(ide_drive_t *drive)
                return -1;
 
        if (!pc.error) {
-               debug_log(DBG_SENSE, "BOP - %s\n",
+               ide_debug_log(IDE_DBG_FUNC, "BOP - %s",
                                (buf[0] & 0x80) ? "Yes" : "No");
-               debug_log(DBG_SENSE, "EOP - %s\n",
+               ide_debug_log(IDE_DBG_FUNC, "EOP - %s",
                                (buf[0] & 0x40) ? "Yes" : "No");
 
                if (buf[0] & 0x4) {
@@ -768,8 +747,8 @@ static int ide_tape_read_position(ide_drive_t *drive)
                                  &drive->atapi_flags);
                        return -1;
                } else {
-                       debug_log(DBG_SENSE, "Block Location - %u\n",
-                                       be32_to_cpup((__be32 *)&buf[4]));
+                       ide_debug_log(IDE_DBG_FUNC, "Block Location: %u",
+                                     be32_to_cpup((__be32 *)&buf[4]));
 
                        tape->partition = buf[1];
                        tape->first_frame = be32_to_cpup((__be32 *)&buf[4]);
@@ -866,7 +845,8 @@ static int idetape_queue_rw_tail(ide_drive_t *drive, int cmd, int size)
        struct request *rq;
        int ret;
 
-       debug_log(DBG_SENSE, "%s: cmd=%d\n", __func__, cmd);
+       ide_debug_log(IDE_DBG_FUNC, "cmd: 0x%x, size: %d", cmd, size);
+
        BUG_ON(cmd != REQ_IDETAPE_READ && cmd != REQ_IDETAPE_WRITE);
        BUG_ON(size < 0 || size % tape->blk_size);
 
@@ -1029,7 +1009,7 @@ static int idetape_rewind_tape(ide_drive_t *drive)
        struct ide_atapi_pc pc;
        int ret;
 
-       debug_log(DBG_SENSE, "Enter %s\n", __func__);
+       ide_debug_log(IDE_DBG_FUNC, "enter");
 
        idetape_create_rewind_cmd(drive, &pc);
        ret = ide_queue_pc_tail(drive, disk, &pc, NULL, 0);
@@ -1055,7 +1035,7 @@ static int idetape_blkdev_ioctl(ide_drive_t *drive, unsigned int cmd,
                int nr_stages;
        } config;
 
-       debug_log(DBG_PROCS, "Enter %s\n", __func__);
+       ide_debug_log(IDE_DBG_FUNC, "cmd: 0x%04x", cmd);
 
        switch (cmd) {
        case 0x0340:
@@ -1085,6 +1065,9 @@ static int idetape_space_over_filemarks(ide_drive_t *drive, short mt_op,
        int retval, count = 0;
        int sprev = !!(tape->caps[4] & 0x20);
 
+
+       ide_debug_log(IDE_DBG_FUNC, "mt_op: %d, mt_count: %d", mt_op, mt_count);
+
        if (mt_count == 0)
                return 0;
        if (MTBSF == mt_op || MTBSFM == mt_op) {
@@ -1148,7 +1131,7 @@ static ssize_t idetape_chrdev_read(struct file *file, char __user *buf,
        ssize_t ret = 0;
        int rc;
 
-       debug_log(DBG_CHRDEV, "Enter %s, count %Zd\n", __func__, count);
+       ide_debug_log(IDE_DBG_FUNC, "count %Zd", count);
 
        if (tape->chrdev_dir != IDETAPE_DIR_READ) {
                if (test_bit(ilog2(IDE_AFLAG_DETECT_BS), &drive->atapi_flags))
@@ -1187,8 +1170,6 @@ static ssize_t idetape_chrdev_read(struct file *file, char __user *buf,
        }
 
        if (!done && test_bit(ilog2(IDE_AFLAG_FILEMARK), &drive->atapi_flags)) {
-               debug_log(DBG_SENSE, "%s: spacing over filemark\n", tape->name);
-
                idetape_space_over_filemarks(drive, MTFSF, 1);
                return 0;
        }
@@ -1209,7 +1190,7 @@ static ssize_t idetape_chrdev_write(struct file *file, const char __user *buf,
        if (tape->write_prot)
                return -EACCES;
 
-       debug_log(DBG_CHRDEV, "Enter %s, count %Zd\n", __func__, count);
+       ide_debug_log(IDE_DBG_FUNC, "count %Zd", count);
 
        /* Initialize write operation */
        rc = idetape_init_rw(drive, IDETAPE_DIR_WRITE);
@@ -1273,8 +1254,8 @@ static int idetape_mtioctop(ide_drive_t *drive, short mt_op, int mt_count)
        struct ide_atapi_pc pc;
        int i, retval;
 
-       debug_log(DBG_ERR, "Handling MTIOCTOP ioctl: mt_op=%d, mt_count=%d\n",
-                       mt_op, mt_count);
+       ide_debug_log(IDE_DBG_FUNC, "MTIOCTOP ioctl: mt_op: %d, mt_count: %d",
+                     mt_op, mt_count);
 
        switch (mt_op) {
        case MTFSF:
@@ -1393,7 +1374,7 @@ static int idetape_chrdev_ioctl(struct inode *inode, struct file *file,
        int block_offset = 0, position = tape->first_frame;
        void __user *argp = (void __user *)arg;
 
-       debug_log(DBG_CHRDEV, "Enter %s, cmd=%u\n", __func__, cmd);
+       ide_debug_log(IDE_DBG_FUNC, "cmd: 0x%x", cmd);
 
        if (tape->chrdev_dir == IDETAPE_DIR_WRITE) {
                ide_tape_flush_merge_buffer(drive);
@@ -1461,6 +1442,9 @@ static void ide_tape_get_bsize_from_bdesc(ide_drive_t *drive)
                                (buf[4 + 6] << 8)  +
                                 buf[4 + 7];
        tape->drv_write_prot = (buf[2] & 0x80) >> 7;
+
+       ide_debug_log(IDE_DBG_FUNC, "blk_size: %d, write_prot: %d",
+                     tape->blk_size, tape->drv_write_prot);
 }
 
 static int idetape_chrdev_open(struct inode *inode, struct file *filp)
@@ -1480,7 +1464,10 @@ static int idetape_chrdev_open(struct inode *inode, struct file *filp)
                return -ENXIO;
        }
 
-       debug_log(DBG_CHRDEV, "Enter %s\n", __func__);
+       drive = tape->drive;
+       filp->private_data = tape;
+
+       ide_debug_log(IDE_DBG_FUNC, "enter");
 
        /*
         * We really want to do nonseekable_open(inode, filp); here, but some
@@ -1489,9 +1476,6 @@ static int idetape_chrdev_open(struct inode *inode, struct file *filp)
         */
        filp->f_mode &= ~(FMODE_PREAD | FMODE_PWRITE);
 
-       drive = tape->drive;
-
-       filp->private_data = tape;
 
        if (test_and_set_bit(ilog2(IDE_AFLAG_BUSY), &drive->atapi_flags)) {
                retval = -EBUSY;
@@ -1570,7 +1554,7 @@ static int idetape_chrdev_release(struct inode *inode, struct file *filp)
        lock_kernel();
        tape = drive->driver_data;
 
-       debug_log(DBG_CHRDEV, "Enter %s\n", __func__);
+       ide_debug_log(IDE_DBG_FUNC, "enter");
 
        if (tape->chrdev_dir == IDETAPE_DIR_WRITE)
                idetape_write_release(drive, minor);
@@ -1707,7 +1691,6 @@ static int divf_buffer_size(ide_drive_t *drive)   { return 1024; }
 
 ide_devset_rw_flag(dsc_overlap, IDE_DFLAG_DSC_OVERLAP);
 
-ide_tape_devset_rw_field(debug_mask, debug_mask);
 ide_tape_devset_rw_field(tdsc, best_dsc_rw_freq);
 
 ide_tape_devset_r_field(avg_speed, avg_speed);
@@ -1719,7 +1702,6 @@ static const struct ide_proc_devset idetape_settings[] = {
        __IDE_PROC_DEVSET(avg_speed,    0, 0xffff, NULL, NULL),
        __IDE_PROC_DEVSET(buffer,       0, 0xffff, NULL, divf_buffer),
        __IDE_PROC_DEVSET(buffer_size,  0, 0xffff, NULL, divf_buffer_size),
-       __IDE_PROC_DEVSET(debug_mask,   0, 0xffff, NULL, NULL),
        __IDE_PROC_DEVSET(dsc_overlap,  0,      1, NULL, NULL),
        __IDE_PROC_DEVSET(speed,        0, 0xffff, NULL, NULL),
        __IDE_PROC_DEVSET(tdsc,         IDETAPE_DSC_RW_MIN, IDETAPE_DSC_RW_MAX,
@@ -1746,7 +1728,9 @@ static void idetape_setup(ide_drive_t *drive, idetape_tape_t *tape, int minor)
        int buffer_size;
        u16 *ctl = (u16 *)&tape->caps[12];
 
-       drive->pc_callback       = ide_tape_callback;
+       ide_debug_log(IDE_DBG_FUNC, "minor: %d", minor);
+
+       drive->pc_callback = ide_tape_callback;
 
        drive->dev_flags |= IDE_DFLAG_DSC_OVERLAP;
 
@@ -1833,22 +1817,32 @@ static void ide_tape_release(struct device *dev)
 }
 
 #ifdef CONFIG_IDE_PROC_FS
-static int proc_idetape_read_name
-       (char *page, char **start, off_t off, int count, int *eof, void *data)
+static int idetape_name_proc_show(struct seq_file *m, void *v)
 {
-       ide_drive_t     *drive = (ide_drive_t *) data;
+       ide_drive_t     *drive = (ide_drive_t *) m->private;
        idetape_tape_t  *tape = drive->driver_data;
-       char            *out = page;
-       int             len;
 
-       len = sprintf(out, "%s\n", tape->name);
-       PROC_IDE_READ_RETURN(page, start, off, count, eof, len);
+       seq_printf(m, "%s\n", tape->name);
+       return 0;
+}
+
+static int idetape_name_proc_open(struct inode *inode, struct file *file)
+{
+       return single_open(file, idetape_name_proc_show, PDE(inode)->data);
 }
 
+static const struct file_operations idetape_name_proc_fops = {
+       .owner          = THIS_MODULE,
+       .open           = idetape_name_proc_open,
+       .read           = seq_read,
+       .llseek         = seq_lseek,
+       .release        = single_release,
+};
+
 static ide_proc_entry_t idetape_proc[] = {
-       { "capacity",   S_IFREG|S_IRUGO,        proc_ide_read_capacity, NULL },
-       { "name",       S_IFREG|S_IRUGO,        proc_idetape_read_name, NULL },
-       { NULL, 0, NULL, NULL }
+       { "capacity",   S_IFREG|S_IRUGO,        &ide_capacity_proc_fops },
+       { "name",       S_IFREG|S_IRUGO,        &idetape_name_proc_fops },
+       {}
 };
 
 static ide_proc_entry_t *ide_tape_proc_entries(ide_drive_t *drive)
@@ -1932,7 +1926,9 @@ static int ide_tape_probe(ide_drive_t *drive)
        struct gendisk *g;
        int minor;
 
-       if (!strstr("ide-tape", drive->driver_req))
+       ide_debug_log(IDE_DBG_FUNC, "enter");
+
+       if (!strstr(DRV_NAME, drive->driver_req))
                goto failed;
 
        if (drive->media != ide_tape)
index 75b85a8cd2d4935ba500927946fa292c890e0e8d..cc8633cbe133db4d9b7f81330ef66a547a6176ac 100644 (file)
@@ -19,8 +19,8 @@
 #include <linux/hdreg.h>
 #include <linux/ide.h>
 #include <linux/scatterlist.h>
+#include <linux/uaccess.h>
 
-#include <asm/uaccess.h>
 #include <asm/io.h>
 
 void ide_tf_readback(ide_drive_t *drive, struct ide_cmd *cmd)
@@ -53,7 +53,7 @@ void ide_tf_dump(const char *s, struct ide_cmd *cmd)
 #endif
 }
 
-int taskfile_lib_get_identify (ide_drive_t *drive, u8 *buf)
+int taskfile_lib_get_identify(ide_drive_t *drive, u8 *buf)
 {
        struct ide_cmd cmd;
 
@@ -86,7 +86,7 @@ ide_startstop_t do_rw_taskfile(ide_drive_t *drive, struct ide_cmd *orig_cmd)
        if (orig_cmd->protocol == ATA_PROT_PIO &&
            (orig_cmd->tf_flags & IDE_TFLAG_MULTI_PIO) &&
            drive->mult_count == 0) {
-               printk(KERN_ERR "%s: multimode not set!\n", drive->name);
+               pr_err("%s: multimode not set!\n", drive->name);
                return ide_stopped;
        }
 
@@ -214,7 +214,7 @@ static u8 wait_drive_not_busy(ide_drive_t *drive)
        }
 
        if (stat & ATA_BUSY)
-               printk(KERN_ERR "%s: drive still BUSY!\n", drive->name);
+               pr_err("%s: drive still BUSY!\n", drive->name);
 
        return stat;
 }
@@ -225,8 +225,8 @@ void ide_pio_bytes(ide_drive_t *drive, struct ide_cmd *cmd,
        ide_hwif_t *hwif = drive->hwif;
        struct scatterlist *sg = hwif->sg_table;
        struct scatterlist *cursg = cmd->cursg;
+       unsigned long uninitialized_var(flags);
        struct page *page;
-       unsigned long flags;
        unsigned int offset;
        u8 *buf;
 
@@ -236,6 +236,7 @@ void ide_pio_bytes(ide_drive_t *drive, struct ide_cmd *cmd,
 
        while (len) {
                unsigned nr_bytes = min(len, cursg->length - cmd->cursg_ofs);
+               int page_is_high;
 
                if (nr_bytes > PAGE_SIZE)
                        nr_bytes = PAGE_SIZE;
@@ -247,7 +248,8 @@ void ide_pio_bytes(ide_drive_t *drive, struct ide_cmd *cmd,
                page = nth_page(page, (offset >> PAGE_SHIFT));
                offset %= PAGE_SIZE;
 
-               if (PageHighMem(page))
+               page_is_high = PageHighMem(page);
+               if (page_is_high)
                        local_irq_save(flags);
 
                buf = kmap_atomic(page, KM_BIO_SRC_IRQ) + offset;
@@ -268,7 +270,7 @@ void ide_pio_bytes(ide_drive_t *drive, struct ide_cmd *cmd,
 
                kunmap_atomic(buf, KM_BIO_SRC_IRQ);
 
-               if (PageHighMem(page))
+               if (page_is_high)
                        local_irq_restore(flags);
 
                len -= nr_bytes;
@@ -322,10 +324,17 @@ static void ide_error_cmd(ide_drive_t *drive, struct ide_cmd *cmd)
 void ide_finish_cmd(ide_drive_t *drive, struct ide_cmd *cmd, u8 stat)
 {
        struct request *rq = drive->hwif->rq;
-       u8 err = ide_read_error(drive);
+       u8 err = ide_read_error(drive), nsect = cmd->tf.nsect;
+       u8 set_xfer = !!(cmd->tf_flags & IDE_TFLAG_SET_XFER);
 
        ide_complete_cmd(drive, cmd, stat, err);
        rq->errors = err;
+
+       if (err == 0 && set_xfer) {
+               ide_set_xfer_rate(drive, nsect);
+               ide_driveid_update(drive);
+       }
+
        ide_complete_rq(drive, err ? -EIO : 0, blk_rq_bytes(rq));
 }
 
@@ -398,8 +407,7 @@ static ide_startstop_t pre_task_out_intr(ide_drive_t *drive,
 
        if (ide_wait_stat(&startstop, drive, ATA_DRQ,
                          drive->bad_wstat, WAIT_DRQ)) {
-               printk(KERN_ERR "%s: no DRQ after issuing %sWRITE%s\n",
-                       drive->name,
+               pr_err("%s: no DRQ after issuing %sWRITE%s\n", drive->name,
                        (cmd->tf_flags & IDE_TFLAG_MULTI_PIO) ? "MULT" : "",
                        (drive->dev_flags & IDE_DFLAG_LBA48) ? "_EXT" : "");
                return startstop;
@@ -449,7 +457,6 @@ put_req:
        blk_put_request(rq);
        return error;
 }
-
 EXPORT_SYMBOL(ide_raw_taskfile);
 
 int ide_no_data_taskfile(ide_drive_t *drive, struct ide_cmd *cmd)
@@ -475,10 +482,9 @@ int ide_taskfile_ioctl(ide_drive_t *drive, unsigned long arg)
        u16 nsect               = 0;
        char __user *buf = (char __user *)arg;
 
-//     printk("IDE Taskfile ...\n");
-
        req_task = kzalloc(tasksize, GFP_KERNEL);
-       if (req_task == NULL) return -ENOMEM;
+       if (req_task == NULL)
+               return -ENOMEM;
        if (copy_from_user(req_task, buf, tasksize)) {
                kfree(req_task);
                return -EFAULT;
@@ -486,7 +492,7 @@ int ide_taskfile_ioctl(ide_drive_t *drive, unsigned long arg)
 
        taskout = req_task->out_size;
        taskin  = req_task->in_size;
-       
+
        if (taskin > 65536 || taskout > 65536) {
                err = -EINVAL;
                goto abort;
@@ -576,51 +582,49 @@ int ide_taskfile_ioctl(ide_drive_t *drive, unsigned long arg)
        cmd.protocol = ATA_PROT_DMA;
 
        switch (req_task->data_phase) {
-               case TASKFILE_MULTI_OUT:
-                       if (!drive->mult_count) {
-                               /* (hs): give up if multcount is not set */
-                               printk(KERN_ERR "%s: %s Multimode Write " \
-                                       "multcount is not set\n",
-                                       drive->name, __func__);
-                               err = -EPERM;
-                               goto abort;
-                       }
-                       cmd.tf_flags |= IDE_TFLAG_MULTI_PIO;
-                       /* fall through */
-               case TASKFILE_OUT:
-                       cmd.protocol = ATA_PROT_PIO;
-                       /* fall through */
-               case TASKFILE_OUT_DMAQ:
-               case TASKFILE_OUT_DMA:
-                       cmd.tf_flags |= IDE_TFLAG_WRITE;
-                       nsect = taskout / SECTOR_SIZE;
-                       data_buf = outbuf;
-                       break;
-               case TASKFILE_MULTI_IN:
-                       if (!drive->mult_count) {
-                               /* (hs): give up if multcount is not set */
-                               printk(KERN_ERR "%s: %s Multimode Read failure " \
-                                       "multcount is not set\n",
-                                       drive->name, __func__);
-                               err = -EPERM;
-                               goto abort;
-                       }
-                       cmd.tf_flags |= IDE_TFLAG_MULTI_PIO;
-                       /* fall through */
-               case TASKFILE_IN:
-                       cmd.protocol = ATA_PROT_PIO;
-                       /* fall through */
-               case TASKFILE_IN_DMAQ:
-               case TASKFILE_IN_DMA:
-                       nsect = taskin / SECTOR_SIZE;
-                       data_buf = inbuf;
-                       break;
-               case TASKFILE_NO_DATA:
-                       cmd.protocol = ATA_PROT_NODATA;
-                       break;
-               default:
-                       err = -EFAULT;
+       case TASKFILE_MULTI_OUT:
+               if (!drive->mult_count) {
+                       /* (hs): give up if multcount is not set */
+                       pr_err("%s: %s Multimode Write multcount is not set\n",
+                               drive->name, __func__);
+                       err = -EPERM;
+                       goto abort;
+               }
+               cmd.tf_flags |= IDE_TFLAG_MULTI_PIO;
+               /* fall through */
+       case TASKFILE_OUT:
+               cmd.protocol = ATA_PROT_PIO;
+               /* fall through */
+       case TASKFILE_OUT_DMAQ:
+       case TASKFILE_OUT_DMA:
+               cmd.tf_flags |= IDE_TFLAG_WRITE;
+               nsect = taskout / SECTOR_SIZE;
+               data_buf = outbuf;
+               break;
+       case TASKFILE_MULTI_IN:
+               if (!drive->mult_count) {
+                       /* (hs): give up if multcount is not set */
+                       pr_err("%s: %s Multimode Read multcount is not set\n",
+                               drive->name, __func__);
+                       err = -EPERM;
                        goto abort;
+               }
+               cmd.tf_flags |= IDE_TFLAG_MULTI_PIO;
+               /* fall through */
+       case TASKFILE_IN:
+               cmd.protocol = ATA_PROT_PIO;
+               /* fall through */
+       case TASKFILE_IN_DMAQ:
+       case TASKFILE_IN_DMA:
+               nsect = taskin / SECTOR_SIZE;
+               data_buf = inbuf;
+               break;
+       case TASKFILE_NO_DATA:
+               cmd.protocol = ATA_PROT_NODATA;
+               break;
+       default:
+               err = -EFAULT;
+               goto abort;
        }
 
        if (req_task->req_cmd == IDE_DRIVE_TASK_NO_DATA)
@@ -629,7 +633,7 @@ int ide_taskfile_ioctl(ide_drive_t *drive, unsigned long arg)
                nsect = (cmd.hob.nsect << 8) | cmd.tf.nsect;
 
                if (!nsect) {
-                       printk(KERN_ERR "%s: in/out command without data\n",
+                       pr_err("%s: in/out command without data\n",
                                        drive->name);
                        err = -EFAULT;
                        goto abort;
@@ -671,8 +675,6 @@ abort:
        kfree(outbuf);
        kfree(inbuf);
 
-//     printk("IDE Taskfile ioctl ended. rc = %i\n", err);
-
        return err;
 }
 #endif
index 3c1dc015215351ed1cf43e00c8fb85b859ff22d0..f8eddf05ecb8533ebca9e9134c56c097a65170bd 100644 (file)
@@ -318,7 +318,7 @@ static int __init palm_bk3710_probe(struct platform_device *pdev)
        int i, rc;
        struct ide_hw hw, *hws[] = { &hw };
 
-       clk = clk_get(&pdev->dev, "IDECLK");
+       clk = clk_get(&pdev->dev, NULL);
        if (IS_ERR(clk))
                return -ENODEV;
 
index 76f9668221a423926e7e19dfb5a0a6e823b487d2..79cd3e9fdf2e2f60d6266fdf4d5df85c5057325c 100644 (file)
@@ -8,7 +8,7 @@
  *
  * Based on a previous implementations by Kevin O'Connor
  * <kevin_at_koconnor.net> and Alex Osborne <bobofdoom@gmail.com> and
- * on some suggestions by Nicolas Pitre <nico@cam.org>.
+ * on some suggestions by Nicolas Pitre <nico@fluxnic.net>.
  *
  * 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
index a0f68386c12f3b5aa026f8cae8b470f23be41faa..588a5b0bc4b59150101b3f214c385a8348693134 100644 (file)
@@ -294,10 +294,11 @@ static void macio_setup_interrupts(struct macio_dev *dev)
        int i = 0, j = 0;
 
        for (;;) {
-               struct resource *res = &dev->interrupt[j];
+               struct resource *res;
 
                if (j >= MACIO_DEV_COUNT_IRQS)
                        break;
+               res = &dev->interrupt[j];
                irq = irq_of_parse_and_map(np, i++);
                if (irq == NO_IRQ)
                        break;
@@ -321,9 +322,10 @@ static void macio_setup_resources(struct macio_dev *dev,
        int index;
 
        for (index = 0; of_address_to_resource(np, index, &r) == 0; index++) {
-               struct resource *res = &dev->resource[index];
+               struct resource *res;
                if (index >= MACIO_DEV_COUNT_RESOURCES)
                        break;
+               res = &dev->resource[index];
                *res = r;
                res->name = dev_name(&dev->ofdev.dev);
 
index 40023313a760ac9005b74e04c17b3f7def7daa6e..8b9364434aa0bbd21995c9b299c021075fabfb30 100644 (file)
@@ -239,8 +239,8 @@ setup_hardware( void )
         * to be on the safe side (OSX doesn't)...
         */
        if( x.overheat_temp == (80 << 8) ) {
-               x.overheat_temp = 65 << 8;
-               x.overheat_hyst = 60 << 8;
+               x.overheat_temp = 75 << 8;
+               x.overheat_hyst = 70 << 8;
                write_reg( x.thermostat, 2, x.overheat_hyst, 2 );
                write_reg( x.thermostat, 3, x.overheat_temp, 2 );
 
index 16792a68a44951e1bc1c2cbb1c9da27a2b6b2722..655474b29e21ca23347cf15d7dc707a644a0011e 100644 (file)
@@ -58,13 +58,24 @@ static void ir_input_key_event(struct input_dev *dev, struct ir_input_state *ir)
 /* -------------------------------------------------------------------------- */
 
 void ir_input_init(struct input_dev *dev, struct ir_input_state *ir,
-                  int ir_type, IR_KEYTAB_TYPE *ir_codes)
+                  int ir_type, struct ir_scancode_table *ir_codes)
 {
        int i;
 
        ir->ir_type = ir_type;
+
+       memset(ir->ir_codes, sizeof(ir->ir_codes), 0);
+
+       /*
+        * FIXME: This is a temporary workaround to use the new IR tables
+        * with the old approach. Later patches will replace this to a
+        * proper method
+        */
+
        if (ir_codes)
-               memcpy(ir->ir_codes, ir_codes, sizeof(ir->ir_codes));
+               for (i = 0; i < ir_codes->size; i++)
+                       if (ir_codes->scan[i].scancode < IR_KEYTAB_SIZE)
+                               ir->ir_codes[ir_codes->scan[i].scancode] = ir_codes->scan[i].keycode;
 
        dev->keycode     = ir->ir_codes;
        dev->keycodesize = sizeof(IR_KEYTAB_TYPE);
index 4216328552f6edad952ca870bf57beabef5b1227..f6790172736a07482eb8ccc4a08a9e32032ae2d3 100644 (file)
@@ -1,8 +1,6 @@
 /*
-
-
-    Keytables for supported remote controls. This file is part of
-    video4linux.
+    Keytables for supported remote controls, used on drivers/media
+    devices.
 
     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
     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.
+*/
 
+/*
+ * NOTICE FOR DEVELOPERS:
+ *   The IR mappings should be as close as possible to what's
+ *   specified at:
+ *      http://linuxtv.org/wiki/index.php/Remote_Controllers
  */
 #include <linux/module.h>
 
 #include <media/ir-common.h>
 
 /* empty keytable, can be used as placeholder for not-yet created keytables */
-IR_KEYTAB_TYPE ir_codes_empty[IR_KEYTAB_SIZE] = {
-       [ 0x2a ] = KEY_COFFEE,
+static struct ir_scancode ir_codes_empty[] = {
+       { 0x2a, KEY_COFFEE },
 };
 
-EXPORT_SYMBOL_GPL(ir_codes_empty);
+struct ir_scancode_table ir_codes_empty_table = {
+       .scan = ir_codes_empty,
+       .size = ARRAY_SIZE(ir_codes_empty),
+};
+EXPORT_SYMBOL_GPL(ir_codes_empty_table);
 
 /* Michal Majchrowicz <mmajchrowicz@gmail.com> */
-IR_KEYTAB_TYPE ir_codes_proteus_2309[IR_KEYTAB_SIZE] = {
+static struct ir_scancode ir_codes_proteus_2309[] = {
        /* numeric */
-       [ 0x00 ] = KEY_0,
-       [ 0x01 ] = KEY_1,
-       [ 0x02 ] = KEY_2,
-       [ 0x03 ] = KEY_3,
-       [ 0x04 ] = KEY_4,
-       [ 0x05 ] = KEY_5,
-       [ 0x06 ] = KEY_6,
-       [ 0x07 ] = KEY_7,
-       [ 0x08 ] = KEY_8,
-       [ 0x09 ] = KEY_9,
-
-       [ 0x5c ] = KEY_POWER,     /* power       */
-       [ 0x20 ] = KEY_F,         /* full screen */
-       [ 0x0f ] = KEY_BACKSPACE, /* recall      */
-       [ 0x1b ] = KEY_ENTER,     /* mute        */
-       [ 0x41 ] = KEY_RECORD,    /* record      */
-       [ 0x43 ] = KEY_STOP,      /* stop        */
-       [ 0x16 ] = KEY_S,
-       [ 0x1a ] = KEY_Q,         /* off         */
-       [ 0x2e ] = KEY_RED,
-       [ 0x1f ] = KEY_DOWN,      /* channel -   */
-       [ 0x1c ] = KEY_UP,        /* channel +   */
-       [ 0x10 ] = KEY_LEFT,      /* volume -    */
-       [ 0x1e ] = KEY_RIGHT,     /* volume +    */
-       [ 0x14 ] = KEY_F1,
-};
-
-EXPORT_SYMBOL_GPL(ir_codes_proteus_2309);
+       { 0x00, KEY_0 },
+       { 0x01, KEY_1 },
+       { 0x02, KEY_2 },
+       { 0x03, KEY_3 },
+       { 0x04, KEY_4 },
+       { 0x05, KEY_5 },
+       { 0x06, KEY_6 },
+       { 0x07, KEY_7 },
+       { 0x08, KEY_8 },
+       { 0x09, KEY_9 },
+
+       { 0x5c, KEY_POWER },            /* power       */
+       { 0x20, KEY_ZOOM },             /* full screen */
+       { 0x0f, KEY_BACKSPACE },        /* recall      */
+       { 0x1b, KEY_ENTER },            /* mute        */
+       { 0x41, KEY_RECORD },           /* record      */
+       { 0x43, KEY_STOP },             /* stop        */
+       { 0x16, KEY_S },
+       { 0x1a, KEY_POWER2 },           /* off         */
+       { 0x2e, KEY_RED },
+       { 0x1f, KEY_CHANNELDOWN },      /* channel -   */
+       { 0x1c, KEY_CHANNELUP },        /* channel +   */
+       { 0x10, KEY_VOLUMEDOWN },       /* volume -    */
+       { 0x1e, KEY_VOLUMEUP },         /* volume +    */
+       { 0x14, KEY_F1 },
+};
+
+struct ir_scancode_table ir_codes_proteus_2309_table = {
+       .scan = ir_codes_proteus_2309,
+       .size = ARRAY_SIZE(ir_codes_proteus_2309),
+};
+EXPORT_SYMBOL_GPL(ir_codes_proteus_2309_table);
+
 /* Matt Jesson <dvb@jesson.eclipse.co.uk */
-IR_KEYTAB_TYPE ir_codes_avermedia_dvbt[IR_KEYTAB_SIZE] = {
-       [ 0x28 ] = KEY_0,         //'0' / 'enter'
-       [ 0x22 ] = KEY_1,         //'1'
-       [ 0x12 ] = KEY_2,         //'2' / 'up arrow'
-       [ 0x32 ] = KEY_3,         //'3'
-       [ 0x24 ] = KEY_4,         //'4' / 'left arrow'
-       [ 0x14 ] = KEY_5,         //'5'
-       [ 0x34 ] = KEY_6,         //'6' / 'right arrow'
-       [ 0x26 ] = KEY_7,         //'7'
-       [ 0x16 ] = KEY_8,         //'8' / 'down arrow'
-       [ 0x36 ] = KEY_9,         //'9'
-
-       [ 0x20 ] = KEY_LIST,        // 'source'
-       [ 0x10 ] = KEY_TEXT,        // 'teletext'
-       [ 0x00 ] = KEY_POWER,       // 'power'
-       [ 0x04 ] = KEY_AUDIO,       // 'audio'
-       [ 0x06 ] = KEY_ZOOM,        // 'full screen'
-       [ 0x18 ] = KEY_VIDEO,       // 'display'
-       [ 0x38 ] = KEY_SEARCH,      // 'loop'
-       [ 0x08 ] = KEY_INFO,        // 'preview'
-       [ 0x2a ] = KEY_REWIND,      // 'backward <<'
-       [ 0x1a ] = KEY_FASTFORWARD, // 'forward >>'
-       [ 0x3a ] = KEY_RECORD,      // 'capture'
-       [ 0x0a ] = KEY_MUTE,        // 'mute'
-       [ 0x2c ] = KEY_RECORD,      // 'record'
-       [ 0x1c ] = KEY_PAUSE,       // 'pause'
-       [ 0x3c ] = KEY_STOP,        // 'stop'
-       [ 0x0c ] = KEY_PLAY,        // 'play'
-       [ 0x2e ] = KEY_RED,         // 'red'
-       [ 0x01 ] = KEY_BLUE,        // 'blue' / 'cancel'
-       [ 0x0e ] = KEY_YELLOW,      // 'yellow' / 'ok'
-       [ 0x21 ] = KEY_GREEN,       // 'green'
-       [ 0x11 ] = KEY_CHANNELDOWN, // 'channel -'
-       [ 0x31 ] = KEY_CHANNELUP,   // 'channel +'
-       [ 0x1e ] = KEY_VOLUMEDOWN,  // 'volume -'
-       [ 0x3e ] = KEY_VOLUMEUP,    // 'volume +'
-};
-
-EXPORT_SYMBOL_GPL(ir_codes_avermedia_dvbt);
+static struct ir_scancode ir_codes_avermedia_dvbt[] = {
+       { 0x28, KEY_0 },                /* '0' / 'enter' */
+       { 0x22, KEY_1 },                /* '1' */
+       { 0x12, KEY_2 },                /* '2' / 'up arrow' */
+       { 0x32, KEY_3 },                /* '3' */
+       { 0x24, KEY_4 },                /* '4' / 'left arrow' */
+       { 0x14, KEY_5 },                /* '5' */
+       { 0x34, KEY_6 },                /* '6' / 'right arrow' */
+       { 0x26, KEY_7 },                /* '7' */
+       { 0x16, KEY_8 },                /* '8' / 'down arrow' */
+       { 0x36, KEY_9 },                /* '9' */
+
+       { 0x20, KEY_LIST },             /* 'source' */
+       { 0x10, KEY_TEXT },             /* 'teletext' */
+       { 0x00, KEY_POWER },            /* 'power' */
+       { 0x04, KEY_AUDIO },            /* 'audio' */
+       { 0x06, KEY_ZOOM },             /* 'full screen' */
+       { 0x18, KEY_VIDEO },            /* 'display' */
+       { 0x38, KEY_SEARCH },           /* 'loop' */
+       { 0x08, KEY_INFO },             /* 'preview' */
+       { 0x2a, KEY_REWIND },           /* 'backward <<' */
+       { 0x1a, KEY_FASTFORWARD },      /* 'forward >>' */
+       { 0x3a, KEY_RECORD },           /* 'capture' */
+       { 0x0a, KEY_MUTE },             /* 'mute' */
+       { 0x2c, KEY_RECORD },           /* 'record' */
+       { 0x1c, KEY_PAUSE },            /* 'pause' */
+       { 0x3c, KEY_STOP },             /* 'stop' */
+       { 0x0c, KEY_PLAY },             /* 'play' */
+       { 0x2e, KEY_RED },              /* 'red' */
+       { 0x01, KEY_BLUE },             /* 'blue' / 'cancel' */
+       { 0x0e, KEY_YELLOW },           /* 'yellow' / 'ok' */
+       { 0x21, KEY_GREEN },            /* 'green' */
+       { 0x11, KEY_CHANNELDOWN },      /* 'channel -' */
+       { 0x31, KEY_CHANNELUP },        /* 'channel +' */
+       { 0x1e, KEY_VOLUMEDOWN },       /* 'volume -' */
+       { 0x3e, KEY_VOLUMEUP },         /* 'volume +' */
+};
+
+struct ir_scancode_table ir_codes_avermedia_dvbt_table = {
+       .scan = ir_codes_avermedia_dvbt,
+       .size = ARRAY_SIZE(ir_codes_avermedia_dvbt),
+};
+EXPORT_SYMBOL_GPL(ir_codes_avermedia_dvbt_table);
 
 /* Mauro Carvalho Chehab <mchehab@infradead.org> */
-IR_KEYTAB_TYPE ir_codes_avermedia_m135a[IR_KEYTAB_SIZE] = {
-       [0x00] = KEY_POWER2,
-       [0x2e] = KEY_DOT,               /* '.' */
-       [0x01] = KEY_MODE,              /* TV/FM */
-
-       [0x05] = KEY_1,
-       [0x06] = KEY_2,
-       [0x07] = KEY_3,
-       [0x09] = KEY_4,
-       [0x0a] = KEY_5,
-       [0x0b] = KEY_6,
-       [0x0d] = KEY_7,
-       [0x0e] = KEY_8,
-       [0x0f] = KEY_9,
-       [0x11] = KEY_0,
-
-       [0x13] = KEY_RIGHT,             /* -> */
-       [0x12] = KEY_LEFT,              /* <- */
-
-       [0x17] = KEY_SLEEP,             /* Capturar Imagem */
-       [0x10] = KEY_SHUFFLE,           /* Amostra */
+static struct ir_scancode ir_codes_avermedia_m135a[] = {
+       { 0x00, KEY_POWER2 },
+       { 0x2e, KEY_DOT },              /* '.' */
+       { 0x01, KEY_MODE },             /* TV/FM */
+
+       { 0x05, KEY_1 },
+       { 0x06, KEY_2 },
+       { 0x07, KEY_3 },
+       { 0x09, KEY_4 },
+       { 0x0a, KEY_5 },
+       { 0x0b, KEY_6 },
+       { 0x0d, KEY_7 },
+       { 0x0e, KEY_8 },
+       { 0x0f, KEY_9 },
+       { 0x11, KEY_0 },
+
+       { 0x13, KEY_RIGHT },            /* -> */
+       { 0x12, KEY_LEFT },             /* <- */
+
+       { 0x17, KEY_SLEEP },            /* Capturar Imagem */
+       { 0x10, KEY_SHUFFLE },          /* Amostra */
 
        /* FIXME: The keys bellow aren't ok */
 
-       [0x43] = KEY_CHANNELUP,
-       [0x42] = KEY_CHANNELDOWN,
-       [0x1f] = KEY_VOLUMEUP,
-       [0x1e] = KEY_VOLUMEDOWN,
-       [0x0c] = KEY_ENTER,
+       { 0x43, KEY_CHANNELUP },
+       { 0x42, KEY_CHANNELDOWN },
+       { 0x1f, KEY_VOLUMEUP },
+       { 0x1e, KEY_VOLUMEDOWN },
+       { 0x0c, KEY_ENTER },
 
-       [0x14] = KEY_MUTE,
-       [0x08] = KEY_AUDIO,
+       { 0x14, KEY_MUTE },
+       { 0x08, KEY_AUDIO },
 
-       [0x03] = KEY_TEXT,
-       [0x04] = KEY_EPG,
-       [0x2b] = KEY_TV2,               /* TV2 */
+       { 0x03, KEY_TEXT },
+       { 0x04, KEY_EPG },
+       { 0x2b, KEY_TV2 },              /* TV2 */
 
-       [0x1d] = KEY_RED,
-       [0x1c] = KEY_YELLOW,
-       [0x41] = KEY_GREEN,
-       [0x40] = KEY_BLUE,
+       { 0x1d, KEY_RED },
+       { 0x1c, KEY_YELLOW },
+       { 0x41, KEY_GREEN },
+       { 0x40, KEY_BLUE },
 
-       [0x1a] = KEY_PLAYPAUSE,
-       [0x19] = KEY_RECORD,
-       [0x18] = KEY_PLAY,
-       [0x1b] = KEY_STOP,
+       { 0x1a, KEY_PLAYPAUSE },
+       { 0x19, KEY_RECORD },
+       { 0x18, KEY_PLAY },
+       { 0x1b, KEY_STOP },
 };
-EXPORT_SYMBOL_GPL(ir_codes_avermedia_m135a);
+
+struct ir_scancode_table ir_codes_avermedia_m135a_table = {
+       .scan = ir_codes_avermedia_m135a,
+       .size = ARRAY_SIZE(ir_codes_avermedia_m135a),
+};
+EXPORT_SYMBOL_GPL(ir_codes_avermedia_m135a_table);
 
 /* Oldrich Jedlicka <oldium.pro@seznam.cz> */
-IR_KEYTAB_TYPE ir_codes_avermedia_cardbus[IR_KEYTAB_SIZE] = {
-       [0x00] = KEY_POWER,
-       [0x01] = KEY_TUNER,             /* TV/FM */
-       [0x03] = KEY_TEXT,              /* Teletext */
-       [0x04] = KEY_EPG,
-       [0x05] = KEY_1,
-       [0x06] = KEY_2,
-       [0x07] = KEY_3,
-       [0x08] = KEY_AUDIO,
-       [0x09] = KEY_4,
-       [0x0a] = KEY_5,
-       [0x0b] = KEY_6,
-       [0x0c] = KEY_ZOOM,              /* Full screen */
-       [0x0d] = KEY_7,
-       [0x0e] = KEY_8,
-       [0x0f] = KEY_9,
-       [0x10] = KEY_PAGEUP,            /* 16-CH PREV */
-       [0x11] = KEY_0,
-       [0x12] = KEY_INFO,
-       [0x13] = KEY_AGAIN,             /* CH RTN - channel return */
-       [0x14] = KEY_MUTE,
-       [0x15] = KEY_EDIT,              /* Autoscan */
-       [0x17] = KEY_SAVE,              /* Screenshot */
-       [0x18] = KEY_PLAYPAUSE,
-       [0x19] = KEY_RECORD,
-       [0x1a] = KEY_PLAY,
-       [0x1b] = KEY_STOP,
-       [0x1c] = KEY_FASTFORWARD,
-       [0x1d] = KEY_REWIND,
-       [0x1e] = KEY_VOLUMEDOWN,
-       [0x1f] = KEY_VOLUMEUP,
-       [0x22] = KEY_SLEEP,             /* Sleep */
-       [0x23] = KEY_ZOOM,              /* Aspect */
-       [0x26] = KEY_SCREEN,            /* Pos */
-       [0x27] = KEY_ANGLE,             /* Size */
-       [0x28] = KEY_SELECT,            /* Select */
-       [0x29] = KEY_BLUE,              /* Blue/Picture */
-       [0x2a] = KEY_BACKSPACE, /* Back */
-       [0x2b] = KEY_MEDIA,             /* PIP (Picture-in-picture) */
-       [0x2c] = KEY_DOWN,
-       [0x2e] = KEY_DOT,
-       [0x2f] = KEY_TV,                /* Live TV */
-       [0x32] = KEY_LEFT,
-       [0x33] = KEY_CLEAR,             /* Clear */
-       [0x35] = KEY_RED,               /* Red/TV */
-       [0x36] = KEY_UP,
-       [0x37] = KEY_HOME,              /* Home */
-       [0x39] = KEY_GREEN,             /* Green/Video */
-       [0x3d] = KEY_YELLOW,            /* Yellow/Music */
-       [0x3e] = KEY_OK,                /* Ok */
-       [0x3f] = KEY_RIGHT,
-       [0x40] = KEY_NEXT,              /* Next */
-       [0x41] = KEY_PREVIOUS,  /* Previous */
-       [0x42] = KEY_CHANNELDOWN,       /* Channel down */
-       [0x43] = KEY_CHANNELUP  /* Channel up */
-};
-EXPORT_SYMBOL_GPL(ir_codes_avermedia_cardbus);
+static struct ir_scancode ir_codes_avermedia_cardbus[] = {
+       { 0x00, KEY_POWER },
+       { 0x01, KEY_TUNER },            /* TV/FM */
+       { 0x03, KEY_TEXT },             /* Teletext */
+       { 0x04, KEY_EPG },
+       { 0x05, KEY_1 },
+       { 0x06, KEY_2 },
+       { 0x07, KEY_3 },
+       { 0x08, KEY_AUDIO },
+       { 0x09, KEY_4 },
+       { 0x0a, KEY_5 },
+       { 0x0b, KEY_6 },
+       { 0x0c, KEY_ZOOM },             /* Full screen */
+       { 0x0d, KEY_7 },
+       { 0x0e, KEY_8 },
+       { 0x0f, KEY_9 },
+       { 0x10, KEY_PAGEUP },           /* 16-CH PREV */
+       { 0x11, KEY_0 },
+       { 0x12, KEY_INFO },
+       { 0x13, KEY_AGAIN },            /* CH RTN - channel return */
+       { 0x14, KEY_MUTE },
+       { 0x15, KEY_EDIT },             /* Autoscan */
+       { 0x17, KEY_SAVE },             /* Screenshot */
+       { 0x18, KEY_PLAYPAUSE },
+       { 0x19, KEY_RECORD },
+       { 0x1a, KEY_PLAY },
+       { 0x1b, KEY_STOP },
+       { 0x1c, KEY_FASTFORWARD },
+       { 0x1d, KEY_REWIND },
+       { 0x1e, KEY_VOLUMEDOWN },
+       { 0x1f, KEY_VOLUMEUP },
+       { 0x22, KEY_SLEEP },            /* Sleep */
+       { 0x23, KEY_ZOOM },             /* Aspect */
+       { 0x26, KEY_SCREEN },           /* Pos */
+       { 0x27, KEY_ANGLE },            /* Size */
+       { 0x28, KEY_SELECT },           /* Select */
+       { 0x29, KEY_BLUE },             /* Blue/Picture */
+       { 0x2a, KEY_BACKSPACE },        /* Back */
+       { 0x2b, KEY_MEDIA },            /* PIP (Picture-in-picture) */
+       { 0x2c, KEY_DOWN },
+       { 0x2e, KEY_DOT },
+       { 0x2f, KEY_TV },               /* Live TV */
+       { 0x32, KEY_LEFT },
+       { 0x33, KEY_CLEAR },            /* Clear */
+       { 0x35, KEY_RED },              /* Red/TV */
+       { 0x36, KEY_UP },
+       { 0x37, KEY_HOME },             /* Home */
+       { 0x39, KEY_GREEN },            /* Green/Video */
+       { 0x3d, KEY_YELLOW },           /* Yellow/Music */
+       { 0x3e, KEY_OK },               /* Ok */
+       { 0x3f, KEY_RIGHT },
+       { 0x40, KEY_NEXT },             /* Next */
+       { 0x41, KEY_PREVIOUS },         /* Previous */
+       { 0x42, KEY_CHANNELDOWN },      /* Channel down */
+       { 0x43, KEY_CHANNELUP },        /* Channel up */
+};
+
+struct ir_scancode_table ir_codes_avermedia_cardbus_table = {
+       .scan = ir_codes_avermedia_cardbus,
+       .size = ARRAY_SIZE(ir_codes_avermedia_cardbus),
+};
+EXPORT_SYMBOL_GPL(ir_codes_avermedia_cardbus_table);
 
 /* Attila Kondoros <attila.kondoros@chello.hu> */
-IR_KEYTAB_TYPE ir_codes_apac_viewcomp[IR_KEYTAB_SIZE] = {
-
-       [ 0x01 ] = KEY_1,
-       [ 0x02 ] = KEY_2,
-       [ 0x03 ] = KEY_3,
-       [ 0x04 ] = KEY_4,
-       [ 0x05 ] = KEY_5,
-       [ 0x06 ] = KEY_6,
-       [ 0x07 ] = KEY_7,
-       [ 0x08 ] = KEY_8,
-       [ 0x09 ] = KEY_9,
-       [ 0x00 ] = KEY_0,
-       [ 0x17 ] = KEY_LAST,        // +100
-       [ 0x0a ] = KEY_LIST,        // recall
-
-
-       [ 0x1c ] = KEY_TUNER,       // TV/FM
-       [ 0x15 ] = KEY_SEARCH,      // scan
-       [ 0x12 ] = KEY_POWER,       // power
-       [ 0x1f ] = KEY_VOLUMEDOWN,  // vol up
-       [ 0x1b ] = KEY_VOLUMEUP,    // vol down
-       [ 0x1e ] = KEY_CHANNELDOWN, // chn up
-       [ 0x1a ] = KEY_CHANNELUP,   // chn down
-
-       [ 0x11 ] = KEY_VIDEO,       // video
-       [ 0x0f ] = KEY_ZOOM,        // full screen
-       [ 0x13 ] = KEY_MUTE,        // mute/unmute
-       [ 0x10 ] = KEY_TEXT,        // min
-
-       [ 0x0d ] = KEY_STOP,        // freeze
-       [ 0x0e ] = KEY_RECORD,      // record
-       [ 0x1d ] = KEY_PLAYPAUSE,   // stop
-       [ 0x19 ] = KEY_PLAY,        // play
-
-       [ 0x16 ] = KEY_GOTO,        // osd
-       [ 0x14 ] = KEY_REFRESH,     // default
-       [ 0x0c ] = KEY_KPPLUS,      // fine tune >>>>
-       [ 0x18 ] = KEY_KPMINUS      // fine tune <<<<
-};
-
-EXPORT_SYMBOL_GPL(ir_codes_apac_viewcomp);
+static struct ir_scancode ir_codes_apac_viewcomp[] = {
+
+       { 0x01, KEY_1 },
+       { 0x02, KEY_2 },
+       { 0x03, KEY_3 },
+       { 0x04, KEY_4 },
+       { 0x05, KEY_5 },
+       { 0x06, KEY_6 },
+       { 0x07, KEY_7 },
+       { 0x08, KEY_8 },
+       { 0x09, KEY_9 },
+       { 0x00, KEY_0 },
+       { 0x17, KEY_LAST },             /* +100 */
+       { 0x0a, KEY_LIST },             /* recall */
+
+
+       { 0x1c, KEY_TUNER },            /* TV/FM */
+       { 0x15, KEY_SEARCH },           /* scan */
+       { 0x12, KEY_POWER },            /* power */
+       { 0x1f, KEY_VOLUMEDOWN },       /* vol up */
+       { 0x1b, KEY_VOLUMEUP },         /* vol down */
+       { 0x1e, KEY_CHANNELDOWN },      /* chn up */
+       { 0x1a, KEY_CHANNELUP },        /* chn down */
+
+       { 0x11, KEY_VIDEO },            /* video */
+       { 0x0f, KEY_ZOOM },             /* full screen */
+       { 0x13, KEY_MUTE },             /* mute/unmute */
+       { 0x10, KEY_TEXT },             /* min */
+
+       { 0x0d, KEY_STOP },             /* freeze */
+       { 0x0e, KEY_RECORD },           /* record */
+       { 0x1d, KEY_PLAYPAUSE },        /* stop */
+       { 0x19, KEY_PLAY },             /* play */
+
+       { 0x16, KEY_GOTO },             /* osd */
+       { 0x14, KEY_REFRESH },          /* default */
+       { 0x0c, KEY_KPPLUS },           /* fine tune >>>> */
+       { 0x18, KEY_KPMINUS },          /* fine tune <<<< */
+};
+
+struct ir_scancode_table ir_codes_apac_viewcomp_table = {
+       .scan = ir_codes_apac_viewcomp,
+       .size = ARRAY_SIZE(ir_codes_apac_viewcomp),
+};
+EXPORT_SYMBOL_GPL(ir_codes_apac_viewcomp_table);
 
 /* ---------------------------------------------------------------------- */
 
-IR_KEYTAB_TYPE ir_codes_pixelview[IR_KEYTAB_SIZE] = {
+static struct ir_scancode ir_codes_pixelview[] = {
 
-       [ 0x1e ] = KEY_POWER,       // power
-       [ 0x07 ] = KEY_MEDIA,       // source
-       [ 0x1c ] = KEY_SEARCH,      // scan
+       { 0x1e, KEY_POWER },    /* power */
+       { 0x07, KEY_MEDIA },    /* source */
+       { 0x1c, 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.
- *
- *     [ 0x17 ] = KEY_BACK,        // fm scan <<
- *     [ 0x1f ] = KEY_FORWARD,     // fm scan >>
- *
- *     [ 0x04 ] = KEY_LEFT,        // fm tuning <
- *     [ 0x0c ] = KEY_RIGHT,       // fm tuning >
- *
- * For now, these four keys are disabled. Pressing them will generate
- * the CH+/CH-/<<</>>> events
- */
 
-       [ 0x03 ] = KEY_TUNER,       // TV/FM
+       { 0x03, KEY_TUNER },            /* TV/FM */
 
-       [ 0x00 ] = KEY_RECORD,
-       [ 0x08 ] = KEY_STOP,
-       [ 0x11 ] = KEY_PLAY,
+       { 0x00, KEY_RECORD },
+       { 0x08, KEY_STOP },
+       { 0x11, KEY_PLAY },
 
-       [ 0x1a ] = KEY_PLAYPAUSE,   // freeze
-       [ 0x19 ] = KEY_ZOOM,        // zoom
-       [ 0x0f ] = KEY_TEXT,        // min
+       { 0x1a, KEY_PLAYPAUSE },        /* freeze */
+       { 0x19, KEY_ZOOM },             /* zoom */
+       { 0x0f, KEY_TEXT },             /* min */
 
-       [ 0x01 ] = KEY_1,
-       [ 0x0b ] = KEY_2,
-       [ 0x1b ] = KEY_3,
-       [ 0x05 ] = KEY_4,
-       [ 0x09 ] = KEY_5,
-       [ 0x15 ] = KEY_6,
-       [ 0x06 ] = KEY_7,
-       [ 0x0a ] = KEY_8,
-       [ 0x12 ] = KEY_9,
-       [ 0x02 ] = KEY_0,
-       [ 0x10 ] = KEY_LAST,        // +100
-       [ 0x13 ] = KEY_LIST,        // recall
+       { 0x01, KEY_1 },
+       { 0x0b, KEY_2 },
+       { 0x1b, KEY_3 },
+       { 0x05, KEY_4 },
+       { 0x09, KEY_5 },
+       { 0x15, KEY_6 },
+       { 0x06, KEY_7 },
+       { 0x0a, KEY_8 },
+       { 0x12, KEY_9 },
+       { 0x02, KEY_0 },
+       { 0x10, KEY_LAST },             /* +100 */
+       { 0x13, KEY_LIST },             /* recall */
 
-       [ 0x1f ] = KEY_CHANNELUP,   // chn down
-       [ 0x17 ] = KEY_CHANNELDOWN, // chn up
-       [ 0x16 ] = KEY_VOLUMEUP,    // vol down
-       [ 0x14 ] = KEY_VOLUMEDOWN,  // vol up
+       { 0x1f, KEY_CHANNELUP },        /* chn down */
+       { 0x17, KEY_CHANNELDOWN },      /* chn up */
+       { 0x16, KEY_VOLUMEUP },         /* vol down */
+       { 0x14, KEY_VOLUMEDOWN },       /* vol up */
 
-       [ 0x04 ] = KEY_KPMINUS,     // <<<
-       [ 0x0e ] = KEY_SETUP,       // function
-       [ 0x0c ] = KEY_KPPLUS,      // >>>
+       { 0x04, KEY_KPMINUS },          /* <<< */
+       { 0x0e, KEY_SETUP },            /* function */
+       { 0x0c, KEY_KPPLUS },           /* >>> */
 
-       [ 0x0d ] = KEY_GOTO,        // mts
-       [ 0x1d ] = KEY_REFRESH,     // reset
-       [ 0x18 ] = KEY_MUTE         // mute/unmute
+       { 0x0d, KEY_GOTO },             /* mts */
+       { 0x1d, KEY_REFRESH },          /* reset */
+       { 0x18, KEY_MUTE },             /* mute/unmute */
 };
 
-EXPORT_SYMBOL_GPL(ir_codes_pixelview);
+struct ir_scancode_table ir_codes_pixelview_table = {
+       .scan = ir_codes_pixelview,
+       .size = ARRAY_SIZE(ir_codes_pixelview),
+};
+EXPORT_SYMBOL_GPL(ir_codes_pixelview_table);
 
 /*
    Mauro Carvalho Chehab <mchehab@infradead.org>
    present on PV MPEG 8000GT
  */
-IR_KEYTAB_TYPE ir_codes_pixelview_new[IR_KEYTAB_SIZE] = {
-       [0x3c] = KEY_PAUSE,             /* Timeshift */
-       [0x12] = KEY_POWER,
-
-       [0x3d] = KEY_1,
-       [0x38] = KEY_2,
-       [0x18] = KEY_3,
-       [0x35] = KEY_4,
-       [0x39] = KEY_5,
-       [0x15] = KEY_6,
-       [0x36] = KEY_7,
-       [0x3a] = KEY_8,
-       [0x1e] = KEY_9,
-       [0x3e] = KEY_0,
-
-       [0x1c] = KEY_AGAIN,             /* LOOP */
-       [0x3f] = KEY_MEDIA,             /* Source */
-       [0x1f] = KEY_LAST,              /* +100 */
-       [0x1b] = KEY_MUTE,
-
-       [0x17] = KEY_CHANNELDOWN,
-       [0x16] = KEY_CHANNELUP,
-       [0x10] = KEY_VOLUMEUP,
-       [0x14] = KEY_VOLUMEDOWN,
-       [0x13] = KEY_ZOOM,
-
-       [0x19] = KEY_SHUFFLE,           /* SNAPSHOT */
-       [0x1a] = KEY_SEARCH,            /* scan */
-
-       [0x37] = KEY_REWIND,            /* << */
-       [0x32] = KEY_RECORD,            /* o (red) */
-       [0x33] = KEY_FORWARD,           /* >> */
-       [0x11] = KEY_STOP,              /* square */
-       [0x3b] = KEY_PLAY,              /* > */
-       [0x30] = KEY_PLAYPAUSE,         /* || */
-
-       [0x31] = KEY_TV,
-       [0x34] = KEY_RADIO,
-};
-EXPORT_SYMBOL_GPL(ir_codes_pixelview_new);
-
-IR_KEYTAB_TYPE ir_codes_nebula[IR_KEYTAB_SIZE] = {
-       [ 0x00 ] = KEY_0,
-       [ 0x01 ] = KEY_1,
-       [ 0x02 ] = KEY_2,
-       [ 0x03 ] = KEY_3,
-       [ 0x04 ] = KEY_4,
-       [ 0x05 ] = KEY_5,
-       [ 0x06 ] = KEY_6,
-       [ 0x07 ] = KEY_7,
-       [ 0x08 ] = KEY_8,
-       [ 0x09 ] = KEY_9,
-       [ 0x0a ] = KEY_TV,
-       [ 0x0b ] = KEY_AUX,
-       [ 0x0c ] = KEY_DVD,
-       [ 0x0d ] = KEY_POWER,
-       [ 0x0e ] = KEY_MHP,     /* labelled 'Picture' */
-       [ 0x0f ] = KEY_AUDIO,
-       [ 0x10 ] = KEY_INFO,
-       [ 0x11 ] = KEY_F13,     /* 16:9 */
-       [ 0x12 ] = KEY_F14,     /* 14:9 */
-       [ 0x13 ] = KEY_EPG,
-       [ 0x14 ] = KEY_EXIT,
-       [ 0x15 ] = KEY_MENU,
-       [ 0x16 ] = KEY_UP,
-       [ 0x17 ] = KEY_DOWN,
-       [ 0x18 ] = KEY_LEFT,
-       [ 0x19 ] = KEY_RIGHT,
-       [ 0x1a ] = KEY_ENTER,
-       [ 0x1b ] = KEY_CHANNELUP,
-       [ 0x1c ] = KEY_CHANNELDOWN,
-       [ 0x1d ] = KEY_VOLUMEUP,
-       [ 0x1e ] = KEY_VOLUMEDOWN,
-       [ 0x1f ] = KEY_RED,
-       [ 0x20 ] = KEY_GREEN,
-       [ 0x21 ] = KEY_YELLOW,
-       [ 0x22 ] = KEY_BLUE,
-       [ 0x23 ] = KEY_SUBTITLE,
-       [ 0x24 ] = KEY_F15,     /* AD */
-       [ 0x25 ] = KEY_TEXT,
-       [ 0x26 ] = KEY_MUTE,
-       [ 0x27 ] = KEY_REWIND,
-       [ 0x28 ] = KEY_STOP,
-       [ 0x29 ] = KEY_PLAY,
-       [ 0x2a ] = KEY_FASTFORWARD,
-       [ 0x2b ] = KEY_F16,     /* chapter */
-       [ 0x2c ] = KEY_PAUSE,
-       [ 0x2d ] = KEY_PLAY,
-       [ 0x2e ] = KEY_RECORD,
-       [ 0x2f ] = KEY_F17,     /* picture in picture */
-       [ 0x30 ] = KEY_KPPLUS,  /* zoom in */
-       [ 0x31 ] = KEY_KPMINUS, /* zoom out */
-       [ 0x32 ] = KEY_F18,     /* capture */
-       [ 0x33 ] = KEY_F19,     /* web */
-       [ 0x34 ] = KEY_EMAIL,
-       [ 0x35 ] = KEY_PHONE,
-       [ 0x36 ] = KEY_PC
-};
-
-EXPORT_SYMBOL_GPL(ir_codes_nebula);
+static struct ir_scancode ir_codes_pixelview_new[] = {
+       { 0x3c, KEY_TIME },             /* Timeshift */
+       { 0x12, KEY_POWER },
+
+       { 0x3d, KEY_1 },
+       { 0x38, KEY_2 },
+       { 0x18, KEY_3 },
+       { 0x35, KEY_4 },
+       { 0x39, KEY_5 },
+       { 0x15, KEY_6 },
+       { 0x36, KEY_7 },
+       { 0x3a, KEY_8 },
+       { 0x1e, KEY_9 },
+       { 0x3e, KEY_0 },
+
+       { 0x1c, KEY_AGAIN },            /* LOOP */
+       { 0x3f, KEY_MEDIA },            /* Source */
+       { 0x1f, KEY_LAST },             /* +100 */
+       { 0x1b, KEY_MUTE },
+
+       { 0x17, KEY_CHANNELDOWN },
+       { 0x16, KEY_CHANNELUP },
+       { 0x10, KEY_VOLUMEUP },
+       { 0x14, KEY_VOLUMEDOWN },
+       { 0x13, KEY_ZOOM },
+
+       { 0x19, KEY_CAMERA },           /* SNAPSHOT */
+       { 0x1a, KEY_SEARCH },           /* scan */
+
+       { 0x37, KEY_REWIND },           /* << */
+       { 0x32, KEY_RECORD },           /* o (red) */
+       { 0x33, KEY_FORWARD },          /* >> */
+       { 0x11, KEY_STOP },             /* square */
+       { 0x3b, KEY_PLAY },             /* > */
+       { 0x30, KEY_PLAYPAUSE },        /* || */
+
+       { 0x31, KEY_TV },
+       { 0x34, KEY_RADIO },
+};
+
+struct ir_scancode_table ir_codes_pixelview_new_table = {
+       .scan = ir_codes_pixelview_new,
+       .size = ARRAY_SIZE(ir_codes_pixelview_new),
+};
+EXPORT_SYMBOL_GPL(ir_codes_pixelview_new_table);
+
+static struct ir_scancode ir_codes_nebula[] = {
+       { 0x00, KEY_0 },
+       { 0x01, KEY_1 },
+       { 0x02, KEY_2 },
+       { 0x03, KEY_3 },
+       { 0x04, KEY_4 },
+       { 0x05, KEY_5 },
+       { 0x06, KEY_6 },
+       { 0x07, KEY_7 },
+       { 0x08, KEY_8 },
+       { 0x09, KEY_9 },
+       { 0x0a, KEY_TV },
+       { 0x0b, KEY_AUX },
+       { 0x0c, KEY_DVD },
+       { 0x0d, KEY_POWER },
+       { 0x0e, KEY_MHP },      /* labelled 'Picture' */
+       { 0x0f, KEY_AUDIO },
+       { 0x10, KEY_INFO },
+       { 0x11, KEY_F13 },      /* 16:9 */
+       { 0x12, KEY_F14 },      /* 14:9 */
+       { 0x13, KEY_EPG },
+       { 0x14, KEY_EXIT },
+       { 0x15, KEY_MENU },
+       { 0x16, KEY_UP },
+       { 0x17, KEY_DOWN },
+       { 0x18, KEY_LEFT },
+       { 0x19, KEY_RIGHT },
+       { 0x1a, KEY_ENTER },
+       { 0x1b, KEY_CHANNELUP },
+       { 0x1c, KEY_CHANNELDOWN },
+       { 0x1d, KEY_VOLUMEUP },
+       { 0x1e, KEY_VOLUMEDOWN },
+       { 0x1f, KEY_RED },
+       { 0x20, KEY_GREEN },
+       { 0x21, KEY_YELLOW },
+       { 0x22, KEY_BLUE },
+       { 0x23, KEY_SUBTITLE },
+       { 0x24, KEY_F15 },      /* AD */
+       { 0x25, KEY_TEXT },
+       { 0x26, KEY_MUTE },
+       { 0x27, KEY_REWIND },
+       { 0x28, KEY_STOP },
+       { 0x29, KEY_PLAY },
+       { 0x2a, KEY_FASTFORWARD },
+       { 0x2b, KEY_F16 },      /* chapter */
+       { 0x2c, KEY_PAUSE },
+       { 0x2d, KEY_PLAY },
+       { 0x2e, KEY_RECORD },
+       { 0x2f, KEY_F17 },      /* picture in picture */
+       { 0x30, KEY_KPPLUS },   /* zoom in */
+       { 0x31, KEY_KPMINUS },  /* zoom out */
+       { 0x32, KEY_F18 },      /* capture */
+       { 0x33, KEY_F19 },      /* web */
+       { 0x34, KEY_EMAIL },
+       { 0x35, KEY_PHONE },
+       { 0x36, KEY_PC },
+};
+
+struct ir_scancode_table ir_codes_nebula_table = {
+       .scan = ir_codes_nebula,
+       .size = ARRAY_SIZE(ir_codes_nebula),
+};
+EXPORT_SYMBOL_GPL(ir_codes_nebula_table);
 
 /* DigitalNow DNTV Live DVB-T Remote */
-IR_KEYTAB_TYPE ir_codes_dntv_live_dvb_t[IR_KEYTAB_SIZE] = {
-       [ 0x00 ] = KEY_ESC,             /* 'go up a level?' */
+static struct ir_scancode ir_codes_dntv_live_dvb_t[] = {
+       { 0x00, KEY_ESC },              /* 'go up a level?' */
        /* Keys 0 to 9 */
-       [ 0x0a ] = KEY_0,
-       [ 0x01 ] = KEY_1,
-       [ 0x02 ] = KEY_2,
-       [ 0x03 ] = KEY_3,
-       [ 0x04 ] = KEY_4,
-       [ 0x05 ] = KEY_5,
-       [ 0x06 ] = KEY_6,
-       [ 0x07 ] = KEY_7,
-       [ 0x08 ] = KEY_8,
-       [ 0x09 ] = KEY_9,
-
-       [ 0x0b ] = KEY_TUNER,           /* tv/fm */
-       [ 0x0c ] = KEY_SEARCH,          /* scan */
-       [ 0x0d ] = KEY_STOP,
-       [ 0x0e ] = KEY_PAUSE,
-       [ 0x0f ] = KEY_LIST,            /* source */
-
-       [ 0x10 ] = KEY_MUTE,
-       [ 0x11 ] = KEY_REWIND,          /* backward << */
-       [ 0x12 ] = KEY_POWER,
-       [ 0x13 ] = KEY_S,                       /* snap */
-       [ 0x14 ] = KEY_AUDIO,           /* stereo */
-       [ 0x15 ] = KEY_CLEAR,           /* reset */
-       [ 0x16 ] = KEY_PLAY,
-       [ 0x17 ] = KEY_ENTER,
-       [ 0x18 ] = KEY_ZOOM,            /* full screen */
-       [ 0x19 ] = KEY_FASTFORWARD,     /* forward >> */
-       [ 0x1a ] = KEY_CHANNELUP,
-       [ 0x1b ] = KEY_VOLUMEUP,
-       [ 0x1c ] = KEY_INFO,            /* preview */
-       [ 0x1d ] = KEY_RECORD,          /* record */
-       [ 0x1e ] = KEY_CHANNELDOWN,
-       [ 0x1f ] = KEY_VOLUMEDOWN,
-};
-
-EXPORT_SYMBOL_GPL(ir_codes_dntv_live_dvb_t);
+       { 0x0a, KEY_0 },
+       { 0x01, KEY_1 },
+       { 0x02, KEY_2 },
+       { 0x03, KEY_3 },
+       { 0x04, KEY_4 },
+       { 0x05, KEY_5 },
+       { 0x06, KEY_6 },
+       { 0x07, KEY_7 },
+       { 0x08, KEY_8 },
+       { 0x09, KEY_9 },
+
+       { 0x0b, KEY_TUNER },            /* tv/fm */
+       { 0x0c, KEY_SEARCH },           /* scan */
+       { 0x0d, KEY_STOP },
+       { 0x0e, KEY_PAUSE },
+       { 0x0f, KEY_LIST },             /* source */
+
+       { 0x10, KEY_MUTE },
+       { 0x11, KEY_REWIND },           /* backward << */
+       { 0x12, KEY_POWER },
+       { 0x13, KEY_CAMERA },           /* snap */
+       { 0x14, KEY_AUDIO },            /* stereo */
+       { 0x15, KEY_CLEAR },            /* reset */
+       { 0x16, KEY_PLAY },
+       { 0x17, KEY_ENTER },
+       { 0x18, KEY_ZOOM },             /* full screen */
+       { 0x19, KEY_FASTFORWARD },      /* forward >> */
+       { 0x1a, KEY_CHANNELUP },
+       { 0x1b, KEY_VOLUMEUP },
+       { 0x1c, KEY_INFO },             /* preview */
+       { 0x1d, KEY_RECORD },           /* record */
+       { 0x1e, KEY_CHANNELDOWN },
+       { 0x1f, KEY_VOLUMEDOWN },
+};
+
+struct ir_scancode_table ir_codes_dntv_live_dvb_t_table = {
+       .scan = ir_codes_dntv_live_dvb_t,
+       .size = ARRAY_SIZE(ir_codes_dntv_live_dvb_t),
+};
+EXPORT_SYMBOL_GPL(ir_codes_dntv_live_dvb_t_table);
 
 /* ---------------------------------------------------------------------- */
 
 /* IO-DATA BCTV7E Remote */
-IR_KEYTAB_TYPE ir_codes_iodata_bctv7e[IR_KEYTAB_SIZE] = {
-       [ 0x40 ] = KEY_TV,
-       [ 0x20 ] = KEY_RADIO,           /* FM */
-       [ 0x60 ] = KEY_EPG,
-       [ 0x00 ] = KEY_POWER,
+static struct ir_scancode ir_codes_iodata_bctv7e[] = {
+       { 0x40, KEY_TV },
+       { 0x20, KEY_RADIO },            /* FM */
+       { 0x60, KEY_EPG },
+       { 0x00, KEY_POWER },
 
        /* Keys 0 to 9 */
-       [ 0x44 ] = KEY_0,               /* 10 */
-       [ 0x50 ] = KEY_1,
-       [ 0x30 ] = KEY_2,
-       [ 0x70 ] = KEY_3,
-       [ 0x48 ] = KEY_4,
-       [ 0x28 ] = KEY_5,
-       [ 0x68 ] = KEY_6,
-       [ 0x58 ] = KEY_7,
-       [ 0x38 ] = KEY_8,
-       [ 0x78 ] = KEY_9,
-
-       [ 0x10 ] = KEY_L,                       /* Live */
-       [ 0x08 ] = KEY_T,                       /* Time Shift */
-
-       [ 0x18 ] = KEY_PLAYPAUSE,               /* Play */
-
-       [ 0x24 ] = KEY_ENTER,           /* 11 */
-       [ 0x64 ] = KEY_ESC,             /* 12 */
-       [ 0x04 ] = KEY_M,                       /* Multi */
-
-       [ 0x54 ] = KEY_VIDEO,
-       [ 0x34 ] = KEY_CHANNELUP,
-       [ 0x74 ] = KEY_VOLUMEUP,
-       [ 0x14 ] = KEY_MUTE,
-
-       [ 0x4c ] = KEY_S,                       /* SVIDEO */
-       [ 0x2c ] = KEY_CHANNELDOWN,
-       [ 0x6c ] = KEY_VOLUMEDOWN,
-       [ 0x0c ] = KEY_ZOOM,
-
-       [ 0x5c ] = KEY_PAUSE,
-       [ 0x3c ] = KEY_C,                       /* || (red) */
-       [ 0x7c ] = KEY_RECORD,          /* recording */
-       [ 0x1c ] = KEY_STOP,
-
-       [ 0x41 ] = KEY_REWIND,          /* backward << */
-       [ 0x21 ] = KEY_PLAY,
-       [ 0x61 ] = KEY_FASTFORWARD,     /* forward >> */
-       [ 0x01 ] = KEY_NEXT,            /* skip >| */
+       { 0x44, KEY_0 },                /* 10 */
+       { 0x50, KEY_1 },
+       { 0x30, KEY_2 },
+       { 0x70, KEY_3 },
+       { 0x48, KEY_4 },
+       { 0x28, KEY_5 },
+       { 0x68, KEY_6 },
+       { 0x58, KEY_7 },
+       { 0x38, KEY_8 },
+       { 0x78, KEY_9 },
+
+       { 0x10, KEY_L },                /* Live */
+       { 0x08, KEY_TIME },             /* Time Shift */
+
+       { 0x18, KEY_PLAYPAUSE },        /* Play */
+
+       { 0x24, KEY_ENTER },            /* 11 */
+       { 0x64, KEY_ESC },              /* 12 */
+       { 0x04, KEY_M },                /* Multi */
+
+       { 0x54, KEY_VIDEO },
+       { 0x34, KEY_CHANNELUP },
+       { 0x74, KEY_VOLUMEUP },
+       { 0x14, KEY_MUTE },
+
+       { 0x4c, KEY_VCR },              /* SVIDEO */
+       { 0x2c, KEY_CHANNELDOWN },
+       { 0x6c, KEY_VOLUMEDOWN },
+       { 0x0c, KEY_ZOOM },
+
+       { 0x5c, KEY_PAUSE },
+       { 0x3c, KEY_RED },              /* || (red) */
+       { 0x7c, KEY_RECORD },           /* recording */
+       { 0x1c, KEY_STOP },
+
+       { 0x41, KEY_REWIND },           /* backward << */
+       { 0x21, KEY_PLAY },
+       { 0x61, KEY_FASTFORWARD },      /* forward >> */
+       { 0x01, KEY_NEXT },             /* skip >| */
 };
 
-EXPORT_SYMBOL_GPL(ir_codes_iodata_bctv7e);
+struct ir_scancode_table ir_codes_iodata_bctv7e_table = {
+       .scan = ir_codes_iodata_bctv7e,
+       .size = ARRAY_SIZE(ir_codes_iodata_bctv7e),
+};
+EXPORT_SYMBOL_GPL(ir_codes_iodata_bctv7e_table);
 
 /* ---------------------------------------------------------------------- */
 
 /* ADS Tech Instant TV DVB-T PCI Remote */
-IR_KEYTAB_TYPE ir_codes_adstech_dvb_t_pci[IR_KEYTAB_SIZE] = {
+static struct ir_scancode ir_codes_adstech_dvb_t_pci[] = {
        /* Keys 0 to 9 */
-       [ 0x4d ] = KEY_0,
-       [ 0x57 ] = KEY_1,
-       [ 0x4f ] = KEY_2,
-       [ 0x53 ] = KEY_3,
-       [ 0x56 ] = KEY_4,
-       [ 0x4e ] = KEY_5,
-       [ 0x5e ] = KEY_6,
-       [ 0x54 ] = KEY_7,
-       [ 0x4c ] = KEY_8,
-       [ 0x5c ] = KEY_9,
-
-       [ 0x5b ] = KEY_POWER,
-       [ 0x5f ] = KEY_MUTE,
-       [ 0x55 ] = KEY_GOTO,
-       [ 0x5d ] = KEY_SEARCH,
-       [ 0x17 ] = KEY_EPG,             /* Guide */
-       [ 0x1f ] = KEY_MENU,
-       [ 0x0f ] = KEY_UP,
-       [ 0x46 ] = KEY_DOWN,
-       [ 0x16 ] = KEY_LEFT,
-       [ 0x1e ] = KEY_RIGHT,
-       [ 0x0e ] = KEY_SELECT,          /* Enter */
-       [ 0x5a ] = KEY_INFO,
-       [ 0x52 ] = KEY_EXIT,
-       [ 0x59 ] = KEY_PREVIOUS,
-       [ 0x51 ] = KEY_NEXT,
-       [ 0x58 ] = KEY_REWIND,
-       [ 0x50 ] = KEY_FORWARD,
-       [ 0x44 ] = KEY_PLAYPAUSE,
-       [ 0x07 ] = KEY_STOP,
-       [ 0x1b ] = KEY_RECORD,
-       [ 0x13 ] = KEY_TUNER,           /* Live */
-       [ 0x0a ] = KEY_A,
-       [ 0x12 ] = KEY_B,
-       [ 0x03 ] = KEY_PROG1,           /* 1 */
-       [ 0x01 ] = KEY_PROG2,           /* 2 */
-       [ 0x00 ] = KEY_PROG3,           /* 3 */
-       [ 0x06 ] = KEY_DVD,
-       [ 0x48 ] = KEY_AUX,             /* Photo */
-       [ 0x40 ] = KEY_VIDEO,
-       [ 0x19 ] = KEY_AUDIO,           /* Music */
-       [ 0x0b ] = KEY_CHANNELUP,
-       [ 0x08 ] = KEY_CHANNELDOWN,
-       [ 0x15 ] = KEY_VOLUMEUP,
-       [ 0x1c ] = KEY_VOLUMEDOWN,
-};
-
-EXPORT_SYMBOL_GPL(ir_codes_adstech_dvb_t_pci);
+       { 0x4d, KEY_0 },
+       { 0x57, KEY_1 },
+       { 0x4f, KEY_2 },
+       { 0x53, KEY_3 },
+       { 0x56, KEY_4 },
+       { 0x4e, KEY_5 },
+       { 0x5e, KEY_6 },
+       { 0x54, KEY_7 },
+       { 0x4c, KEY_8 },
+       { 0x5c, KEY_9 },
+
+       { 0x5b, KEY_POWER },
+       { 0x5f, KEY_MUTE },
+       { 0x55, KEY_GOTO },
+       { 0x5d, KEY_SEARCH },
+       { 0x17, KEY_EPG },              /* Guide */
+       { 0x1f, KEY_MENU },
+       { 0x0f, KEY_UP },
+       { 0x46, KEY_DOWN },
+       { 0x16, KEY_LEFT },
+       { 0x1e, KEY_RIGHT },
+       { 0x0e, KEY_SELECT },           /* Enter */
+       { 0x5a, KEY_INFO },
+       { 0x52, KEY_EXIT },
+       { 0x59, KEY_PREVIOUS },
+       { 0x51, KEY_NEXT },
+       { 0x58, KEY_REWIND },
+       { 0x50, KEY_FORWARD },
+       { 0x44, KEY_PLAYPAUSE },
+       { 0x07, KEY_STOP },
+       { 0x1b, KEY_RECORD },
+       { 0x13, KEY_TUNER },            /* Live */
+       { 0x0a, KEY_A },
+       { 0x12, KEY_B },
+       { 0x03, KEY_PROG1 },            /* 1 */
+       { 0x01, KEY_PROG2 },            /* 2 */
+       { 0x00, KEY_PROG3 },            /* 3 */
+       { 0x06, KEY_DVD },
+       { 0x48, KEY_AUX },              /* Photo */
+       { 0x40, KEY_VIDEO },
+       { 0x19, KEY_AUDIO },            /* Music */
+       { 0x0b, KEY_CHANNELUP },
+       { 0x08, KEY_CHANNELDOWN },
+       { 0x15, KEY_VOLUMEUP },
+       { 0x1c, KEY_VOLUMEDOWN },
+};
+
+struct ir_scancode_table ir_codes_adstech_dvb_t_pci_table = {
+       .scan = ir_codes_adstech_dvb_t_pci,
+       .size = ARRAY_SIZE(ir_codes_adstech_dvb_t_pci),
+};
+EXPORT_SYMBOL_GPL(ir_codes_adstech_dvb_t_pci_table);
 
 /* ---------------------------------------------------------------------- */
 
 /* MSI TV@nywhere MASTER remote */
 
-IR_KEYTAB_TYPE ir_codes_msi_tvanywhere[IR_KEYTAB_SIZE] = {
+static struct ir_scancode ir_codes_msi_tvanywhere[] = {
        /* Keys 0 to 9 */
-       [ 0x00 ] = KEY_0,
-       [ 0x01 ] = KEY_1,
-       [ 0x02 ] = KEY_2,
-       [ 0x03 ] = KEY_3,
-       [ 0x04 ] = KEY_4,
-       [ 0x05 ] = KEY_5,
-       [ 0x06 ] = KEY_6,
-       [ 0x07 ] = KEY_7,
-       [ 0x08 ] = KEY_8,
-       [ 0x09 ] = KEY_9,
-
-       [ 0x0c ] = KEY_MUTE,
-       [ 0x0f ] = KEY_SCREEN,          /* Full Screen */
-       [ 0x10 ] = KEY_F,                       /* Funtion */
-       [ 0x11 ] = KEY_T,                       /* Time shift */
-       [ 0x12 ] = KEY_POWER,
-       [ 0x13 ] = KEY_MEDIA,           /* MTS */
-       [ 0x14 ] = KEY_SLOW,
-       [ 0x16 ] = KEY_REWIND,          /* backward << */
-       [ 0x17 ] = KEY_ENTER,           /* Return */
-       [ 0x18 ] = KEY_FASTFORWARD,     /* forward >> */
-       [ 0x1a ] = KEY_CHANNELUP,
-       [ 0x1b ] = KEY_VOLUMEUP,
-       [ 0x1e ] = KEY_CHANNELDOWN,
-       [ 0x1f ] = KEY_VOLUMEDOWN,
-};
-
-EXPORT_SYMBOL_GPL(ir_codes_msi_tvanywhere);
+       { 0x00, KEY_0 },
+       { 0x01, KEY_1 },
+       { 0x02, KEY_2 },
+       { 0x03, KEY_3 },
+       { 0x04, KEY_4 },
+       { 0x05, KEY_5 },
+       { 0x06, KEY_6 },
+       { 0x07, KEY_7 },
+       { 0x08, KEY_8 },
+       { 0x09, KEY_9 },
+
+       { 0x0c, KEY_MUTE },
+       { 0x0f, KEY_SCREEN },           /* Full Screen */
+       { 0x10, KEY_FN },               /* Funtion */
+       { 0x11, KEY_TIME },             /* Time shift */
+       { 0x12, KEY_POWER },
+       { 0x13, KEY_MEDIA },            /* MTS */
+       { 0x14, KEY_SLOW },
+       { 0x16, KEY_REWIND },           /* backward << */
+       { 0x17, KEY_ENTER },            /* Return */
+       { 0x18, KEY_FASTFORWARD },      /* forward >> */
+       { 0x1a, KEY_CHANNELUP },
+       { 0x1b, KEY_VOLUMEUP },
+       { 0x1e, KEY_CHANNELDOWN },
+       { 0x1f, KEY_VOLUMEDOWN },
+};
+
+struct ir_scancode_table ir_codes_msi_tvanywhere_table = {
+       .scan = ir_codes_msi_tvanywhere,
+       .size = ARRAY_SIZE(ir_codes_msi_tvanywhere),
+};
+EXPORT_SYMBOL_GPL(ir_codes_msi_tvanywhere_table);
 
 /* ---------------------------------------------------------------------- */
 
@@ -626,7 +668,7 @@ EXPORT_SYMBOL_GPL(ir_codes_msi_tvanywhere);
 
 */
 
-IR_KEYTAB_TYPE ir_codes_msi_tvanywhere_plus[IR_KEYTAB_SIZE] = {
+static struct ir_scancode ir_codes_msi_tvanywhere_plus[] = {
 
 /*  ---- Remote Button Layout ----
 
@@ -648,596 +690,645 @@ IR_KEYTAB_TYPE ir_codes_msi_tvanywhere_plus[IR_KEYTAB_SIZE] = {
      <<      FUNC    >>     RESET
 */
 
-       [0x01] = KEY_KP1,             /* 1 */
-       [0x0b] = KEY_KP2,             /* 2 */
-       [0x1b] = KEY_KP3,             /* 3 */
-       [0x05] = KEY_KP4,             /* 4 */
-       [0x09] = KEY_KP5,             /* 5 */
-       [0x15] = KEY_KP6,             /* 6 */
-       [0x06] = KEY_KP7,             /* 7 */
-       [0x0a] = KEY_KP8,             /* 8 */
-       [0x12] = KEY_KP9,             /* 9 */
-       [0x02] = KEY_KP0,             /* 0 */
-       [0x10] = KEY_KPPLUS,          /* + */
-       [0x13] = KEY_AGAIN,           /* Recall */
-
-       [0x1e] = KEY_POWER,           /* Power */
-       [0x07] = KEY_TUNER,           /* Source */
-       [0x1c] = KEY_SEARCH,          /* Scan */
-       [0x18] = KEY_MUTE,            /* Mute */
-
-       [0x03] = KEY_RADIO,           /* TV/FM */
+       { 0x01, KEY_1 },                /* 1 */
+       { 0x0b, KEY_2 },                /* 2 */
+       { 0x1b, KEY_3 },                /* 3 */
+       { 0x05, KEY_4 },                /* 4 */
+       { 0x09, KEY_5 },                /* 5 */
+       { 0x15, KEY_6 },                /* 6 */
+       { 0x06, KEY_7 },                /* 7 */
+       { 0x0a, KEY_8 },                /* 8 */
+       { 0x12, KEY_9 },                /* 9 */
+       { 0x02, KEY_0 },                /* 0 */
+       { 0x10, KEY_KPPLUS },           /* + */
+       { 0x13, KEY_AGAIN },            /* Recall */
+
+       { 0x1e, KEY_POWER },            /* Power */
+       { 0x07, KEY_TUNER },            /* Source */
+       { 0x1c, KEY_SEARCH },           /* Scan */
+       { 0x18, KEY_MUTE },             /* Mute */
+
+       { 0x03, KEY_RADIO },            /* TV/FM */
        /* The next four keys are duplicates that appear to send the
           same IR code as Ch+, Ch-, >>, and << .  The raw code assigned
           to them is the actual code + 0x20 - they will never be
           detected as such unless some way is discovered to distinguish
           these buttons from those that have the same code. */
-       [0x3f] = KEY_RIGHT,           /* |> and Ch+ */
-       [0x37] = KEY_LEFT,            /* <| and Ch- */
-       [0x2c] = KEY_UP,              /* ^^Up and >> */
-       [0x24] = KEY_DOWN,            /* vvDn and << */
-
-       [0x00] = KEY_RECORD,          /* Record */
-       [0x08] = KEY_STOP,            /* Stop */
-       [0x11] = KEY_PLAY,            /* Play */
-
-       [0x0f] = KEY_CLOSE,           /* Minimize */
-       [0x19] = KEY_ZOOM,            /* Zoom */
-       [0x1a] = KEY_SHUFFLE,         /* Snapshot */
-       [0x0d] = KEY_LANGUAGE,        /* MTS */
-
-       [0x14] = KEY_VOLUMEDOWN,      /* Vol- */
-       [0x16] = KEY_VOLUMEUP,        /* Vol+ */
-       [0x17] = KEY_CHANNELDOWN,     /* Ch- */
-       [0x1f] = KEY_CHANNELUP,       /* Ch+ */
+       { 0x3f, KEY_RIGHT },            /* |> and Ch+ */
+       { 0x37, KEY_LEFT },             /* <| and Ch- */
+       { 0x2c, KEY_UP },               /* ^^Up and >> */
+       { 0x24, KEY_DOWN },             /* vvDn and << */
+
+       { 0x00, KEY_RECORD },           /* Record */
+       { 0x08, KEY_STOP },             /* Stop */
+       { 0x11, KEY_PLAY },             /* Play */
+
+       { 0x0f, KEY_CLOSE },            /* Minimize */
+       { 0x19, KEY_ZOOM },             /* Zoom */
+       { 0x1a, KEY_CAMERA },           /* Snapshot */
+       { 0x0d, KEY_LANGUAGE },         /* MTS */
+
+       { 0x14, KEY_VOLUMEDOWN },       /* Vol- */
+       { 0x16, KEY_VOLUMEUP },         /* Vol+ */
+       { 0x17, KEY_CHANNELDOWN },      /* Ch- */
+       { 0x1f, KEY_CHANNELUP },        /* Ch+ */
+
+       { 0x04, KEY_REWIND },           /* << */
+       { 0x0e, KEY_MENU },             /* Function */
+       { 0x0c, KEY_FASTFORWARD },      /* >> */
+       { 0x1d, KEY_RESTART },          /* Reset */
+};
 
-       [0x04] = KEY_REWIND,          /* << */
-       [0x0e] = KEY_MENU,            /* Function */
-       [0x0c] = KEY_FASTFORWARD,     /* >> */
-       [0x1d] = KEY_RESTART,         /* Reset */
+struct ir_scancode_table ir_codes_msi_tvanywhere_plus_table = {
+       .scan = ir_codes_msi_tvanywhere_plus,
+       .size = ARRAY_SIZE(ir_codes_msi_tvanywhere_plus),
 };
-EXPORT_SYMBOL_GPL(ir_codes_msi_tvanywhere_plus);
+EXPORT_SYMBOL_GPL(ir_codes_msi_tvanywhere_plus_table);
 
 /* ---------------------------------------------------------------------- */
 
 /* Cinergy 1400 DVB-T */
-IR_KEYTAB_TYPE ir_codes_cinergy_1400[IR_KEYTAB_SIZE] = {
-       [ 0x01 ] = KEY_POWER,
-       [ 0x02 ] = KEY_1,
-       [ 0x03 ] = KEY_2,
-       [ 0x04 ] = KEY_3,
-       [ 0x05 ] = KEY_4,
-       [ 0x06 ] = KEY_5,
-       [ 0x07 ] = KEY_6,
-       [ 0x08 ] = KEY_7,
-       [ 0x09 ] = KEY_8,
-       [ 0x0a ] = KEY_9,
-       [ 0x0c ] = KEY_0,
-
-       [ 0x0b ] = KEY_VIDEO,
-       [ 0x0d ] = KEY_REFRESH,
-       [ 0x0e ] = KEY_SELECT,
-       [ 0x0f ] = KEY_EPG,
-       [ 0x10 ] = KEY_UP,
-       [ 0x11 ] = KEY_LEFT,
-       [ 0x12 ] = KEY_OK,
-       [ 0x13 ] = KEY_RIGHT,
-       [ 0x14 ] = KEY_DOWN,
-       [ 0x15 ] = KEY_TEXT,
-       [ 0x16 ] = KEY_INFO,
-
-       [ 0x17 ] = KEY_RED,
-       [ 0x18 ] = KEY_GREEN,
-       [ 0x19 ] = KEY_YELLOW,
-       [ 0x1a ] = KEY_BLUE,
-
-       [ 0x1b ] = KEY_CHANNELUP,
-       [ 0x1c ] = KEY_VOLUMEUP,
-       [ 0x1d ] = KEY_MUTE,
-       [ 0x1e ] = KEY_VOLUMEDOWN,
-       [ 0x1f ] = KEY_CHANNELDOWN,
-
-       [ 0x40 ] = KEY_PAUSE,
-       [ 0x4c ] = KEY_PLAY,
-       [ 0x58 ] = KEY_RECORD,
-       [ 0x54 ] = KEY_PREVIOUS,
-       [ 0x48 ] = KEY_STOP,
-       [ 0x5c ] = KEY_NEXT,
-};
-
-EXPORT_SYMBOL_GPL(ir_codes_cinergy_1400);
+static struct ir_scancode ir_codes_cinergy_1400[] = {
+       { 0x01, KEY_POWER },
+       { 0x02, KEY_1 },
+       { 0x03, KEY_2 },
+       { 0x04, KEY_3 },
+       { 0x05, KEY_4 },
+       { 0x06, KEY_5 },
+       { 0x07, KEY_6 },
+       { 0x08, KEY_7 },
+       { 0x09, KEY_8 },
+       { 0x0a, KEY_9 },
+       { 0x0c, KEY_0 },
+
+       { 0x0b, KEY_VIDEO },
+       { 0x0d, KEY_REFRESH },
+       { 0x0e, KEY_SELECT },
+       { 0x0f, KEY_EPG },
+       { 0x10, KEY_UP },
+       { 0x11, KEY_LEFT },
+       { 0x12, KEY_OK },
+       { 0x13, KEY_RIGHT },
+       { 0x14, KEY_DOWN },
+       { 0x15, KEY_TEXT },
+       { 0x16, KEY_INFO },
+
+       { 0x17, KEY_RED },
+       { 0x18, KEY_GREEN },
+       { 0x19, KEY_YELLOW },
+       { 0x1a, KEY_BLUE },
+
+       { 0x1b, KEY_CHANNELUP },
+       { 0x1c, KEY_VOLUMEUP },
+       { 0x1d, KEY_MUTE },
+       { 0x1e, KEY_VOLUMEDOWN },
+       { 0x1f, KEY_CHANNELDOWN },
+
+       { 0x40, KEY_PAUSE },
+       { 0x4c, KEY_PLAY },
+       { 0x58, KEY_RECORD },
+       { 0x54, KEY_PREVIOUS },
+       { 0x48, KEY_STOP },
+       { 0x5c, KEY_NEXT },
+};
+
+struct ir_scancode_table ir_codes_cinergy_1400_table = {
+       .scan = ir_codes_cinergy_1400,
+       .size = ARRAY_SIZE(ir_codes_cinergy_1400),
+};
+EXPORT_SYMBOL_GPL(ir_codes_cinergy_1400_table);
 
 /* ---------------------------------------------------------------------- */
 
 /* AVERTV STUDIO 303 Remote */
-IR_KEYTAB_TYPE ir_codes_avertv_303[IR_KEYTAB_SIZE] = {
-       [ 0x2a ] = KEY_1,
-       [ 0x32 ] = KEY_2,
-       [ 0x3a ] = KEY_3,
-       [ 0x4a ] = KEY_4,
-       [ 0x52 ] = KEY_5,
-       [ 0x5a ] = KEY_6,
-       [ 0x6a ] = KEY_7,
-       [ 0x72 ] = KEY_8,
-       [ 0x7a ] = KEY_9,
-       [ 0x0e ] = KEY_0,
-
-       [ 0x02 ] = KEY_POWER,
-       [ 0x22 ] = KEY_VIDEO,
-       [ 0x42 ] = KEY_AUDIO,
-       [ 0x62 ] = KEY_ZOOM,
-       [ 0x0a ] = KEY_TV,
-       [ 0x12 ] = KEY_CD,
-       [ 0x1a ] = KEY_TEXT,
-
-       [ 0x16 ] = KEY_SUBTITLE,
-       [ 0x1e ] = KEY_REWIND,
-       [ 0x06 ] = KEY_PRINT,
-
-       [ 0x2e ] = KEY_SEARCH,
-       [ 0x36 ] = KEY_SLEEP,
-       [ 0x3e ] = KEY_SHUFFLE,
-       [ 0x26 ] = KEY_MUTE,
-
-       [ 0x4e ] = KEY_RECORD,
-       [ 0x56 ] = KEY_PAUSE,
-       [ 0x5e ] = KEY_STOP,
-       [ 0x46 ] = KEY_PLAY,
-
-       [ 0x6e ] = KEY_RED,
-       [ 0x0b ] = KEY_GREEN,
-       [ 0x66 ] = KEY_YELLOW,
-       [ 0x03 ] = KEY_BLUE,
-
-       [ 0x76 ] = KEY_LEFT,
-       [ 0x7e ] = KEY_RIGHT,
-       [ 0x13 ] = KEY_DOWN,
-       [ 0x1b ] = KEY_UP,
-};
-
-EXPORT_SYMBOL_GPL(ir_codes_avertv_303);
+static struct ir_scancode ir_codes_avertv_303[] = {
+       { 0x2a, KEY_1 },
+       { 0x32, KEY_2 },
+       { 0x3a, KEY_3 },
+       { 0x4a, KEY_4 },
+       { 0x52, KEY_5 },
+       { 0x5a, KEY_6 },
+       { 0x6a, KEY_7 },
+       { 0x72, KEY_8 },
+       { 0x7a, KEY_9 },
+       { 0x0e, KEY_0 },
+
+       { 0x02, KEY_POWER },
+       { 0x22, KEY_VIDEO },
+       { 0x42, KEY_AUDIO },
+       { 0x62, KEY_ZOOM },
+       { 0x0a, KEY_TV },
+       { 0x12, KEY_CD },
+       { 0x1a, KEY_TEXT },
+
+       { 0x16, KEY_SUBTITLE },
+       { 0x1e, KEY_REWIND },
+       { 0x06, KEY_PRINT },
+
+       { 0x2e, KEY_SEARCH },
+       { 0x36, KEY_SLEEP },
+       { 0x3e, KEY_SHUFFLE },
+       { 0x26, KEY_MUTE },
+
+       { 0x4e, KEY_RECORD },
+       { 0x56, KEY_PAUSE },
+       { 0x5e, KEY_STOP },
+       { 0x46, KEY_PLAY },
+
+       { 0x6e, KEY_RED },
+       { 0x0b, KEY_GREEN },
+       { 0x66, KEY_YELLOW },
+       { 0x03, KEY_BLUE },
+
+       { 0x76, KEY_LEFT },
+       { 0x7e, KEY_RIGHT },
+       { 0x13, KEY_DOWN },
+       { 0x1b, KEY_UP },
+};
+
+struct ir_scancode_table ir_codes_avertv_303_table = {
+       .scan = ir_codes_avertv_303,
+       .size = ARRAY_SIZE(ir_codes_avertv_303),
+};
+EXPORT_SYMBOL_GPL(ir_codes_avertv_303_table);
 
 /* ---------------------------------------------------------------------- */
 
 /* DigitalNow DNTV Live! DVB-T Pro Remote */
-IR_KEYTAB_TYPE ir_codes_dntv_live_dvbt_pro[IR_KEYTAB_SIZE] = {
-       [ 0x16 ] = KEY_POWER,
-       [ 0x5b ] = KEY_HOME,
-
-       [ 0x55 ] = KEY_TV,              /* live tv */
-       [ 0x58 ] = KEY_TUNER,           /* digital Radio */
-       [ 0x5a ] = KEY_RADIO,           /* FM radio */
-       [ 0x59 ] = KEY_DVD,             /* dvd menu */
-       [ 0x03 ] = KEY_1,
-       [ 0x01 ] = KEY_2,
-       [ 0x06 ] = KEY_3,
-       [ 0x09 ] = KEY_4,
-       [ 0x1d ] = KEY_5,
-       [ 0x1f ] = KEY_6,
-       [ 0x0d ] = KEY_7,
-       [ 0x19 ] = KEY_8,
-       [ 0x1b ] = KEY_9,
-       [ 0x0c ] = KEY_CANCEL,
-       [ 0x15 ] = KEY_0,
-       [ 0x4a ] = KEY_CLEAR,
-       [ 0x13 ] = KEY_BACK,
-       [ 0x00 ] = KEY_TAB,
-       [ 0x4b ] = KEY_UP,
-       [ 0x4e ] = KEY_LEFT,
-       [ 0x4f ] = KEY_OK,
-       [ 0x52 ] = KEY_RIGHT,
-       [ 0x51 ] = KEY_DOWN,
-       [ 0x1e ] = KEY_VOLUMEUP,
-       [ 0x0a ] = KEY_VOLUMEDOWN,
-       [ 0x02 ] = KEY_CHANNELDOWN,
-       [ 0x05 ] = KEY_CHANNELUP,
-       [ 0x11 ] = KEY_RECORD,
-       [ 0x14 ] = KEY_PLAY,
-       [ 0x4c ] = KEY_PAUSE,
-       [ 0x1a ] = KEY_STOP,
-       [ 0x40 ] = KEY_REWIND,
-       [ 0x12 ] = KEY_FASTFORWARD,
-       [ 0x41 ] = KEY_PREVIOUSSONG,    /* replay |< */
-       [ 0x42 ] = KEY_NEXTSONG,        /* skip >| */
-       [ 0x54 ] = KEY_CAMERA,          /* capture */
-       [ 0x50 ] = KEY_LANGUAGE,        /* sap */
-       [ 0x47 ] = KEY_TV2,             /* pip */
-       [ 0x4d ] = KEY_SCREEN,
-       [ 0x43 ] = KEY_SUBTITLE,
-       [ 0x10 ] = KEY_MUTE,
-       [ 0x49 ] = KEY_AUDIO,           /* l/r */
-       [ 0x07 ] = KEY_SLEEP,
-       [ 0x08 ] = KEY_VIDEO,           /* a/v */
-       [ 0x0e ] = KEY_PREVIOUS,        /* recall */
-       [ 0x45 ] = KEY_ZOOM,            /* zoom + */
-       [ 0x46 ] = KEY_ANGLE,           /* zoom - */
-       [ 0x56 ] = KEY_RED,
-       [ 0x57 ] = KEY_GREEN,
-       [ 0x5c ] = KEY_YELLOW,
-       [ 0x5d ] = KEY_BLUE,
-};
-
-EXPORT_SYMBOL_GPL(ir_codes_dntv_live_dvbt_pro);
-
-IR_KEYTAB_TYPE ir_codes_em_terratec[IR_KEYTAB_SIZE] = {
-       [ 0x01 ] = KEY_CHANNEL,
-       [ 0x02 ] = KEY_SELECT,
-       [ 0x03 ] = KEY_MUTE,
-       [ 0x04 ] = KEY_POWER,
-       [ 0x05 ] = KEY_1,
-       [ 0x06 ] = KEY_2,
-       [ 0x07 ] = KEY_3,
-       [ 0x08 ] = KEY_CHANNELUP,
-       [ 0x09 ] = KEY_4,
-       [ 0x0a ] = KEY_5,
-       [ 0x0b ] = KEY_6,
-       [ 0x0c ] = KEY_CHANNELDOWN,
-       [ 0x0d ] = KEY_7,
-       [ 0x0e ] = KEY_8,
-       [ 0x0f ] = KEY_9,
-       [ 0x10 ] = KEY_VOLUMEUP,
-       [ 0x11 ] = KEY_0,
-       [ 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,
-};
-
-EXPORT_SYMBOL_GPL(ir_codes_em_terratec);
-
-IR_KEYTAB_TYPE ir_codes_pinnacle_grey[IR_KEYTAB_SIZE] = {
-       [ 0x3a ] = KEY_0,
-       [ 0x31 ] = KEY_1,
-       [ 0x32 ] = KEY_2,
-       [ 0x33 ] = KEY_3,
-       [ 0x34 ] = KEY_4,
-       [ 0x35 ] = KEY_5,
-       [ 0x36 ] = KEY_6,
-       [ 0x37 ] = KEY_7,
-       [ 0x38 ] = KEY_8,
-       [ 0x39 ] = KEY_9,
-
-       [ 0x2f ] = KEY_POWER,
-
-       [ 0x2e ] = KEY_P,
-       [ 0x1f ] = KEY_L,
-       [ 0x2b ] = KEY_I,
-
-       [ 0x2d ] = KEY_SCREEN,
-       [ 0x1e ] = KEY_ZOOM,
-       [ 0x1b ] = KEY_VOLUMEUP,
-       [ 0x0f ] = KEY_VOLUMEDOWN,
-       [ 0x17 ] = KEY_CHANNELUP,
-       [ 0x1c ] = KEY_CHANNELDOWN,
-       [ 0x25 ] = KEY_INFO,
-
-       [ 0x3c ] = KEY_MUTE,
-
-       [ 0x3d ] = KEY_LEFT,
-       [ 0x3b ] = KEY_RIGHT,
-
-       [ 0x3f ] = KEY_UP,
-       [ 0x3e ] = KEY_DOWN,
-       [ 0x1a ] = KEY_ENTER,
-
-       [ 0x1d ] = KEY_MENU,
-       [ 0x19 ] = KEY_AGAIN,
-       [ 0x16 ] = KEY_PREVIOUSSONG,
-       [ 0x13 ] = KEY_NEXTSONG,
-       [ 0x15 ] = KEY_PAUSE,
-       [ 0x0e ] = KEY_REWIND,
-       [ 0x0d ] = KEY_PLAY,
-       [ 0x0b ] = KEY_STOP,
-       [ 0x07 ] = KEY_FORWARD,
-       [ 0x27 ] = KEY_RECORD,
-       [ 0x26 ] = KEY_TUNER,
-       [ 0x29 ] = KEY_TEXT,
-       [ 0x2a ] = KEY_MEDIA,
-       [ 0x18 ] = KEY_EPG,
-};
-
-EXPORT_SYMBOL_GPL(ir_codes_pinnacle_grey);
-
-IR_KEYTAB_TYPE ir_codes_flyvideo[IR_KEYTAB_SIZE] = {
-       [ 0x0f ] = KEY_0,
-       [ 0x03 ] = KEY_1,
-       [ 0x04 ] = KEY_2,
-       [ 0x05 ] = KEY_3,
-       [ 0x07 ] = KEY_4,
-       [ 0x08 ] = KEY_5,
-       [ 0x09 ] = KEY_6,
-       [ 0x0b ] = KEY_7,
-       [ 0x0c ] = KEY_8,
-       [ 0x0d ] = KEY_9,
-
-       [ 0x0e ] = KEY_MODE,         // Air/Cable
-       [ 0x11 ] = KEY_VIDEO,        // Video
-       [ 0x15 ] = KEY_AUDIO,        // Audio
-       [ 0x00 ] = KEY_POWER,        // Power
-       [ 0x18 ] = KEY_TUNER,        // AV Source
-       [ 0x02 ] = KEY_ZOOM,         // Fullscreen
-       [ 0x1a ] = KEY_LANGUAGE,     // Stereo
-       [ 0x1b ] = KEY_MUTE,         // Mute
-       [ 0x14 ] = KEY_VOLUMEUP,     // Volume +
-       [ 0x17 ] = KEY_VOLUMEDOWN,   // Volume -
-       [ 0x12 ] = KEY_CHANNELUP,    // Channel +
-       [ 0x13 ] = KEY_CHANNELDOWN,  // Channel -
-       [ 0x06 ] = KEY_AGAIN,        // Recall
-       [ 0x10 ] = KEY_ENTER,        // Enter
-
-       [ 0x19 ] = KEY_BACK,         // Rewind  ( <<< )
-       [ 0x1f ] = KEY_FORWARD,      // Forward ( >>> )
-       [ 0x0a ] = KEY_ANGLE,        // (no label, may be used as the PAUSE button)
-};
-
-EXPORT_SYMBOL_GPL(ir_codes_flyvideo);
-
-IR_KEYTAB_TYPE ir_codes_flydvb[IR_KEYTAB_SIZE] = {
-       [ 0x01 ] = KEY_ZOOM,            // Full Screen
-       [ 0x00 ] = KEY_POWER,           // Power
-
-       [ 0x03 ] = KEY_1,
-       [ 0x04 ] = KEY_2,
-       [ 0x05 ] = KEY_3,
-       [ 0x07 ] = KEY_4,
-       [ 0x08 ] = KEY_5,
-       [ 0x09 ] = KEY_6,
-       [ 0x0b ] = KEY_7,
-       [ 0x0c ] = KEY_8,
-       [ 0x0d ] = KEY_9,
-       [ 0x06 ] = KEY_AGAIN,           // Recall
-       [ 0x0f ] = KEY_0,
-       [ 0x10 ] = KEY_MUTE,            // Mute
-       [ 0x02 ] = KEY_RADIO,           // TV/Radio
-       [ 0x1b ] = KEY_LANGUAGE,                // SAP (Second Audio Program)
-
-       [ 0x14 ] = KEY_VOLUMEUP,                // VOL+
-       [ 0x17 ] = KEY_VOLUMEDOWN,      // VOL-
-       [ 0x12 ] = KEY_CHANNELUP,               // CH+
-       [ 0x13 ] = KEY_CHANNELDOWN,     // CH-
-       [ 0x1d ] = KEY_ENTER,           // Enter
-
-       [ 0x1a ] = KEY_MODE,            // PIP
-       [ 0x18 ] = KEY_TUNER,           // Source
-
-       [ 0x1e ] = KEY_RECORD,          // Record/Pause
-       [ 0x15 ] = KEY_ANGLE,           // Swap (no label on key)
-       [ 0x1c ] = KEY_PAUSE,           // Timeshift/Pause
-       [ 0x19 ] = KEY_BACK,            // Rewind <<
-       [ 0x0a ] = KEY_PLAYPAUSE,               // Play/Pause
-       [ 0x1f ] = KEY_FORWARD,         // Forward >>
-       [ 0x16 ] = KEY_PREVIOUS,                // Back |<<
-       [ 0x11 ] = KEY_STOP,            // Stop
-       [ 0x0e ] = KEY_NEXT,            // End >>|
-};
-
-EXPORT_SYMBOL_GPL(ir_codes_flydvb);
-
-IR_KEYTAB_TYPE ir_codes_cinergy[IR_KEYTAB_SIZE] = {
-       [ 0x00 ] = KEY_0,
-       [ 0x01 ] = KEY_1,
-       [ 0x02 ] = KEY_2,
-       [ 0x03 ] = KEY_3,
-       [ 0x04 ] = KEY_4,
-       [ 0x05 ] = KEY_5,
-       [ 0x06 ] = KEY_6,
-       [ 0x07 ] = KEY_7,
-       [ 0x08 ] = KEY_8,
-       [ 0x09 ] = KEY_9,
-
-       [ 0x0a ] = KEY_POWER,
-       [ 0x0b ] = KEY_PROG1,           // app
-       [ 0x0c ] = KEY_ZOOM,            // zoom/fullscreen
-       [ 0x0d ] = KEY_CHANNELUP,       // channel
-       [ 0x0e ] = KEY_CHANNELDOWN,     // channel-
-       [ 0x0f ] = KEY_VOLUMEUP,
-       [ 0x10 ] = KEY_VOLUMEDOWN,
-       [ 0x11 ] = KEY_TUNER,           // AV
-       [ 0x12 ] = KEY_NUMLOCK,         // -/--
-       [ 0x13 ] = KEY_AUDIO,           // audio
-       [ 0x14 ] = KEY_MUTE,
-       [ 0x15 ] = KEY_UP,
-       [ 0x16 ] = KEY_DOWN,
-       [ 0x17 ] = KEY_LEFT,
-       [ 0x18 ] = KEY_RIGHT,
-       [ 0x19 ] = BTN_LEFT,
-       [ 0x1a ] = BTN_RIGHT,
-       [ 0x1b ] = KEY_WWW,             // text
-       [ 0x1c ] = KEY_REWIND,
-       [ 0x1d ] = KEY_FORWARD,
-       [ 0x1e ] = KEY_RECORD,
-       [ 0x1f ] = KEY_PLAY,
-       [ 0x20 ] = KEY_PREVIOUSSONG,
-       [ 0x21 ] = KEY_NEXTSONG,
-       [ 0x22 ] = KEY_PAUSE,
-       [ 0x23 ] = KEY_STOP,
-};
-
-EXPORT_SYMBOL_GPL(ir_codes_cinergy);
+static struct ir_scancode ir_codes_dntv_live_dvbt_pro[] = {
+       { 0x16, KEY_POWER },
+       { 0x5b, KEY_HOME },
+
+       { 0x55, KEY_TV },               /* live tv */
+       { 0x58, KEY_TUNER },            /* digital Radio */
+       { 0x5a, KEY_RADIO },            /* FM radio */
+       { 0x59, KEY_DVD },              /* dvd menu */
+       { 0x03, KEY_1 },
+       { 0x01, KEY_2 },
+       { 0x06, KEY_3 },
+       { 0x09, KEY_4 },
+       { 0x1d, KEY_5 },
+       { 0x1f, KEY_6 },
+       { 0x0d, KEY_7 },
+       { 0x19, KEY_8 },
+       { 0x1b, KEY_9 },
+       { 0x0c, KEY_CANCEL },
+       { 0x15, KEY_0 },
+       { 0x4a, KEY_CLEAR },
+       { 0x13, KEY_BACK },
+       { 0x00, KEY_TAB },
+       { 0x4b, KEY_UP },
+       { 0x4e, KEY_LEFT },
+       { 0x4f, KEY_OK },
+       { 0x52, KEY_RIGHT },
+       { 0x51, KEY_DOWN },
+       { 0x1e, KEY_VOLUMEUP },
+       { 0x0a, KEY_VOLUMEDOWN },
+       { 0x02, KEY_CHANNELDOWN },
+       { 0x05, KEY_CHANNELUP },
+       { 0x11, KEY_RECORD },
+       { 0x14, KEY_PLAY },
+       { 0x4c, KEY_PAUSE },
+       { 0x1a, KEY_STOP },
+       { 0x40, KEY_REWIND },
+       { 0x12, KEY_FASTFORWARD },
+       { 0x41, KEY_PREVIOUSSONG },     /* replay |< */
+       { 0x42, KEY_NEXTSONG },         /* skip >| */
+       { 0x54, KEY_CAMERA },           /* capture */
+       { 0x50, KEY_LANGUAGE },         /* sap */
+       { 0x47, KEY_TV2 },              /* pip */
+       { 0x4d, KEY_SCREEN },
+       { 0x43, KEY_SUBTITLE },
+       { 0x10, KEY_MUTE },
+       { 0x49, KEY_AUDIO },            /* l/r */
+       { 0x07, KEY_SLEEP },
+       { 0x08, KEY_VIDEO },            /* a/v */
+       { 0x0e, KEY_PREVIOUS },         /* recall */
+       { 0x45, KEY_ZOOM },             /* zoom + */
+       { 0x46, KEY_ANGLE },            /* zoom - */
+       { 0x56, KEY_RED },
+       { 0x57, KEY_GREEN },
+       { 0x5c, KEY_YELLOW },
+       { 0x5d, KEY_BLUE },
+};
+
+struct ir_scancode_table ir_codes_dntv_live_dvbt_pro_table = {
+       .scan = ir_codes_dntv_live_dvbt_pro,
+       .size = ARRAY_SIZE(ir_codes_dntv_live_dvbt_pro),
+};
+EXPORT_SYMBOL_GPL(ir_codes_dntv_live_dvbt_pro_table);
+
+static struct ir_scancode ir_codes_em_terratec[] = {
+       { 0x01, KEY_CHANNEL },
+       { 0x02, KEY_SELECT },
+       { 0x03, KEY_MUTE },
+       { 0x04, KEY_POWER },
+       { 0x05, KEY_1 },
+       { 0x06, KEY_2 },
+       { 0x07, KEY_3 },
+       { 0x08, KEY_CHANNELUP },
+       { 0x09, KEY_4 },
+       { 0x0a, KEY_5 },
+       { 0x0b, KEY_6 },
+       { 0x0c, KEY_CHANNELDOWN },
+       { 0x0d, KEY_7 },
+       { 0x0e, KEY_8 },
+       { 0x0f, KEY_9 },
+       { 0x10, KEY_VOLUMEUP },
+       { 0x11, KEY_0 },
+       { 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 },
+};
+
+struct ir_scancode_table ir_codes_em_terratec_table = {
+       .scan = ir_codes_em_terratec,
+       .size = ARRAY_SIZE(ir_codes_em_terratec),
+};
+EXPORT_SYMBOL_GPL(ir_codes_em_terratec_table);
+
+static struct ir_scancode ir_codes_pinnacle_grey[] = {
+       { 0x3a, KEY_0 },
+       { 0x31, KEY_1 },
+       { 0x32, KEY_2 },
+       { 0x33, KEY_3 },
+       { 0x34, KEY_4 },
+       { 0x35, KEY_5 },
+       { 0x36, KEY_6 },
+       { 0x37, KEY_7 },
+       { 0x38, KEY_8 },
+       { 0x39, KEY_9 },
+
+       { 0x2f, KEY_POWER },
+
+       { 0x2e, KEY_P },
+       { 0x1f, KEY_L },
+       { 0x2b, KEY_I },
+
+       { 0x2d, KEY_SCREEN },
+       { 0x1e, KEY_ZOOM },
+       { 0x1b, KEY_VOLUMEUP },
+       { 0x0f, KEY_VOLUMEDOWN },
+       { 0x17, KEY_CHANNELUP },
+       { 0x1c, KEY_CHANNELDOWN },
+       { 0x25, KEY_INFO },
+
+       { 0x3c, KEY_MUTE },
+
+       { 0x3d, KEY_LEFT },
+       { 0x3b, KEY_RIGHT },
+
+       { 0x3f, KEY_UP },
+       { 0x3e, KEY_DOWN },
+       { 0x1a, KEY_ENTER },
+
+       { 0x1d, KEY_MENU },
+       { 0x19, KEY_AGAIN },
+       { 0x16, KEY_PREVIOUSSONG },
+       { 0x13, KEY_NEXTSONG },
+       { 0x15, KEY_PAUSE },
+       { 0x0e, KEY_REWIND },
+       { 0x0d, KEY_PLAY },
+       { 0x0b, KEY_STOP },
+       { 0x07, KEY_FORWARD },
+       { 0x27, KEY_RECORD },
+       { 0x26, KEY_TUNER },
+       { 0x29, KEY_TEXT },
+       { 0x2a, KEY_MEDIA },
+       { 0x18, KEY_EPG },
+};
+
+struct ir_scancode_table ir_codes_pinnacle_grey_table = {
+       .scan = ir_codes_pinnacle_grey,
+       .size = ARRAY_SIZE(ir_codes_pinnacle_grey),
+};
+EXPORT_SYMBOL_GPL(ir_codes_pinnacle_grey_table);
+
+static struct ir_scancode ir_codes_flyvideo[] = {
+       { 0x0f, KEY_0 },
+       { 0x03, KEY_1 },
+       { 0x04, KEY_2 },
+       { 0x05, KEY_3 },
+       { 0x07, KEY_4 },
+       { 0x08, KEY_5 },
+       { 0x09, KEY_6 },
+       { 0x0b, KEY_7 },
+       { 0x0c, KEY_8 },
+       { 0x0d, KEY_9 },
+
+       { 0x0e, KEY_MODE },     /* Air/Cable */
+       { 0x11, KEY_VIDEO },    /* Video */
+       { 0x15, KEY_AUDIO },    /* Audio */
+       { 0x00, KEY_POWER },    /* Power */
+       { 0x18, KEY_TUNER },    /* AV Source */
+       { 0x02, KEY_ZOOM },     /* Fullscreen */
+       { 0x1a, KEY_LANGUAGE }, /* Stereo */
+       { 0x1b, KEY_MUTE },     /* Mute */
+       { 0x14, KEY_VOLUMEUP }, /* Volume + */
+       { 0x17, KEY_VOLUMEDOWN },/* Volume - */
+       { 0x12, KEY_CHANNELUP },/* Channel + */
+       { 0x13, KEY_CHANNELDOWN },/* Channel - */
+       { 0x06, KEY_AGAIN },    /* Recall */
+       { 0x10, KEY_ENTER },    /* Enter */
+
+       { 0x19, KEY_BACK },     /* Rewind  ( <<< ) */
+       { 0x1f, KEY_FORWARD },  /* Forward ( >>> ) */
+       { 0x0a, KEY_ANGLE },    /* no label, may be used as the PAUSE button */
+};
+
+struct ir_scancode_table ir_codes_flyvideo_table = {
+       .scan = ir_codes_flyvideo,
+       .size = ARRAY_SIZE(ir_codes_flyvideo),
+};
+EXPORT_SYMBOL_GPL(ir_codes_flyvideo_table);
+
+static struct ir_scancode ir_codes_flydvb[] = {
+       { 0x01, KEY_ZOOM },             /* Full Screen */
+       { 0x00, KEY_POWER },            /* Power */
+
+       { 0x03, KEY_1 },
+       { 0x04, KEY_2 },
+       { 0x05, KEY_3 },
+       { 0x07, KEY_4 },
+       { 0x08, KEY_5 },
+       { 0x09, KEY_6 },
+       { 0x0b, KEY_7 },
+       { 0x0c, KEY_8 },
+       { 0x0d, KEY_9 },
+       { 0x06, KEY_AGAIN },            /* Recall */
+       { 0x0f, KEY_0 },
+       { 0x10, KEY_MUTE },             /* Mute */
+       { 0x02, KEY_RADIO },            /* TV/Radio */
+       { 0x1b, KEY_LANGUAGE },         /* SAP (Second Audio Program) */
+
+       { 0x14, KEY_VOLUMEUP },         /* VOL+ */
+       { 0x17, KEY_VOLUMEDOWN },       /* VOL- */
+       { 0x12, KEY_CHANNELUP },        /* CH+ */
+       { 0x13, KEY_CHANNELDOWN },      /* CH- */
+       { 0x1d, KEY_ENTER },            /* Enter */
+
+       { 0x1a, KEY_MODE },             /* PIP */
+       { 0x18, KEY_TUNER },            /* Source */
+
+       { 0x1e, KEY_RECORD },           /* Record/Pause */
+       { 0x15, KEY_ANGLE },            /* Swap (no label on key) */
+       { 0x1c, KEY_PAUSE },            /* Timeshift/Pause */
+       { 0x19, KEY_BACK },             /* Rewind << */
+       { 0x0a, KEY_PLAYPAUSE },        /* Play/Pause */
+       { 0x1f, KEY_FORWARD },          /* Forward >> */
+       { 0x16, KEY_PREVIOUS },         /* Back |<< */
+       { 0x11, KEY_STOP },             /* Stop */
+       { 0x0e, KEY_NEXT },             /* End >>| */
+};
+
+struct ir_scancode_table ir_codes_flydvb_table = {
+       .scan = ir_codes_flydvb,
+       .size = ARRAY_SIZE(ir_codes_flydvb),
+};
+EXPORT_SYMBOL_GPL(ir_codes_flydvb_table);
+
+static struct ir_scancode ir_codes_cinergy[] = {
+       { 0x00, KEY_0 },
+       { 0x01, KEY_1 },
+       { 0x02, KEY_2 },
+       { 0x03, KEY_3 },
+       { 0x04, KEY_4 },
+       { 0x05, KEY_5 },
+       { 0x06, KEY_6 },
+       { 0x07, KEY_7 },
+       { 0x08, KEY_8 },
+       { 0x09, KEY_9 },
+
+       { 0x0a, KEY_POWER },
+       { 0x0b, KEY_PROG1 },            /* app */
+       { 0x0c, KEY_ZOOM },             /* zoom/fullscreen */
+       { 0x0d, KEY_CHANNELUP },        /* channel */
+       { 0x0e, KEY_CHANNELDOWN },      /* channel- */
+       { 0x0f, KEY_VOLUMEUP },
+       { 0x10, KEY_VOLUMEDOWN },
+       { 0x11, KEY_TUNER },            /* AV */
+       { 0x12, KEY_NUMLOCK },          /* -/-- */
+       { 0x13, KEY_AUDIO },            /* audio */
+       { 0x14, KEY_MUTE },
+       { 0x15, KEY_UP },
+       { 0x16, KEY_DOWN },
+       { 0x17, KEY_LEFT },
+       { 0x18, KEY_RIGHT },
+       { 0x19, BTN_LEFT, },
+       { 0x1a, BTN_RIGHT, },
+       { 0x1b, KEY_WWW },              /* text */
+       { 0x1c, KEY_REWIND },
+       { 0x1d, KEY_FORWARD },
+       { 0x1e, KEY_RECORD },
+       { 0x1f, KEY_PLAY },
+       { 0x20, KEY_PREVIOUSSONG },
+       { 0x21, KEY_NEXTSONG },
+       { 0x22, KEY_PAUSE },
+       { 0x23, KEY_STOP },
+};
+
+struct ir_scancode_table ir_codes_cinergy_table = {
+       .scan = ir_codes_cinergy,
+       .size = ARRAY_SIZE(ir_codes_cinergy),
+};
+EXPORT_SYMBOL_GPL(ir_codes_cinergy_table);
 
 /* Alfons Geser <a.geser@cox.net>
  * updates from Job D. R. Borges <jobdrb@ig.com.br> */
-IR_KEYTAB_TYPE ir_codes_eztv[IR_KEYTAB_SIZE] = {
-       [ 0x12 ] = KEY_POWER,
-       [ 0x01 ] = KEY_TV,             // DVR
-       [ 0x15 ] = KEY_DVD,            // DVD
-       [ 0x17 ] = KEY_AUDIO,          // music
-                                    // DVR mode / DVD mode / music mode
-
-       [ 0x1b ] = KEY_MUTE,           // mute
-       [ 0x02 ] = KEY_LANGUAGE,       // MTS/SAP / audio / autoseek
-       [ 0x1e ] = KEY_SUBTITLE,       // closed captioning / subtitle / seek
-       [ 0x16 ] = KEY_ZOOM,           // full screen
-       [ 0x1c ] = KEY_VIDEO,          // video source / eject / delall
-       [ 0x1d ] = KEY_RESTART,        // playback / angle / del
-       [ 0x2f ] = KEY_SEARCH,         // scan / menu / playlist
-       [ 0x30 ] = KEY_CHANNEL,        // CH surfing / bookmark / memo
-
-       [ 0x31 ] = KEY_HELP,           // help
-       [ 0x32 ] = KEY_MODE,           // num/memo
-       [ 0x33 ] = KEY_ESC,            // cancel
-
-       [ 0x0c ] = KEY_UP,             // up
-       [ 0x10 ] = KEY_DOWN,           // down
-       [ 0x08 ] = KEY_LEFT,           // left
-       [ 0x04 ] = KEY_RIGHT,          // right
-       [ 0x03 ] = KEY_SELECT,         // select
-
-       [ 0x1f ] = KEY_REWIND,         // rewind
-       [ 0x20 ] = KEY_PLAYPAUSE,      // play/pause
-       [ 0x29 ] = KEY_FORWARD,        // forward
-       [ 0x14 ] = KEY_AGAIN,          // repeat
-       [ 0x2b ] = KEY_RECORD,         // recording
-       [ 0x2c ] = KEY_STOP,           // stop
-       [ 0x2d ] = KEY_PLAY,           // play
-       [ 0x2e ] = KEY_SHUFFLE,        // snapshot / shuffle
-
-       [ 0x00 ] = KEY_0,
-       [ 0x05 ] = KEY_1,
-       [ 0x06 ] = KEY_2,
-       [ 0x07 ] = KEY_3,
-       [ 0x09 ] = KEY_4,
-       [ 0x0a ] = KEY_5,
-       [ 0x0b ] = KEY_6,
-       [ 0x0d ] = KEY_7,
-       [ 0x0e ] = KEY_8,
-       [ 0x0f ] = KEY_9,
-
-       [ 0x2a ] = KEY_VOLUMEUP,
-       [ 0x11 ] = KEY_VOLUMEDOWN,
-       [ 0x18 ] = KEY_CHANNELUP,      // CH.tracking up
-       [ 0x19 ] = KEY_CHANNELDOWN,    // CH.tracking down
-
-       [ 0x13 ] = KEY_ENTER,        // enter
-       [ 0x21 ] = KEY_DOT,          // . (decimal dot)
-};
-
-EXPORT_SYMBOL_GPL(ir_codes_eztv);
+static struct ir_scancode ir_codes_eztv[] = {
+       { 0x12, KEY_POWER },
+       { 0x01, KEY_TV },       /* DVR */
+       { 0x15, KEY_DVD },      /* DVD */
+       { 0x17, KEY_AUDIO },    /* music */
+                               /* DVR mode / DVD mode / music mode */
+
+       { 0x1b, KEY_MUTE },     /* mute */
+       { 0x02, KEY_LANGUAGE }, /* MTS/SAP / audio / autoseek */
+       { 0x1e, KEY_SUBTITLE }, /* closed captioning / subtitle / seek */
+       { 0x16, KEY_ZOOM },     /* full screen */
+       { 0x1c, KEY_VIDEO },    /* video source / eject / delall */
+       { 0x1d, KEY_RESTART },  /* playback / angle / del */
+       { 0x2f, KEY_SEARCH },   /* scan / menu / playlist */
+       { 0x30, KEY_CHANNEL },  /* CH surfing / bookmark / memo */
+
+       { 0x31, KEY_HELP },     /* help */
+       { 0x32, KEY_MODE },     /* num/memo */
+       { 0x33, KEY_ESC },      /* cancel */
+
+       { 0x0c, KEY_UP },       /* up */
+       { 0x10, KEY_DOWN },     /* down */
+       { 0x08, KEY_LEFT },     /* left */
+       { 0x04, KEY_RIGHT },    /* right */
+       { 0x03, KEY_SELECT },   /* select */
+
+       { 0x1f, KEY_REWIND },   /* rewind */
+       { 0x20, KEY_PLAYPAUSE },/* play/pause */
+       { 0x29, KEY_FORWARD },  /* forward */
+       { 0x14, KEY_AGAIN },    /* repeat */
+       { 0x2b, KEY_RECORD },   /* recording */
+       { 0x2c, KEY_STOP },     /* stop */
+       { 0x2d, KEY_PLAY },     /* play */
+       { 0x2e, KEY_CAMERA },   /* snapshot / shuffle */
+
+       { 0x00, KEY_0 },
+       { 0x05, KEY_1 },
+       { 0x06, KEY_2 },
+       { 0x07, KEY_3 },
+       { 0x09, KEY_4 },
+       { 0x0a, KEY_5 },
+       { 0x0b, KEY_6 },
+       { 0x0d, KEY_7 },
+       { 0x0e, KEY_8 },
+       { 0x0f, KEY_9 },
+
+       { 0x2a, KEY_VOLUMEUP },
+       { 0x11, KEY_VOLUMEDOWN },
+       { 0x18, KEY_CHANNELUP },/* CH.tracking up */
+       { 0x19, KEY_CHANNELDOWN },/* CH.tracking down */
+
+       { 0x13, KEY_ENTER },    /* enter */
+       { 0x21, KEY_DOT },      /* . (decimal dot) */
+};
+
+struct ir_scancode_table ir_codes_eztv_table = {
+       .scan = ir_codes_eztv,
+       .size = ARRAY_SIZE(ir_codes_eztv),
+};
+EXPORT_SYMBOL_GPL(ir_codes_eztv_table);
 
 /* Alex Hermann <gaaf@gmx.net> */
-IR_KEYTAB_TYPE ir_codes_avermedia[IR_KEYTAB_SIZE] = {
-       [ 0x28 ] = KEY_1,
-       [ 0x18 ] = KEY_2,
-       [ 0x38 ] = KEY_3,
-       [ 0x24 ] = KEY_4,
-       [ 0x14 ] = KEY_5,
-       [ 0x34 ] = KEY_6,
-       [ 0x2c ] = KEY_7,
-       [ 0x1c ] = KEY_8,
-       [ 0x3c ] = KEY_9,
-       [ 0x22 ] = KEY_0,
-
-       [ 0x20 ] = KEY_TV,              /* TV/FM */
-       [ 0x10 ] = KEY_CD,              /* CD */
-       [ 0x30 ] = KEY_TEXT,            /* TELETEXT */
-       [ 0x00 ] = KEY_POWER,           /* POWER */
-
-       [ 0x08 ] = KEY_VIDEO,           /* VIDEO */
-       [ 0x04 ] = KEY_AUDIO,           /* AUDIO */
-       [ 0x0c ] = KEY_ZOOM,            /* FULL SCREEN */
-
-       [ 0x12 ] = KEY_SUBTITLE,        /* DISPLAY */
-       [ 0x32 ] = KEY_REWIND,          /* LOOP */
-       [ 0x02 ] = KEY_PRINT,           /* PREVIEW */
-
-       [ 0x2a ] = KEY_SEARCH,          /* AUTOSCAN */
-       [ 0x1a ] = KEY_SLEEP,           /* FREEZE */
-       [ 0x3a ] = KEY_SHUFFLE,         /* SNAPSHOT */
-       [ 0x0a ] = KEY_MUTE,            /* MUTE */
-
-       [ 0x26 ] = KEY_RECORD,          /* RECORD */
-       [ 0x16 ] = KEY_PAUSE,           /* PAUSE */
-       [ 0x36 ] = KEY_STOP,            /* STOP */
-       [ 0x06 ] = KEY_PLAY,            /* PLAY */
-
-       [ 0x2e ] = KEY_RED,             /* RED */
-       [ 0x21 ] = KEY_GREEN,           /* GREEN */
-       [ 0x0e ] = KEY_YELLOW,          /* YELLOW */
-       [ 0x01 ] = KEY_BLUE,            /* BLUE */
-
-       [ 0x1e ] = KEY_VOLUMEDOWN,      /* VOLUME- */
-       [ 0x3e ] = KEY_VOLUMEUP,        /* VOLUME+ */
-       [ 0x11 ] = KEY_CHANNELDOWN,     /* CHANNEL/PAGE- */
-       [ 0x31 ] = KEY_CHANNELUP        /* CHANNEL/PAGE+ */
-};
-
-EXPORT_SYMBOL_GPL(ir_codes_avermedia);
-
-IR_KEYTAB_TYPE ir_codes_videomate_tv_pvr[IR_KEYTAB_SIZE] = {
-       [ 0x14 ] = KEY_MUTE,
-       [ 0x24 ] = KEY_ZOOM,
-
-       [ 0x01 ] = KEY_DVD,
-       [ 0x23 ] = KEY_RADIO,
-       [ 0x00 ] = KEY_TV,
-
-       [ 0x0a ] = KEY_REWIND,
-       [ 0x08 ] = KEY_PLAYPAUSE,
-       [ 0x0f ] = KEY_FORWARD,
-
-       [ 0x02 ] = KEY_PREVIOUS,
-       [ 0x07 ] = KEY_STOP,
-       [ 0x06 ] = KEY_NEXT,
-
-       [ 0x0c ] = KEY_UP,
-       [ 0x0e ] = KEY_DOWN,
-       [ 0x0b ] = KEY_LEFT,
-       [ 0x0d ] = KEY_RIGHT,
-       [ 0x11 ] = KEY_OK,
-
-       [ 0x03 ] = KEY_MENU,
-       [ 0x09 ] = KEY_SETUP,
-       [ 0x05 ] = KEY_VIDEO,
-       [ 0x22 ] = KEY_CHANNEL,
-
-       [ 0x12 ] = KEY_VOLUMEUP,
-       [ 0x15 ] = KEY_VOLUMEDOWN,
-       [ 0x10 ] = KEY_CHANNELUP,
-       [ 0x13 ] = KEY_CHANNELDOWN,
-
-       [ 0x04 ] = KEY_RECORD,
-
-       [ 0x16 ] = KEY_1,
-       [ 0x17 ] = KEY_2,
-       [ 0x18 ] = KEY_3,
-       [ 0x19 ] = KEY_4,
-       [ 0x1a ] = KEY_5,
-       [ 0x1b ] = KEY_6,
-       [ 0x1c ] = KEY_7,
-       [ 0x1d ] = KEY_8,
-       [ 0x1e ] = KEY_9,
-       [ 0x1f ] = KEY_0,
-
-       [ 0x20 ] = KEY_LANGUAGE,
-       [ 0x21 ] = KEY_SLEEP,
-};
-
-EXPORT_SYMBOL_GPL(ir_codes_videomate_tv_pvr);
+static struct ir_scancode ir_codes_avermedia[] = {
+       { 0x28, KEY_1 },
+       { 0x18, KEY_2 },
+       { 0x38, KEY_3 },
+       { 0x24, KEY_4 },
+       { 0x14, KEY_5 },
+       { 0x34, KEY_6 },
+       { 0x2c, KEY_7 },
+       { 0x1c, KEY_8 },
+       { 0x3c, KEY_9 },
+       { 0x22, KEY_0 },
+
+       { 0x20, KEY_TV },               /* TV/FM */
+       { 0x10, KEY_CD },               /* CD */
+       { 0x30, KEY_TEXT },             /* TELETEXT */
+       { 0x00, KEY_POWER },            /* POWER */
+
+       { 0x08, KEY_VIDEO },            /* VIDEO */
+       { 0x04, KEY_AUDIO },            /* AUDIO */
+       { 0x0c, KEY_ZOOM },             /* FULL SCREEN */
+
+       { 0x12, KEY_SUBTITLE },         /* DISPLAY */
+       { 0x32, KEY_REWIND },           /* LOOP */
+       { 0x02, KEY_PRINT },            /* PREVIEW */
+
+       { 0x2a, KEY_SEARCH },           /* AUTOSCAN */
+       { 0x1a, KEY_SLEEP },            /* FREEZE */
+       { 0x3a, KEY_CAMERA },           /* SNAPSHOT */
+       { 0x0a, KEY_MUTE },             /* MUTE */
+
+       { 0x26, KEY_RECORD },           /* RECORD */
+       { 0x16, KEY_PAUSE },            /* PAUSE */
+       { 0x36, KEY_STOP },             /* STOP */
+       { 0x06, KEY_PLAY },             /* PLAY */
+
+       { 0x2e, KEY_RED },              /* RED */
+       { 0x21, KEY_GREEN },            /* GREEN */
+       { 0x0e, KEY_YELLOW },           /* YELLOW */
+       { 0x01, KEY_BLUE },             /* BLUE */
+
+       { 0x1e, KEY_VOLUMEDOWN },       /* VOLUME- */
+       { 0x3e, KEY_VOLUMEUP },         /* VOLUME+ */
+       { 0x11, KEY_CHANNELDOWN },      /* CHANNEL/PAGE- */
+       { 0x31, KEY_CHANNELUP }         /* CHANNEL/PAGE+ */
+};
+
+struct ir_scancode_table ir_codes_avermedia_table = {
+       .scan = ir_codes_avermedia,
+       .size = ARRAY_SIZE(ir_codes_avermedia),
+};
+EXPORT_SYMBOL_GPL(ir_codes_avermedia_table);
+
+static struct ir_scancode ir_codes_videomate_tv_pvr[] = {
+       { 0x14, KEY_MUTE },
+       { 0x24, KEY_ZOOM },
+
+       { 0x01, KEY_DVD },
+       { 0x23, KEY_RADIO },
+       { 0x00, KEY_TV },
+
+       { 0x0a, KEY_REWIND },
+       { 0x08, KEY_PLAYPAUSE },
+       { 0x0f, KEY_FORWARD },
+
+       { 0x02, KEY_PREVIOUS },
+       { 0x07, KEY_STOP },
+       { 0x06, KEY_NEXT },
+
+       { 0x0c, KEY_UP },
+       { 0x0e, KEY_DOWN },
+       { 0x0b, KEY_LEFT },
+       { 0x0d, KEY_RIGHT },
+       { 0x11, KEY_OK },
+
+       { 0x03, KEY_MENU },
+       { 0x09, KEY_SETUP },
+       { 0x05, KEY_VIDEO },
+       { 0x22, KEY_CHANNEL },
+
+       { 0x12, KEY_VOLUMEUP },
+       { 0x15, KEY_VOLUMEDOWN },
+       { 0x10, KEY_CHANNELUP },
+       { 0x13, KEY_CHANNELDOWN },
+
+       { 0x04, KEY_RECORD },
+
+       { 0x16, KEY_1 },
+       { 0x17, KEY_2 },
+       { 0x18, KEY_3 },
+       { 0x19, KEY_4 },
+       { 0x1a, KEY_5 },
+       { 0x1b, KEY_6 },
+       { 0x1c, KEY_7 },
+       { 0x1d, KEY_8 },
+       { 0x1e, KEY_9 },
+       { 0x1f, KEY_0 },
+
+       { 0x20, KEY_LANGUAGE },
+       { 0x21, KEY_SLEEP },
+};
+
+struct ir_scancode_table ir_codes_videomate_tv_pvr_table = {
+       .scan = ir_codes_videomate_tv_pvr,
+       .size = ARRAY_SIZE(ir_codes_videomate_tv_pvr),
+};
+EXPORT_SYMBOL_GPL(ir_codes_videomate_tv_pvr_table);
 
 /* Michael Tokarev <mjt@tls.msk.ru>
    http://www.corpit.ru/mjt/beholdTV/remote_control.jpg
-   keytable is used by MANLI MTV00[ 0x0c ] and BeholdTV 40[13] at
+   keytable is used by MANLI MTV00[0x0c] and BeholdTV 40[13] at
    least, and probably other cards too.
    The "ascii-art picture" below (in comments, first row
    is the keycode in hex, and subsequent row(s) shows
    the button labels (several variants when appropriate)
    helps to descide which keycodes to assign to the buttons.
  */
-IR_KEYTAB_TYPE ir_codes_manli[IR_KEYTAB_SIZE] = {
+static struct ir_scancode ir_codes_manli[] = {
 
        /*  0x1c            0x12  *
         * FUNCTION         POWER *
         *   FM              (|)  *
         *                        */
-       [ 0x1c ] = KEY_RADIO,   /*XXX*/
-       [ 0x12 ] = KEY_POWER,
+       { 0x1c, KEY_RADIO },    /*XXX*/
+       { 0x12, KEY_POWER },
 
        /*  0x01    0x02    0x03  *
         *   1       2       3    *
@@ -1248,29 +1339,29 @@ IR_KEYTAB_TYPE ir_codes_manli[IR_KEYTAB_SIZE] = {
         *  0x07    0x08    0x09  *
         *   7       8       9    *
         *                        */
-       [ 0x01 ] = KEY_1,
-       [ 0x02 ] = KEY_2,
-       [ 0x03 ] = KEY_3,
-       [ 0x04 ] = KEY_4,
-       [ 0x05 ] = KEY_5,
-       [ 0x06 ] = KEY_6,
-       [ 0x07 ] = KEY_7,
-       [ 0x08 ] = KEY_8,
-       [ 0x09 ] = KEY_9,
+       { 0x01, KEY_1 },
+       { 0x02, KEY_2 },
+       { 0x03, KEY_3 },
+       { 0x04, KEY_4 },
+       { 0x05, KEY_5 },
+       { 0x06, KEY_6 },
+       { 0x07, KEY_7 },
+       { 0x08, KEY_8 },
+       { 0x09, KEY_9 },
 
        /*  0x0a    0x00    0x17  *
         * RECALL    0      +100  *
         *                  PLUS  *
         *                        */
-       [ 0x0a ] = KEY_AGAIN,   /*XXX KEY_REWIND? */
-       [ 0x00 ] = KEY_0,
-       [ 0x17 ] = KEY_DIGITS,  /*XXX*/
+       { 0x0a, KEY_AGAIN },    /*XXX KEY_REWIND? */
+       { 0x00, KEY_0 },
+       { 0x17, KEY_DIGITS },   /*XXX*/
 
        /*  0x14            0x10  *
         *  MENU            INFO  *
         *  OSD                   */
-       [ 0x14 ] = KEY_MENU,
-       [ 0x10 ] = KEY_INFO,
+       { 0x14, KEY_MENU },
+       { 0x10, KEY_INFO },
 
        /*          0x0b          *
         *           Up           *
@@ -1281,18 +1372,18 @@ IR_KEYTAB_TYPE ir_codes_manli[IR_KEYTAB_SIZE] = {
         *         0x015          *
         *         Down           *
         *                        */
-       [ 0x0b ] = KEY_UP,      /*XXX KEY_SCROLLUP? */
-       [ 0x18 ] = KEY_LEFT,    /*XXX KEY_BACK? */
-       [ 0x16 ] = KEY_OK,      /*XXX KEY_SELECT? KEY_ENTER? */
-       [ 0x0c ] = KEY_RIGHT,   /*XXX KEY_FORWARD? */
-       [ 0x15 ] = KEY_DOWN,    /*XXX KEY_SCROLLDOWN? */
+       { 0x0b, KEY_UP },
+       { 0x18, KEY_LEFT },
+       { 0x16, KEY_OK },       /*XXX KEY_SELECT? KEY_ENTER? */
+       { 0x0c, KEY_RIGHT },
+       { 0x15, KEY_DOWN },
 
        /*  0x11            0x0d  *
         *  TV/AV           MODE  *
         *  SOURCE         STEREO *
         *                        */
-       [ 0x11 ] = KEY_TV,      /*XXX*/
-       [ 0x0d ] = KEY_MODE,    /*XXX there's no KEY_STEREO */
+       { 0x11, KEY_TV },       /*XXX*/
+       { 0x0d, KEY_MODE },     /*XXX there's no KEY_STEREO     */
 
        /*  0x0f    0x1b    0x1a  *
         *  AUDIO   Vol+    Chan+ *
@@ -1301,891 +1392,967 @@ IR_KEYTAB_TYPE ir_codes_manli[IR_KEYTAB_SIZE] = {
         *  0x0e    0x1f    0x1e  *
         *  SLEEP   Vol-    Chan- *
         *                        */
-       [ 0x0f ] = KEY_AUDIO,
-       [ 0x1b ] = KEY_VOLUMEUP,
-       [ 0x1a ] = KEY_CHANNELUP,
-       [ 0x0e ] = KEY_SLEEP,   /*XXX maybe KEY_PAUSE */
-       [ 0x1f ] = KEY_VOLUMEDOWN,
-       [ 0x1e ] = KEY_CHANNELDOWN,
+       { 0x0f, KEY_AUDIO },
+       { 0x1b, KEY_VOLUMEUP },
+       { 0x1a, KEY_CHANNELUP },
+       { 0x0e, KEY_TIME },
+       { 0x1f, KEY_VOLUMEDOWN },
+       { 0x1e, KEY_CHANNELDOWN },
 
        /*         0x13     0x19  *
         *         MUTE   SNAPSHOT*
         *                        */
-       [ 0x13 ] = KEY_MUTE,
-       [ 0x19 ] = KEY_RECORD,  /*XXX*/
+       { 0x13, KEY_MUTE },
+       { 0x19, KEY_CAMERA },
 
-       // 0x1d unused ?
+       /* 0x1d unused ? */
 };
 
-EXPORT_SYMBOL_GPL(ir_codes_manli);
+struct ir_scancode_table ir_codes_manli_table = {
+       .scan = ir_codes_manli,
+       .size = ARRAY_SIZE(ir_codes_manli),
+};
+EXPORT_SYMBOL_GPL(ir_codes_manli_table);
 
 /* Mike Baikov <mike@baikov.com> */
-IR_KEYTAB_TYPE ir_codes_gotview7135[IR_KEYTAB_SIZE] = {
-
-       [ 0x11 ] = KEY_POWER,
-       [ 0x35 ] = KEY_TV,
-       [ 0x1b ] = KEY_0,
-       [ 0x29 ] = KEY_1,
-       [ 0x19 ] = KEY_2,
-       [ 0x39 ] = KEY_3,
-       [ 0x1f ] = KEY_4,
-       [ 0x2c ] = KEY_5,
-       [ 0x21 ] = KEY_6,
-       [ 0x24 ] = KEY_7,
-       [ 0x18 ] = KEY_8,
-       [ 0x2b ] = KEY_9,
-       [ 0x3b ] = KEY_AGAIN, /* LOOP */
-       [ 0x06 ] = KEY_AUDIO,
-       [ 0x31 ] = KEY_PRINT, /* PREVIEW */
-       [ 0x3e ] = KEY_VIDEO,
-       [ 0x10 ] = KEY_CHANNELUP,
-       [ 0x20 ] = KEY_CHANNELDOWN,
-       [ 0x0c ] = KEY_VOLUMEDOWN,
-       [ 0x28 ] = KEY_VOLUMEUP,
-       [ 0x08 ] = KEY_MUTE,
-       [ 0x26 ] = KEY_SEARCH, /*SCAN*/
-       [ 0x3f ] = KEY_SHUFFLE, /* SNAPSHOT */
-       [ 0x12 ] = KEY_RECORD,
-       [ 0x32 ] = KEY_STOP,
-       [ 0x3c ] = KEY_PLAY,
-       [ 0x1d ] = KEY_REWIND,
-       [ 0x2d ] = KEY_PAUSE,
-       [ 0x0d ] = KEY_FORWARD,
-       [ 0x05 ] = KEY_ZOOM,  /*FULL*/
-
-       [ 0x2a ] = KEY_F21, /* LIVE TIMESHIFT */
-       [ 0x0e ] = KEY_F22, /* MIN TIMESHIFT */
-       [ 0x1e ] = KEY_F23, /* TIMESHIFT */
-       [ 0x38 ] = KEY_F24, /* NORMAL TIMESHIFT */
-};
-
-EXPORT_SYMBOL_GPL(ir_codes_gotview7135);
-
-IR_KEYTAB_TYPE ir_codes_purpletv[IR_KEYTAB_SIZE] = {
-       [ 0x03 ] = KEY_POWER,
-       [ 0x6f ] = KEY_MUTE,
-       [ 0x10 ] = KEY_BACKSPACE,       /* Recall */
-
-       [ 0x11 ] = KEY_0,
-       [ 0x04 ] = KEY_1,
-       [ 0x05 ] = KEY_2,
-       [ 0x06 ] = KEY_3,
-       [ 0x08 ] = KEY_4,
-       [ 0x09 ] = KEY_5,
-       [ 0x0a ] = KEY_6,
-       [ 0x0c ] = KEY_7,
-       [ 0x0d ] = KEY_8,
-       [ 0x0e ] = KEY_9,
-       [ 0x12 ] = KEY_DOT,           /* 100+ */
-
-       [ 0x07 ] = KEY_VOLUMEUP,
-       [ 0x0b ] = KEY_VOLUMEDOWN,
-       [ 0x1a ] = KEY_KPPLUS,
-       [ 0x18 ] = KEY_KPMINUS,
-       [ 0x15 ] = KEY_UP,
-       [ 0x1d ] = KEY_DOWN,
-       [ 0x0f ] = 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 ? */
-
-};
-
-EXPORT_SYMBOL_GPL(ir_codes_purpletv);
+static struct ir_scancode ir_codes_gotview7135[] = {
+
+       { 0x11, KEY_POWER },
+       { 0x35, KEY_TV },
+       { 0x1b, KEY_0 },
+       { 0x29, KEY_1 },
+       { 0x19, KEY_2 },
+       { 0x39, KEY_3 },
+       { 0x1f, KEY_4 },
+       { 0x2c, KEY_5 },
+       { 0x21, KEY_6 },
+       { 0x24, KEY_7 },
+       { 0x18, KEY_8 },
+       { 0x2b, KEY_9 },
+       { 0x3b, KEY_AGAIN },    /* LOOP */
+       { 0x06, KEY_AUDIO },
+       { 0x31, KEY_PRINT },    /* PREVIEW */
+       { 0x3e, KEY_VIDEO },
+       { 0x10, KEY_CHANNELUP },
+       { 0x20, KEY_CHANNELDOWN },
+       { 0x0c, KEY_VOLUMEDOWN },
+       { 0x28, KEY_VOLUMEUP },
+       { 0x08, KEY_MUTE },
+       { 0x26, KEY_SEARCH },   /* SCAN */
+       { 0x3f, KEY_CAMERA },   /* SNAPSHOT */
+       { 0x12, KEY_RECORD },
+       { 0x32, KEY_STOP },
+       { 0x3c, KEY_PLAY },
+       { 0x1d, KEY_REWIND },
+       { 0x2d, KEY_PAUSE },
+       { 0x0d, KEY_FORWARD },
+       { 0x05, KEY_ZOOM },     /*FULL*/
+
+       { 0x2a, KEY_F21 },      /* LIVE TIMESHIFT */
+       { 0x0e, KEY_F22 },      /* MIN TIMESHIFT */
+       { 0x1e, KEY_TIME },     /* TIMESHIFT */
+       { 0x38, KEY_F24 },      /* NORMAL TIMESHIFT */
+};
+
+struct ir_scancode_table ir_codes_gotview7135_table = {
+       .scan = ir_codes_gotview7135,
+       .size = ARRAY_SIZE(ir_codes_gotview7135),
+};
+EXPORT_SYMBOL_GPL(ir_codes_gotview7135_table);
+
+static struct ir_scancode ir_codes_purpletv[] = {
+       { 0x03, KEY_POWER },
+       { 0x6f, KEY_MUTE },
+       { 0x10, KEY_BACKSPACE },        /* Recall */
+
+       { 0x11, KEY_0 },
+       { 0x04, KEY_1 },
+       { 0x05, KEY_2 },
+       { 0x06, KEY_3 },
+       { 0x08, KEY_4 },
+       { 0x09, KEY_5 },
+       { 0x0a, KEY_6 },
+       { 0x0c, KEY_7 },
+       { 0x0d, KEY_8 },
+       { 0x0e, KEY_9 },
+       { 0x12, KEY_DOT },      /* 100+ */
+
+       { 0x07, KEY_VOLUMEUP },
+       { 0x0b, KEY_VOLUMEDOWN },
+       { 0x1a, KEY_KPPLUS },
+       { 0x18, KEY_KPMINUS },
+       { 0x15, KEY_UP },
+       { 0x1d, KEY_DOWN },
+       { 0x0f, KEY_CHANNELUP },
+       { 0x13, KEY_CHANNELDOWN },
+       { 0x48, KEY_ZOOM },
+
+       { 0x1b, KEY_VIDEO },    /* Video source */
+       { 0x1f, KEY_CAMERA },   /* Snapshot */
+       { 0x49, KEY_LANGUAGE }, /* MTS Select */
+       { 0x19, KEY_SEARCH },   /* Auto Scan */
+
+       { 0x4b, KEY_RECORD },
+       { 0x46, KEY_PLAY },
+       { 0x45, KEY_PAUSE },    /* Pause */
+       { 0x44, KEY_STOP },
+       { 0x43, KEY_TIME },     /* Time Shift */
+       { 0x17, KEY_CHANNEL },  /* SURF CH */
+       { 0x40, KEY_FORWARD },  /* Forward ? */
+       { 0x42, KEY_REWIND },   /* Backward ? */
+
+};
+
+struct ir_scancode_table ir_codes_purpletv_table = {
+       .scan = ir_codes_purpletv,
+       .size = ARRAY_SIZE(ir_codes_purpletv),
+};
+EXPORT_SYMBOL_GPL(ir_codes_purpletv_table);
 
 /* Mapping for the 28 key remote control as seen at
    http://www.sednacomputer.com/photo/cardbus-tv.jpg
    Pavel Mihaylov <bin@bash.info>
    Also for the remote bundled with Kozumi KTV-01C card */
-IR_KEYTAB_TYPE ir_codes_pctv_sedna[IR_KEYTAB_SIZE] = {
-       [ 0x00 ] = KEY_0,
-       [ 0x01 ] = KEY_1,
-       [ 0x02 ] = KEY_2,
-       [ 0x03 ] = KEY_3,
-       [ 0x04 ] = KEY_4,
-       [ 0x05 ] = KEY_5,
-       [ 0x06 ] = KEY_6,
-       [ 0x07 ] = KEY_7,
-       [ 0x08 ] = KEY_8,
-       [ 0x09 ] = KEY_9,
-
-       [ 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,
+static struct ir_scancode ir_codes_pctv_sedna[] = {
+       { 0x00, KEY_0 },
+       { 0x01, KEY_1 },
+       { 0x02, KEY_2 },
+       { 0x03, KEY_3 },
+       { 0x04, KEY_4 },
+       { 0x05, KEY_5 },
+       { 0x06, KEY_6 },
+       { 0x07, KEY_7 },
+       { 0x08, KEY_8 },
+       { 0x09, KEY_9 },
+
+       { 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_CAMERA },   /* Snapshot */
+       { 0x1a, KEY_NEXTSONG },
+       { 0x1b, KEY_TIME },     /* Time Shift */
+       { 0x1c, KEY_RADIO },    /* FM Radio */
+       { 0x1d, KEY_RECORD },
+       { 0x1e, KEY_PAUSE },
        /* additional codes for Kozumi's remote */
-       [0x14] = KEY_INFO,        /* OSD */
-       [0x16] = KEY_OK,          /* OK */
-       [0x17] = KEY_DIGITS,      /* Plus */
-       [0x1f] = KEY_PLAY,        /* Play */
+       { 0x14, KEY_INFO },     /* OSD */
+       { 0x16, KEY_OK },       /* OK */
+       { 0x17, KEY_DIGITS },   /* Plus */
+       { 0x1f, KEY_PLAY },     /* Play */
 };
 
-EXPORT_SYMBOL_GPL(ir_codes_pctv_sedna);
+struct ir_scancode_table ir_codes_pctv_sedna_table = {
+       .scan = ir_codes_pctv_sedna,
+       .size = ARRAY_SIZE(ir_codes_pctv_sedna),
+};
+EXPORT_SYMBOL_GPL(ir_codes_pctv_sedna_table);
 
 /* Mark Phalan <phalanm@o2.ie> */
-IR_KEYTAB_TYPE ir_codes_pv951[IR_KEYTAB_SIZE] = {
-       [ 0x00 ] = KEY_0,
-       [ 0x01 ] = KEY_1,
-       [ 0x02 ] = KEY_2,
-       [ 0x03 ] = KEY_3,
-       [ 0x04 ] = KEY_4,
-       [ 0x05 ] = KEY_5,
-       [ 0x06 ] = KEY_6,
-       [ 0x07 ] = KEY_7,
-       [ 0x08 ] = KEY_8,
-       [ 0x09 ] = KEY_9,
-
-       [ 0x12 ] = KEY_POWER,
-       [ 0x10 ] = KEY_MUTE,
-       [ 0x1f ] = KEY_VOLUMEDOWN,
-       [ 0x1b ] = KEY_VOLUMEUP,
-       [ 0x1a ] = KEY_CHANNELUP,
-       [ 0x1e ] = KEY_CHANNELDOWN,
-       [ 0x0e ] = KEY_PAGEUP,
-       [ 0x1d ] = KEY_PAGEDOWN,
-       [ 0x13 ] = KEY_SOUND,
-
-       [ 0x18 ] = KEY_KPPLUSMINUS,     /* CH +/- */
-       [ 0x16 ] = KEY_SUBTITLE,                /* CC */
-       [ 0x0d ] = KEY_TEXT,            /* TTX */
-       [ 0x0b ] = KEY_TV,              /* AIR/CBL */
-       [ 0x11 ] = KEY_PC,              /* PC/TV */
-       [ 0x17 ] = KEY_OK,              /* CH RTN */
-       [ 0x19 ] = KEY_MODE,            /* FUNC */
-       [ 0x0c ] = KEY_SEARCH,          /* AUTOSCAN */
+static struct ir_scancode ir_codes_pv951[] = {
+       { 0x00, KEY_0 },
+       { 0x01, KEY_1 },
+       { 0x02, KEY_2 },
+       { 0x03, KEY_3 },
+       { 0x04, KEY_4 },
+       { 0x05, KEY_5 },
+       { 0x06, KEY_6 },
+       { 0x07, KEY_7 },
+       { 0x08, KEY_8 },
+       { 0x09, KEY_9 },
+
+       { 0x12, KEY_POWER },
+       { 0x10, KEY_MUTE },
+       { 0x1f, KEY_VOLUMEDOWN },
+       { 0x1b, KEY_VOLUMEUP },
+       { 0x1a, KEY_CHANNELUP },
+       { 0x1e, KEY_CHANNELDOWN },
+       { 0x0e, KEY_PAGEUP },
+       { 0x1d, KEY_PAGEDOWN },
+       { 0x13, KEY_SOUND },
+
+       { 0x18, KEY_KPPLUSMINUS },      /* CH +/- */
+       { 0x16, KEY_SUBTITLE },         /* CC */
+       { 0x0d, KEY_TEXT },             /* TTX */
+       { 0x0b, KEY_TV },               /* AIR/CBL */
+       { 0x11, KEY_PC },               /* PC/TV */
+       { 0x17, KEY_OK },               /* CH RTN */
+       { 0x19, KEY_MODE },             /* FUNC */
+       { 0x0c, KEY_SEARCH },           /* AUTOSCAN */
 
        /* Not sure what to do with these ones! */
-       [ 0x0f ] = KEY_SELECT,          /* SOURCE */
-       [ 0x0a ] = KEY_KPPLUS,          /* +100 */
-       [ 0x14 ] = KEY_EQUAL,           /* SYNC */
-       [ 0x1c ] = KEY_MEDIA,             /* PC/TV */
+       { 0x0f, KEY_SELECT },           /* SOURCE */
+       { 0x0a, KEY_KPPLUS },           /* +100 */
+       { 0x14, KEY_EQUAL },            /* SYNC */
+       { 0x1c, KEY_MEDIA },            /* PC/TV */
 };
 
-EXPORT_SYMBOL_GPL(ir_codes_pv951);
+struct ir_scancode_table ir_codes_pv951_table = {
+       .scan = ir_codes_pv951,
+       .size = ARRAY_SIZE(ir_codes_pv951),
+};
+EXPORT_SYMBOL_GPL(ir_codes_pv951_table);
 
 /* generic RC5 keytable                                          */
 /* see http://users.pandora.be/nenya/electronics/rc5/codes00.htm */
 /* used by old (black) Hauppauge remotes                         */
-IR_KEYTAB_TYPE ir_codes_rc5_tv[IR_KEYTAB_SIZE] = {
+static struct ir_scancode ir_codes_rc5_tv[] = {
        /* Keys 0 to 9 */
-       [ 0x00 ] = KEY_0,
-       [ 0x01 ] = KEY_1,
-       [ 0x02 ] = KEY_2,
-       [ 0x03 ] = KEY_3,
-       [ 0x04 ] = KEY_4,
-       [ 0x05 ] = KEY_5,
-       [ 0x06 ] = KEY_6,
-       [ 0x07 ] = KEY_7,
-       [ 0x08 ] = KEY_8,
-       [ 0x09 ] = KEY_9,
-
-       [ 0x0b ] = KEY_CHANNEL,         /* channel / program (japan: 11) */
-       [ 0x0c ] = KEY_POWER,           /* standby */
-       [ 0x0d ] = KEY_MUTE,            /* mute / demute */
-       [ 0x0f ] = KEY_TV,              /* display */
-       [ 0x10 ] = KEY_VOLUMEUP,
-       [ 0x11 ] = KEY_VOLUMEDOWN,
-       [ 0x12 ] = KEY_BRIGHTNESSUP,
-       [ 0x13 ] = KEY_BRIGHTNESSDOWN,
-       [ 0x1e ] = KEY_SEARCH,          /* search + */
-       [ 0x20 ] = KEY_CHANNELUP,       /* channel / program + */
-       [ 0x21 ] = KEY_CHANNELDOWN,     /* channel / program - */
-       [ 0x22 ] = KEY_CHANNEL,         /* alt / channel */
-       [ 0x23 ] = KEY_LANGUAGE,        /* 1st / 2nd language */
-       [ 0x26 ] = KEY_SLEEP,           /* sleeptimer */
-       [ 0x2e ] = KEY_MENU,            /* 2nd controls (USA: menu) */
-       [ 0x30 ] = KEY_PAUSE,
-       [ 0x32 ] = KEY_REWIND,
-       [ 0x33 ] = KEY_GOTO,
-       [ 0x35 ] = KEY_PLAY,
-       [ 0x36 ] = KEY_STOP,
-       [ 0x37 ] = KEY_RECORD,          /* recording */
-       [ 0x3c ] = KEY_TEXT,            /* teletext submode (Japan: 12) */
-       [ 0x3d ] = KEY_SUSPEND,         /* system standby */
-
-};
-
-EXPORT_SYMBOL_GPL(ir_codes_rc5_tv);
+       { 0x00, KEY_0 },
+       { 0x01, KEY_1 },
+       { 0x02, KEY_2 },
+       { 0x03, KEY_3 },
+       { 0x04, KEY_4 },
+       { 0x05, KEY_5 },
+       { 0x06, KEY_6 },
+       { 0x07, KEY_7 },
+       { 0x08, KEY_8 },
+       { 0x09, KEY_9 },
+
+       { 0x0b, KEY_CHANNEL },          /* channel / program (japan: 11) */
+       { 0x0c, KEY_POWER },            /* standby */
+       { 0x0d, KEY_MUTE },             /* mute / demute */
+       { 0x0f, KEY_TV },               /* display */
+       { 0x10, KEY_VOLUMEUP },
+       { 0x11, KEY_VOLUMEDOWN },
+       { 0x12, KEY_BRIGHTNESSUP },
+       { 0x13, KEY_BRIGHTNESSDOWN },
+       { 0x1e, KEY_SEARCH },           /* search + */
+       { 0x20, KEY_CHANNELUP },        /* channel / program + */
+       { 0x21, KEY_CHANNELDOWN },      /* channel / program - */
+       { 0x22, KEY_CHANNEL },          /* alt / channel */
+       { 0x23, KEY_LANGUAGE },         /* 1st / 2nd language */
+       { 0x26, KEY_SLEEP },            /* sleeptimer */
+       { 0x2e, KEY_MENU },             /* 2nd controls (USA: menu) */
+       { 0x30, KEY_PAUSE },
+       { 0x32, KEY_REWIND },
+       { 0x33, KEY_GOTO },
+       { 0x35, KEY_PLAY },
+       { 0x36, KEY_STOP },
+       { 0x37, KEY_RECORD },           /* recording */
+       { 0x3c, KEY_TEXT },             /* teletext submode (Japan: 12) */
+       { 0x3d, KEY_SUSPEND },          /* system standby */
+
+};
+
+struct ir_scancode_table ir_codes_rc5_tv_table = {
+       .scan = ir_codes_rc5_tv,
+       .size = ARRAY_SIZE(ir_codes_rc5_tv),
+};
+EXPORT_SYMBOL_GPL(ir_codes_rc5_tv_table);
 
 /* Table for Leadtek Winfast Remote Controls - used by both bttv and cx88 */
-IR_KEYTAB_TYPE ir_codes_winfast[IR_KEYTAB_SIZE] = {
+static struct ir_scancode ir_codes_winfast[] = {
        /* Keys 0 to 9 */
-       [ 0x12 ] = KEY_0,
-       [ 0x05 ] = KEY_1,
-       [ 0x06 ] = KEY_2,
-       [ 0x07 ] = KEY_3,
-       [ 0x09 ] = KEY_4,
-       [ 0x0a ] = KEY_5,
-       [ 0x0b ] = KEY_6,
-       [ 0x0d ] = KEY_7,
-       [ 0x0e ] = KEY_8,
-       [ 0x0f ] = KEY_9,
-
-       [ 0x00 ] = KEY_POWER,
-       [ 0x1b ] = KEY_AUDIO,           /* Audio Source */
-       [ 0x02 ] = KEY_TUNER,           /* TV/FM, not on Y0400052 */
-       [ 0x1e ] = KEY_VIDEO,           /* Video Source */
-       [ 0x16 ] = KEY_INFO,            /* Display information */
-       [ 0x04 ] = KEY_VOLUMEUP,
-       [ 0x08 ] = KEY_VOLUMEDOWN,
-       [ 0x0c ] = KEY_CHANNELUP,
-       [ 0x10 ] = KEY_CHANNELDOWN,
-       [ 0x03 ] = KEY_ZOOM,            /* fullscreen */
-       [ 0x1f ] = KEY_TEXT,            /* closed caption/teletext */
-       [ 0x20 ] = KEY_SLEEP,
-       [ 0x29 ] = KEY_CLEAR,           /* boss key */
-       [ 0x14 ] = KEY_MUTE,
-       [ 0x2b ] = KEY_RED,
-       [ 0x2c ] = KEY_GREEN,
-       [ 0x2d ] = KEY_YELLOW,
-       [ 0x2e ] = KEY_BLUE,
-       [ 0x18 ] = KEY_KPPLUS,          /* fine tune + , not on Y040052 */
-       [ 0x19 ] = KEY_KPMINUS,         /* fine tune - , not on Y040052 */
-       [ 0x2a ] = KEY_MEDIA,           /* PIP (Picture in picture */
-       [ 0x21 ] = KEY_DOT,
-       [ 0x13 ] = KEY_ENTER,
-       [ 0x11 ] = KEY_LAST,            /* Recall (last channel */
-       [ 0x22 ] = KEY_PREVIOUS,
-       [ 0x23 ] = KEY_PLAYPAUSE,
-       [ 0x24 ] = KEY_NEXT,
-       [ 0x25 ] = KEY_ARCHIVE,       /* Time Shifting */
-       [ 0x26 ] = KEY_STOP,
-       [ 0x27 ] = KEY_RECORD,
-       [ 0x28 ] = KEY_SAVE,          /* Screenshot */
-       [ 0x2f ] = KEY_MENU,
-       [ 0x30 ] = KEY_CANCEL,
-       [ 0x31 ] = KEY_CHANNEL,       /* Channel Surf */
-       [ 0x32 ] = KEY_SUBTITLE,
-       [ 0x33 ] = KEY_LANGUAGE,
-       [ 0x34 ] = KEY_REWIND,
-       [ 0x35 ] = KEY_FASTFORWARD,
-       [ 0x36 ] = KEY_TV,
-       [ 0x37 ] = KEY_RADIO,         /* FM */
-       [ 0x38 ] = KEY_DVD,
-
-       [ 0x3e ] = KEY_F21,           /* MCE +VOL, on Y04G0033 */
-       [ 0x3a ] = KEY_F22,           /* MCE -VOL, on Y04G0033 */
-       [ 0x3b ] = KEY_F23,           /* MCE +CH,  on Y04G0033 */
-       [ 0x3f ] = KEY_F24            /* MCE -CH,  on Y04G0033 */
-};
-
-EXPORT_SYMBOL_GPL(ir_codes_winfast);
-
-IR_KEYTAB_TYPE ir_codes_pinnacle_color[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_0,
-       [ 0x6a ] = KEY_1,
-       [ 0x6b ] = KEY_2,
-       [ 0x6c ] = KEY_3,
-       [ 0x6d ] = KEY_4,
-       [ 0x6e ] = KEY_5,
-       [ 0x6f ] = KEY_6,
-       [ 0x70 ] = KEY_7,
-       [ 0x71 ] = KEY_8,
-       [ 0x72 ] = KEY_9,
-
-       [ 0x74 ] = KEY_CHANNEL,
-       [ 0x0a ] = KEY_BACKSPACE,
-};
-
-EXPORT_SYMBOL_GPL(ir_codes_pinnacle_color);
+       { 0x12, KEY_0 },
+       { 0x05, KEY_1 },
+       { 0x06, KEY_2 },
+       { 0x07, KEY_3 },
+       { 0x09, KEY_4 },
+       { 0x0a, KEY_5 },
+       { 0x0b, KEY_6 },
+       { 0x0d, KEY_7 },
+       { 0x0e, KEY_8 },
+       { 0x0f, KEY_9 },
+
+       { 0x00, KEY_POWER },
+       { 0x1b, KEY_AUDIO },            /* Audio Source */
+       { 0x02, KEY_TUNER },            /* TV/FM, not on Y0400052 */
+       { 0x1e, KEY_VIDEO },            /* Video Source */
+       { 0x16, KEY_INFO },             /* Display information */
+       { 0x04, KEY_VOLUMEUP },
+       { 0x08, KEY_VOLUMEDOWN },
+       { 0x0c, KEY_CHANNELUP },
+       { 0x10, KEY_CHANNELDOWN },
+       { 0x03, KEY_ZOOM },             /* fullscreen */
+       { 0x1f, KEY_TEXT },             /* closed caption/teletext */
+       { 0x20, KEY_SLEEP },
+       { 0x29, KEY_CLEAR },            /* boss key */
+       { 0x14, KEY_MUTE },
+       { 0x2b, KEY_RED },
+       { 0x2c, KEY_GREEN },
+       { 0x2d, KEY_YELLOW },
+       { 0x2e, KEY_BLUE },
+       { 0x18, KEY_KPPLUS },           /* fine tune + , not on Y040052 */
+       { 0x19, KEY_KPMINUS },          /* fine tune - , not on Y040052 */
+       { 0x2a, KEY_MEDIA },            /* PIP (Picture in picture */
+       { 0x21, KEY_DOT },
+       { 0x13, KEY_ENTER },
+       { 0x11, KEY_LAST },             /* Recall (last channel */
+       { 0x22, KEY_PREVIOUS },
+       { 0x23, KEY_PLAYPAUSE },
+       { 0x24, KEY_NEXT },
+       { 0x25, KEY_TIME },             /* Time Shifting */
+       { 0x26, KEY_STOP },
+       { 0x27, KEY_RECORD },
+       { 0x28, KEY_SAVE },             /* Screenshot */
+       { 0x2f, KEY_MENU },
+       { 0x30, KEY_CANCEL },
+       { 0x31, KEY_CHANNEL },          /* Channel Surf */
+       { 0x32, KEY_SUBTITLE },
+       { 0x33, KEY_LANGUAGE },
+       { 0x34, KEY_REWIND },
+       { 0x35, KEY_FASTFORWARD },
+       { 0x36, KEY_TV },
+       { 0x37, KEY_RADIO },            /* FM */
+       { 0x38, KEY_DVD },
+
+       { 0x3e, KEY_F21 },              /* MCE +VOL, on Y04G0033 */
+       { 0x3a, KEY_F22 },              /* MCE -VOL, on Y04G0033 */
+       { 0x3b, KEY_F23 },              /* MCE +CH,  on Y04G0033 */
+       { 0x3f, KEY_F24 }               /* MCE -CH,  on Y04G0033 */
+};
+
+struct ir_scancode_table ir_codes_winfast_table = {
+       .scan = ir_codes_winfast,
+       .size = ARRAY_SIZE(ir_codes_winfast),
+};
+EXPORT_SYMBOL_GPL(ir_codes_winfast_table);
+
+static struct ir_scancode ir_codes_pinnacle_color[] = {
+       { 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_0 },
+       { 0x6a, KEY_1 },
+       { 0x6b, KEY_2 },
+       { 0x6c, KEY_3 },
+       { 0x6d, KEY_4 },
+       { 0x6e, KEY_5 },
+       { 0x6f, KEY_6 },
+       { 0x70, KEY_7 },
+       { 0x71, KEY_8 },
+       { 0x72, KEY_9 },
+
+       { 0x74, KEY_CHANNEL },
+       { 0x0a, KEY_BACKSPACE },
+};
+
+struct ir_scancode_table ir_codes_pinnacle_color_table = {
+       .scan = ir_codes_pinnacle_color,
+       .size = ARRAY_SIZE(ir_codes_pinnacle_color),
+};
+EXPORT_SYMBOL_GPL(ir_codes_pinnacle_color_table);
 
 /* Hauppauge: the newer, gray remotes (seems there are multiple
  * slightly different versions), shipped with cx88+ivtv cards.
  * almost rc5 coding, but some non-standard keys */
-IR_KEYTAB_TYPE ir_codes_hauppauge_new[IR_KEYTAB_SIZE] = {
+static struct ir_scancode ir_codes_hauppauge_new[] = {
        /* Keys 0 to 9 */
-       [ 0x00 ] = KEY_0,
-       [ 0x01 ] = KEY_1,
-       [ 0x02 ] = KEY_2,
-       [ 0x03 ] = KEY_3,
-       [ 0x04 ] = KEY_4,
-       [ 0x05 ] = KEY_5,
-       [ 0x06 ] = KEY_6,
-       [ 0x07 ] = KEY_7,
-       [ 0x08 ] = KEY_8,
-       [ 0x09 ] = KEY_9,
-
-       [ 0x0a ] = KEY_TEXT,            /* keypad asterisk as well */
-       [ 0x0b ] = KEY_RED,             /* red button */
-       [ 0x0c ] = KEY_RADIO,
-       [ 0x0d ] = KEY_MENU,
-       [ 0x0e ] = KEY_SUBTITLE,        /* also the # key */
-       [ 0x0f ] = KEY_MUTE,
-       [ 0x10 ] = KEY_VOLUMEUP,
-       [ 0x11 ] = KEY_VOLUMEDOWN,
-       [ 0x12 ] = KEY_PREVIOUS,        /* previous channel */
-       [ 0x14 ] = KEY_UP,
-       [ 0x15 ] = KEY_DOWN,
-       [ 0x16 ] = KEY_LEFT,
-       [ 0x17 ] = KEY_RIGHT,
-       [ 0x18 ] = KEY_VIDEO,           /* Videos */
-       [ 0x19 ] = KEY_AUDIO,           /* Music */
+       { 0x00, KEY_0 },
+       { 0x01, KEY_1 },
+       { 0x02, KEY_2 },
+       { 0x03, KEY_3 },
+       { 0x04, KEY_4 },
+       { 0x05, KEY_5 },
+       { 0x06, KEY_6 },
+       { 0x07, KEY_7 },
+       { 0x08, KEY_8 },
+       { 0x09, KEY_9 },
+
+       { 0x0a, KEY_TEXT },             /* keypad asterisk as well */
+       { 0x0b, KEY_RED },              /* red button */
+       { 0x0c, KEY_RADIO },
+       { 0x0d, KEY_MENU },
+       { 0x0e, KEY_SUBTITLE },         /* also the # key */
+       { 0x0f, KEY_MUTE },
+       { 0x10, KEY_VOLUMEUP },
+       { 0x11, KEY_VOLUMEDOWN },
+       { 0x12, KEY_PREVIOUS },         /* previous channel */
+       { 0x14, KEY_UP },
+       { 0x15, KEY_DOWN },
+       { 0x16, KEY_LEFT },
+       { 0x17, KEY_RIGHT },
+       { 0x18, KEY_VIDEO },            /* Videos */
+       { 0x19, KEY_AUDIO },            /* Music */
        /* 0x1a: Pictures - presume this means
           "Multimedia Home Platform" -
           no "PICTURES" key in input.h
         */
-       [ 0x1a ] = KEY_MHP,
-
-       [ 0x1b ] = KEY_EPG,             /* Guide */
-       [ 0x1c ] = KEY_TV,
-       [ 0x1e ] = KEY_NEXTSONG,        /* skip >| */
-       [ 0x1f ] = KEY_EXIT,            /* back/exit */
-       [ 0x20 ] = KEY_CHANNELUP,       /* channel / program + */
-       [ 0x21 ] = KEY_CHANNELDOWN,     /* channel / program - */
-       [ 0x22 ] = KEY_CHANNEL,         /* source (old black remote) */
-       [ 0x24 ] = KEY_PREVIOUSSONG,    /* replay |< */
-       [ 0x25 ] = KEY_ENTER,           /* OK */
-       [ 0x26 ] = KEY_SLEEP,           /* minimize (old black remote) */
-       [ 0x29 ] = KEY_BLUE,            /* blue key */
-       [ 0x2e ] = KEY_GREEN,           /* green button */
-       [ 0x30 ] = KEY_PAUSE,           /* pause */
-       [ 0x32 ] = KEY_REWIND,          /* backward << */
-       [ 0x34 ] = KEY_FASTFORWARD,     /* forward >> */
-       [ 0x35 ] = KEY_PLAY,
-       [ 0x36 ] = KEY_STOP,
-       [ 0x37 ] = KEY_RECORD,          /* recording */
-       [ 0x38 ] = KEY_YELLOW,          /* yellow key */
-       [ 0x3b ] = KEY_SELECT,          /* top right button */
-       [ 0x3c ] = KEY_ZOOM,            /* full */
-       [ 0x3d ] = KEY_POWER,           /* system power (green button) */
-};
-
-EXPORT_SYMBOL_GPL(ir_codes_hauppauge_new);
-
-IR_KEYTAB_TYPE ir_codes_npgtech[IR_KEYTAB_SIZE] = {
-       [ 0x1d ] = KEY_SWITCHVIDEOMODE, /* switch inputs */
-       [ 0x2a ] = KEY_FRONT,
-
-       [ 0x3e ] = KEY_1,
-       [ 0x02 ] = KEY_2,
-       [ 0x06 ] = KEY_3,
-       [ 0x0a ] = KEY_4,
-       [ 0x0e ] = KEY_5,
-       [ 0x12 ] = KEY_6,
-       [ 0x16 ] = KEY_7,
-       [ 0x1a ] = KEY_8,
-       [ 0x1e ] = KEY_9,
-       [ 0x3a ] = KEY_0,
-       [ 0x22 ] = KEY_NUMLOCK,         /* -/-- */
-       [ 0x20 ] = KEY_REFRESH,
-
-       [ 0x03 ] = KEY_BRIGHTNESSDOWN,
-       [ 0x28 ] = KEY_AUDIO,
-       [ 0x3c ] = KEY_UP,
-       [ 0x3f ] = KEY_LEFT,
-       [ 0x2e ] = KEY_MUTE,
-       [ 0x3b ] = KEY_RIGHT,
-       [ 0x00 ] = KEY_DOWN,
-       [ 0x07 ] = KEY_BRIGHTNESSUP,
-       [ 0x2c ] = KEY_TEXT,
-
-       [ 0x37 ] = KEY_RECORD,
-       [ 0x17 ] = KEY_PLAY,
-       [ 0x13 ] = KEY_PAUSE,
-       [ 0x26 ] = KEY_STOP,
-       [ 0x18 ] = KEY_FASTFORWARD,
-       [ 0x14 ] = KEY_REWIND,
-       [ 0x33 ] = KEY_ZOOM,
-       [ 0x32 ] = KEY_KEYBOARD,
-       [ 0x30 ] = KEY_GOTO,            /* Pointing arrow */
-       [ 0x36 ] = KEY_MACRO,           /* Maximize/Minimize (yellow) */
-       [ 0x0b ] = KEY_RADIO,
-       [ 0x10 ] = KEY_POWER,
-
-};
-
-EXPORT_SYMBOL_GPL(ir_codes_npgtech);
+       { 0x1a, KEY_MHP },
+
+       { 0x1b, KEY_EPG },              /* Guide */
+       { 0x1c, KEY_TV },
+       { 0x1e, KEY_NEXTSONG },         /* skip >| */
+       { 0x1f, KEY_EXIT },             /* back/exit */
+       { 0x20, KEY_CHANNELUP },        /* channel / program + */
+       { 0x21, KEY_CHANNELDOWN },      /* channel / program - */
+       { 0x22, KEY_CHANNEL },          /* source (old black remote) */
+       { 0x24, KEY_PREVIOUSSONG },     /* replay |< */
+       { 0x25, KEY_ENTER },            /* OK */
+       { 0x26, KEY_SLEEP },            /* minimize (old black remote) */
+       { 0x29, KEY_BLUE },             /* blue key */
+       { 0x2e, KEY_GREEN },            /* green button */
+       { 0x30, KEY_PAUSE },            /* pause */
+       { 0x32, KEY_REWIND },           /* backward << */
+       { 0x34, KEY_FASTFORWARD },      /* forward >> */
+       { 0x35, KEY_PLAY },
+       { 0x36, KEY_STOP },
+       { 0x37, KEY_RECORD },           /* recording */
+       { 0x38, KEY_YELLOW },           /* yellow key */
+       { 0x3b, KEY_SELECT },           /* top right button */
+       { 0x3c, KEY_ZOOM },             /* full */
+       { 0x3d, KEY_POWER },            /* system power (green button) */
+};
+
+struct ir_scancode_table ir_codes_hauppauge_new_table = {
+       .scan = ir_codes_hauppauge_new,
+       .size = ARRAY_SIZE(ir_codes_hauppauge_new),
+};
+EXPORT_SYMBOL_GPL(ir_codes_hauppauge_new_table);
+
+static struct ir_scancode ir_codes_npgtech[] = {
+       { 0x1d, KEY_SWITCHVIDEOMODE },  /* switch inputs */
+       { 0x2a, KEY_FRONT },
+
+       { 0x3e, KEY_1 },
+       { 0x02, KEY_2 },
+       { 0x06, KEY_3 },
+       { 0x0a, KEY_4 },
+       { 0x0e, KEY_5 },
+       { 0x12, KEY_6 },
+       { 0x16, KEY_7 },
+       { 0x1a, KEY_8 },
+       { 0x1e, KEY_9 },
+       { 0x3a, KEY_0 },
+       { 0x22, KEY_NUMLOCK },          /* -/-- */
+       { 0x20, KEY_REFRESH },
+
+       { 0x03, KEY_BRIGHTNESSDOWN },
+       { 0x28, KEY_AUDIO },
+       { 0x3c, KEY_CHANNELUP },
+       { 0x3f, KEY_VOLUMEDOWN },
+       { 0x2e, KEY_MUTE },
+       { 0x3b, KEY_VOLUMEUP },
+       { 0x00, KEY_CHANNELDOWN },
+       { 0x07, KEY_BRIGHTNESSUP },
+       { 0x2c, KEY_TEXT },
+
+       { 0x37, KEY_RECORD },
+       { 0x17, KEY_PLAY },
+       { 0x13, KEY_PAUSE },
+       { 0x26, KEY_STOP },
+       { 0x18, KEY_FASTFORWARD },
+       { 0x14, KEY_REWIND },
+       { 0x33, KEY_ZOOM },
+       { 0x32, KEY_KEYBOARD },
+       { 0x30, KEY_GOTO },             /* Pointing arrow */
+       { 0x36, KEY_MACRO },            /* Maximize/Minimize (yellow) */
+       { 0x0b, KEY_RADIO },
+       { 0x10, KEY_POWER },
+
+};
+
+struct ir_scancode_table ir_codes_npgtech_table = {
+       .scan = ir_codes_npgtech,
+       .size = ARRAY_SIZE(ir_codes_npgtech),
+};
+EXPORT_SYMBOL_GPL(ir_codes_npgtech_table);
 
 /* Norwood Micro (non-Pro) TV Tuner
    By Peter Naulls <peter@chocky.org>
    Key comments are the functions given in the manual */
-IR_KEYTAB_TYPE ir_codes_norwood[IR_KEYTAB_SIZE] = {
+static struct ir_scancode ir_codes_norwood[] = {
        /* Keys 0 to 9 */
-       [ 0x20 ] = KEY_0,
-       [ 0x21 ] = KEY_1,
-       [ 0x22 ] = KEY_2,
-       [ 0x23 ] = KEY_3,
-       [ 0x24 ] = KEY_4,
-       [ 0x25 ] = KEY_5,
-       [ 0x26 ] = KEY_6,
-       [ 0x27 ] = KEY_7,
-       [ 0x28 ] = KEY_8,
-       [ 0x29 ] = KEY_9,
-
-       [ 0x78 ] = KEY_TUNER,             /* Video Source        */
-       [ 0x2c ] = KEY_EXIT,              /* Open/Close software */
-       [ 0x2a ] = KEY_SELECT,            /* 2 Digit Select      */
-       [ 0x69 ] = KEY_AGAIN,             /* Recall              */
-
-       [ 0x32 ] = KEY_BRIGHTNESSUP,      /* Brightness increase */
-       [ 0x33 ] = KEY_BRIGHTNESSDOWN,    /* Brightness decrease */
-       [ 0x6b ] = KEY_KPPLUS,            /* (not named >>>>>)   */
-       [ 0x6c ] = KEY_KPMINUS,           /* (not named <<<<<)   */
-
-       [ 0x2d ] = KEY_MUTE,              /* Mute                */
-       [ 0x30 ] = KEY_VOLUMEUP,          /* Volume up           */
-       [ 0x31 ] = KEY_VOLUMEDOWN,        /* Volume down         */
-       [ 0x60 ] = KEY_CHANNELUP,         /* Channel up          */
-       [ 0x61 ] = KEY_CHANNELDOWN,       /* Channel down        */
-
-       [ 0x3f ] = KEY_RECORD,            /* Record              */
-       [ 0x37 ] = KEY_PLAY,              /* Play                */
-       [ 0x36 ] = KEY_PAUSE,             /* Pause               */
-       [ 0x2b ] = KEY_STOP,              /* Stop                */
-       [ 0x67 ] = KEY_FASTFORWARD,       /* Foward              */
-       [ 0x66 ] = KEY_REWIND,            /* Rewind              */
-       [ 0x3e ] = KEY_SEARCH,            /* Auto Scan           */
-       [ 0x2e ] = KEY_CAMERA,            /* Capture Video       */
-       [ 0x6d ] = KEY_MENU,              /* Show/Hide Control   */
-       [ 0x2f ] = KEY_ZOOM,              /* Full Screen         */
-       [ 0x34 ] = KEY_RADIO,             /* FM                  */
-       [ 0x65 ] = KEY_POWER,             /* Computer power      */
-};
-
-EXPORT_SYMBOL_GPL(ir_codes_norwood);
+       { 0x20, KEY_0 },
+       { 0x21, KEY_1 },
+       { 0x22, KEY_2 },
+       { 0x23, KEY_3 },
+       { 0x24, KEY_4 },
+       { 0x25, KEY_5 },
+       { 0x26, KEY_6 },
+       { 0x27, KEY_7 },
+       { 0x28, KEY_8 },
+       { 0x29, KEY_9 },
+
+       { 0x78, KEY_TUNER },            /* Video Source        */
+       { 0x2c, KEY_EXIT },             /* Open/Close software */
+       { 0x2a, KEY_SELECT },           /* 2 Digit Select      */
+       { 0x69, KEY_AGAIN },            /* Recall              */
+
+       { 0x32, KEY_BRIGHTNESSUP },     /* Brightness increase */
+       { 0x33, KEY_BRIGHTNESSDOWN },   /* Brightness decrease */
+       { 0x6b, KEY_KPPLUS },           /* (not named >>>>>)   */
+       { 0x6c, KEY_KPMINUS },          /* (not named <<<<<)   */
+
+       { 0x2d, KEY_MUTE },             /* Mute                */
+       { 0x30, KEY_VOLUMEUP },         /* Volume up           */
+       { 0x31, KEY_VOLUMEDOWN },       /* Volume down         */
+       { 0x60, KEY_CHANNELUP },        /* Channel up          */
+       { 0x61, KEY_CHANNELDOWN },      /* Channel down        */
+
+       { 0x3f, KEY_RECORD },           /* Record              */
+       { 0x37, KEY_PLAY },             /* Play                */
+       { 0x36, KEY_PAUSE },            /* Pause               */
+       { 0x2b, KEY_STOP },             /* Stop                */
+       { 0x67, KEY_FASTFORWARD },      /* Foward              */
+       { 0x66, KEY_REWIND },           /* Rewind              */
+       { 0x3e, KEY_SEARCH },           /* Auto Scan           */
+       { 0x2e, KEY_CAMERA },           /* Capture Video       */
+       { 0x6d, KEY_MENU },             /* Show/Hide Control   */
+       { 0x2f, KEY_ZOOM },             /* Full Screen         */
+       { 0x34, KEY_RADIO },            /* FM                  */
+       { 0x65, KEY_POWER },            /* Computer power      */
+};
+
+struct ir_scancode_table ir_codes_norwood_table = {
+       .scan = ir_codes_norwood,
+       .size = ARRAY_SIZE(ir_codes_norwood),
+};
+EXPORT_SYMBOL_GPL(ir_codes_norwood_table);
 
 /* From reading the following remotes:
  * Zenith Universal 7 / TV Mode 807 / VCR Mode 837
  * Hauppauge (from NOVA-CI-s box product)
  * This is a "middle of the road" approach, differences are noted
  */
-IR_KEYTAB_TYPE ir_codes_budget_ci_old[IR_KEYTAB_SIZE] = {
-       [ 0x00 ] = KEY_0,
-       [ 0x01 ] = KEY_1,
-       [ 0x02 ] = KEY_2,
-       [ 0x03 ] = KEY_3,
-       [ 0x04 ] = KEY_4,
-       [ 0x05 ] = KEY_5,
-       [ 0x06 ] = KEY_6,
-       [ 0x07 ] = KEY_7,
-       [ 0x08 ] = KEY_8,
-       [ 0x09 ] = KEY_9,
-       [ 0x0a ] = KEY_ENTER,
-       [ 0x0b ] = KEY_RED,
-       [ 0x0c ] = KEY_POWER,             /* RADIO on Hauppauge */
-       [ 0x0d ] = KEY_MUTE,
-       [ 0x0f ] = KEY_A,                 /* TV on Hauppauge */
-       [ 0x10 ] = KEY_VOLUMEUP,
-       [ 0x11 ] = KEY_VOLUMEDOWN,
-       [ 0x14 ] = KEY_B,
-       [ 0x1c ] = KEY_UP,
-       [ 0x1d ] = KEY_DOWN,
-       [ 0x1e ] = KEY_OPTION,            /* RESERVED on Hauppauge */
-       [ 0x1f ] = KEY_BREAK,
-       [ 0x20 ] = KEY_CHANNELUP,
-       [ 0x21 ] = KEY_CHANNELDOWN,
-       [ 0x22 ] = KEY_PREVIOUS,          /* Prev. Ch on Zenith, SOURCE on Hauppauge */
-       [ 0x24 ] = KEY_RESTART,
-       [ 0x25 ] = KEY_OK,
-       [ 0x26 ] = KEY_CYCLEWINDOWS,      /* MINIMIZE on Hauppauge */
-       [ 0x28 ] = KEY_ENTER,             /* VCR mode on Zenith */
-       [ 0x29 ] = KEY_PAUSE,
-       [ 0x2b ] = KEY_RIGHT,
-       [ 0x2c ] = KEY_LEFT,
-       [ 0x2e ] = KEY_MENU,              /* FULL SCREEN on Hauppauge */
-       [ 0x30 ] = KEY_SLOW,
-       [ 0x31 ] = KEY_PREVIOUS,          /* VCR mode on Zenith */
-       [ 0x32 ] = KEY_REWIND,
-       [ 0x34 ] = KEY_FASTFORWARD,
-       [ 0x35 ] = KEY_PLAY,
-       [ 0x36 ] = KEY_STOP,
-       [ 0x37 ] = KEY_RECORD,
-       [ 0x38 ] = KEY_TUNER,             /* TV/VCR on Zenith */
-       [ 0x3a ] = KEY_C,
-       [ 0x3c ] = KEY_EXIT,
-       [ 0x3d ] = KEY_POWER2,
-       [ 0x3e ] = KEY_TUNER,
-};
-
-EXPORT_SYMBOL_GPL(ir_codes_budget_ci_old);
+static struct ir_scancode ir_codes_budget_ci_old[] = {
+       { 0x00, KEY_0 },
+       { 0x01, KEY_1 },
+       { 0x02, KEY_2 },
+       { 0x03, KEY_3 },
+       { 0x04, KEY_4 },
+       { 0x05, KEY_5 },
+       { 0x06, KEY_6 },
+       { 0x07, KEY_7 },
+       { 0x08, KEY_8 },
+       { 0x09, KEY_9 },
+       { 0x0a, KEY_ENTER },
+       { 0x0b, KEY_RED },
+       { 0x0c, KEY_POWER },            /* RADIO on Hauppauge */
+       { 0x0d, KEY_MUTE },
+       { 0x0f, KEY_A },                /* TV on Hauppauge */
+       { 0x10, KEY_VOLUMEUP },
+       { 0x11, KEY_VOLUMEDOWN },
+       { 0x14, KEY_B },
+       { 0x1c, KEY_UP },
+       { 0x1d, KEY_DOWN },
+       { 0x1e, KEY_OPTION },           /* RESERVED on Hauppauge */
+       { 0x1f, KEY_BREAK },
+       { 0x20, KEY_CHANNELUP },
+       { 0x21, KEY_CHANNELDOWN },
+       { 0x22, KEY_PREVIOUS },         /* Prev Ch on Zenith, SOURCE on Hauppauge */
+       { 0x24, KEY_RESTART },
+       { 0x25, KEY_OK },
+       { 0x26, KEY_CYCLEWINDOWS },     /* MINIMIZE on Hauppauge */
+       { 0x28, KEY_ENTER },            /* VCR mode on Zenith */
+       { 0x29, KEY_PAUSE },
+       { 0x2b, KEY_RIGHT },
+       { 0x2c, KEY_LEFT },
+       { 0x2e, KEY_MENU },             /* FULL SCREEN on Hauppauge */
+       { 0x30, KEY_SLOW },
+       { 0x31, KEY_PREVIOUS },         /* VCR mode on Zenith */
+       { 0x32, KEY_REWIND },
+       { 0x34, KEY_FASTFORWARD },
+       { 0x35, KEY_PLAY },
+       { 0x36, KEY_STOP },
+       { 0x37, KEY_RECORD },
+       { 0x38, KEY_TUNER },            /* TV/VCR on Zenith */
+       { 0x3a, KEY_C },
+       { 0x3c, KEY_EXIT },
+       { 0x3d, KEY_POWER2 },
+       { 0x3e, KEY_TUNER },
+};
+
+struct ir_scancode_table ir_codes_budget_ci_old_table = {
+       .scan = ir_codes_budget_ci_old,
+       .size = ARRAY_SIZE(ir_codes_budget_ci_old),
+};
+EXPORT_SYMBOL_GPL(ir_codes_budget_ci_old_table);
 
 /*
  * Marc Fargas <telenieko@telenieko.com>
  * this is the remote control that comes with the asus p7131
  * which has a label saying is "Model PC-39"
  */
-IR_KEYTAB_TYPE ir_codes_asus_pc39[IR_KEYTAB_SIZE] = {
+static struct ir_scancode ir_codes_asus_pc39[] = {
        /* Keys 0 to 9 */
-       [ 0x15 ] = KEY_0,
-       [ 0x29 ] = KEY_1,
-       [ 0x2d ] = KEY_2,
-       [ 0x2b ] = KEY_3,
-       [ 0x09 ] = KEY_4,
-       [ 0x0d ] = KEY_5,
-       [ 0x0b ] = KEY_6,
-       [ 0x31 ] = KEY_7,
-       [ 0x35 ] = KEY_8,
-       [ 0x33 ] = KEY_9,
-
-       [ 0x3e ] = KEY_RADIO,           /* radio */
-       [ 0x03 ] = KEY_MENU,            /* dvd/menu */
-       [ 0x2a ] = KEY_VOLUMEUP,
-       [ 0x19 ] = KEY_VOLUMEDOWN,
-       [ 0x37 ] = KEY_UP,
-       [ 0x3b ] = KEY_DOWN,
-       [ 0x27 ] = KEY_LEFT,
-       [ 0x2f ] = KEY_RIGHT,
-       [ 0x25 ] = KEY_VIDEO,           /* video */
-       [ 0x39 ] = KEY_AUDIO,           /* music */
-
-       [ 0x21 ] = KEY_TV,              /* tv */
-       [ 0x1d ] = KEY_EXIT,            /* back */
-       [ 0x0a ] = KEY_CHANNELUP,       /* channel / program + */
-       [ 0x1b ] = KEY_CHANNELDOWN,     /* channel / program - */
-       [ 0x1a ] = KEY_ENTER,           /* enter */
-
-       [ 0x06 ] = KEY_PAUSE,           /* play/pause */
-       [ 0x1e ] = KEY_PREVIOUS,        /* rew */
-       [ 0x26 ] = KEY_NEXT,            /* forward */
-       [ 0x0e ] = KEY_REWIND,          /* backward << */
-       [ 0x3a ] = KEY_FASTFORWARD,     /* forward >> */
-       [ 0x36 ] = KEY_STOP,
-       [ 0x2e ] = KEY_RECORD,          /* recording */
-       [ 0x16 ] = KEY_POWER,           /* the button that reads "close" */
-
-       [ 0x11 ] = KEY_ZOOM,            /* full screen */
-       [ 0x13 ] = KEY_MACRO,           /* recall */
-       [ 0x23 ] = KEY_HOME,            /* home */
-       [ 0x05 ] = KEY_PVR,             /* picture */
-       [ 0x3d ] = KEY_MUTE,            /* mute */
-       [ 0x01 ] = KEY_DVD,             /* dvd */
-};
-
-EXPORT_SYMBOL_GPL(ir_codes_asus_pc39);
+       { 0x15, KEY_0 },
+       { 0x29, KEY_1 },
+       { 0x2d, KEY_2 },
+       { 0x2b, KEY_3 },
+       { 0x09, KEY_4 },
+       { 0x0d, KEY_5 },
+       { 0x0b, KEY_6 },
+       { 0x31, KEY_7 },
+       { 0x35, KEY_8 },
+       { 0x33, KEY_9 },
+
+       { 0x3e, KEY_RADIO },            /* radio */
+       { 0x03, KEY_MENU },             /* dvd/menu */
+       { 0x2a, KEY_VOLUMEUP },
+       { 0x19, KEY_VOLUMEDOWN },
+       { 0x37, KEY_UP },
+       { 0x3b, KEY_DOWN },
+       { 0x27, KEY_LEFT },
+       { 0x2f, KEY_RIGHT },
+       { 0x25, KEY_VIDEO },            /* video */
+       { 0x39, KEY_AUDIO },            /* music */
+
+       { 0x21, KEY_TV },               /* tv */
+       { 0x1d, KEY_EXIT },             /* back */
+       { 0x0a, KEY_CHANNELUP },        /* channel / program + */
+       { 0x1b, KEY_CHANNELDOWN },      /* channel / program - */
+       { 0x1a, KEY_ENTER },            /* enter */
+
+       { 0x06, KEY_PAUSE },            /* play/pause */
+       { 0x1e, KEY_PREVIOUS },         /* rew */
+       { 0x26, KEY_NEXT },             /* forward */
+       { 0x0e, KEY_REWIND },           /* backward << */
+       { 0x3a, KEY_FASTFORWARD },      /* forward >> */
+       { 0x36, KEY_STOP },
+       { 0x2e, KEY_RECORD },           /* recording */
+       { 0x16, KEY_POWER },            /* the button that reads "close" */
+
+       { 0x11, KEY_ZOOM },             /* full screen */
+       { 0x13, KEY_MACRO },            /* recall */
+       { 0x23, KEY_HOME },             /* home */
+       { 0x05, KEY_PVR },              /* picture */
+       { 0x3d, KEY_MUTE },             /* mute */
+       { 0x01, KEY_DVD },              /* dvd */
+};
+
+struct ir_scancode_table ir_codes_asus_pc39_table = {
+       .scan = ir_codes_asus_pc39,
+       .size = ARRAY_SIZE(ir_codes_asus_pc39),
+};
+EXPORT_SYMBOL_GPL(ir_codes_asus_pc39_table);
 
 
 /* Encore ENLTV-FM  - black plastic, white front cover with white glowing buttons
     Juan Pablo Sormani <sorman@gmail.com> */
-IR_KEYTAB_TYPE ir_codes_encore_enltv[IR_KEYTAB_SIZE] = {
+static struct ir_scancode ir_codes_encore_enltv[] = {
 
        /* Power button does nothing, neither in Windows app,
         although it sends data (used for BIOS wakeup?) */
-       [ 0x0d ] = KEY_MUTE,
-
-       [ 0x1e ] = KEY_TV,
-       [ 0x00 ] = KEY_VIDEO,
-       [ 0x01 ] = KEY_AUDIO,           /* music */
-       [ 0x02 ] = KEY_MHP,             /* picture */
-
-       [ 0x1f ] = KEY_1,
-       [ 0x03 ] = KEY_2,
-       [ 0x04 ] = KEY_3,
-       [ 0x05 ] = KEY_4,
-       [ 0x1c ] = KEY_5,
-       [ 0x06 ] = KEY_6,
-       [ 0x07 ] = KEY_7,
-       [ 0x08 ] = KEY_8,
-       [ 0x1d ] = KEY_9,
-       [ 0x0a ] = KEY_0,
-
-       [ 0x09 ] = KEY_LIST,        /* -/-- */
-       [ 0x0b ] = KEY_LAST,        /* recall */
-
-       [ 0x14 ] = KEY_HOME,            /* win start menu */
-       [ 0x15 ] = KEY_EXIT,            /* exit */
-       [ 0x16 ] = KEY_UP,
-       [ 0x12 ] = KEY_DOWN,
-       [ 0x0c ] = KEY_RIGHT,
-       [ 0x17 ] = KEY_LEFT,
-
-       [ 0x18 ] = KEY_ENTER,           /* OK */
-
-       [ 0x0e ] = KEY_ESC,
-       [ 0x13 ] = KEY_D,               /* desktop */
-       [ 0x11 ] = KEY_TAB,
-       [ 0x19 ] = KEY_SWITCHVIDEOMODE, /* switch */
-
-       [ 0x1a ] = KEY_MENU,
-       [ 0x1b ] = KEY_ZOOM,            /* fullscreen */
-       [ 0x44 ] = KEY_TIME,            /* time shift */
-       [ 0x40 ] = KEY_MODE,            /* source */
-
-       [ 0x5a ] = KEY_RECORD,
-       [ 0x42 ] = KEY_PLAY,            /* play/pause */
-       [ 0x45 ] = KEY_STOP,
-       [ 0x43 ] = KEY_CAMERA,          /* camera icon */
-
-       [ 0x48 ] = KEY_REWIND,
-       [ 0x4a ] = KEY_FASTFORWARD,
-       [ 0x49 ] = KEY_PREVIOUS,
-       [ 0x4b ] = KEY_NEXT,
-
-       [ 0x4c ] = KEY_FAVORITES,       /* tv wall */
-       [ 0x4d ] = KEY_SOUND,           /* DVD sound */
-       [ 0x4e ] = KEY_LANGUAGE,        /* DVD lang */
-       [ 0x4f ] = KEY_TEXT,            /* DVD text */
-
-       [ 0x50 ] = KEY_SLEEP,           /* shutdown */
-       [ 0x51 ] = KEY_MODE,            /* stereo > main */
-       [ 0x52 ] = KEY_SELECT,          /* stereo > sap */
-       [ 0x53 ] = KEY_PROG1,           /* teletext */
-
-
-       [ 0x59 ] = KEY_RED,             /* AP1 */
-       [ 0x41 ] = KEY_GREEN,           /* AP2 */
-       [ 0x47 ] = KEY_YELLOW,          /* AP3 */
-       [ 0x57 ] = KEY_BLUE,            /* AP4 */
-};
-EXPORT_SYMBOL_GPL(ir_codes_encore_enltv);
+       { 0x0d, KEY_MUTE },
+
+       { 0x1e, KEY_TV },
+       { 0x00, KEY_VIDEO },
+       { 0x01, KEY_AUDIO },            /* music */
+       { 0x02, KEY_MHP },              /* picture */
+
+       { 0x1f, KEY_1 },
+       { 0x03, KEY_2 },
+       { 0x04, KEY_3 },
+       { 0x05, KEY_4 },
+       { 0x1c, KEY_5 },
+       { 0x06, KEY_6 },
+       { 0x07, KEY_7 },
+       { 0x08, KEY_8 },
+       { 0x1d, KEY_9 },
+       { 0x0a, KEY_0 },
+
+       { 0x09, KEY_LIST },             /* -/-- */
+       { 0x0b, KEY_LAST },             /* recall */
+
+       { 0x14, KEY_HOME },             /* win start menu */
+       { 0x15, KEY_EXIT },             /* exit */
+       { 0x16, KEY_CHANNELUP },        /* UP */
+       { 0x12, KEY_CHANNELDOWN },      /* DOWN */
+       { 0x0c, KEY_VOLUMEUP },         /* RIGHT */
+       { 0x17, KEY_VOLUMEDOWN },       /* LEFT */
+
+       { 0x18, KEY_ENTER },            /* OK */
+
+       { 0x0e, KEY_ESC },
+       { 0x13, KEY_CYCLEWINDOWS },     /* desktop */
+       { 0x11, KEY_TAB },
+       { 0x19, KEY_SWITCHVIDEOMODE },  /* switch */
+
+       { 0x1a, KEY_MENU },
+       { 0x1b, KEY_ZOOM },             /* fullscreen */
+       { 0x44, KEY_TIME },             /* time shift */
+       { 0x40, KEY_MODE },             /* source */
+
+       { 0x5a, KEY_RECORD },
+       { 0x42, KEY_PLAY },             /* play/pause */
+       { 0x45, KEY_STOP },
+       { 0x43, KEY_CAMERA },           /* camera icon */
+
+       { 0x48, KEY_REWIND },
+       { 0x4a, KEY_FASTFORWARD },
+       { 0x49, KEY_PREVIOUS },
+       { 0x4b, KEY_NEXT },
+
+       { 0x4c, KEY_FAVORITES },        /* tv wall */
+       { 0x4d, KEY_SOUND },            /* DVD sound */
+       { 0x4e, KEY_LANGUAGE },         /* DVD lang */
+       { 0x4f, KEY_TEXT },             /* DVD text */
+
+       { 0x50, KEY_SLEEP },            /* shutdown */
+       { 0x51, KEY_MODE },             /* stereo > main */
+       { 0x52, KEY_SELECT },           /* stereo > sap */
+       { 0x53, KEY_PROG1 },            /* teletext */
+
+
+       { 0x59, KEY_RED },              /* AP1 */
+       { 0x41, KEY_GREEN },            /* AP2 */
+       { 0x47, KEY_YELLOW },           /* AP3 */
+       { 0x57, KEY_BLUE },             /* AP4 */
+};
+
+struct ir_scancode_table ir_codes_encore_enltv_table = {
+       .scan = ir_codes_encore_enltv,
+       .size = ARRAY_SIZE(ir_codes_encore_enltv),
+};
+EXPORT_SYMBOL_GPL(ir_codes_encore_enltv_table);
 
 /* Encore ENLTV2-FM  - silver plastic - "Wand Media" written at the botton
     Mauro Carvalho Chehab <mchehab@infradead.org> */
-IR_KEYTAB_TYPE ir_codes_encore_enltv2[IR_KEYTAB_SIZE] = {
-       [0x4c] = KEY_POWER2,
-       [0x4a] = KEY_TUNER,
-       [0x40] = KEY_1,
-       [0x60] = KEY_2,
-       [0x50] = KEY_3,
-       [0x70] = KEY_4,
-       [0x48] = KEY_5,
-       [0x68] = KEY_6,
-       [0x58] = KEY_7,
-       [0x78] = KEY_8,
-       [0x44] = KEY_9,
-       [0x54] = KEY_0,
-
-       [0x64] = KEY_LAST,              /* +100 */
-       [0x4e] = KEY_AGAIN,             /* Recall */
-
-       [0x6c] = KEY_SWITCHVIDEOMODE,   /* Video Source */
-       [0x5e] = KEY_MENU,
-       [0x56] = KEY_SCREEN,
-       [0x7a] = KEY_SETUP,
-
-       [0x46] = KEY_MUTE,
-       [0x5c] = KEY_MODE,              /* Stereo */
-       [0x74] = KEY_INFO,
-       [0x7c] = KEY_CLEAR,
-
-       [0x55] = KEY_UP,
-       [0x49] = KEY_DOWN,
-       [0x7e] = KEY_LEFT,
-       [0x59] = KEY_RIGHT,
-       [0x6a] = KEY_ENTER,
-
-       [0x42] = KEY_VOLUMEUP,
-       [0x62] = KEY_VOLUMEDOWN,
-       [0x52] = KEY_CHANNELUP,
-       [0x72] = KEY_CHANNELDOWN,
-
-       [0x41] = KEY_RECORD,
-       [0x51] = KEY_SHUFFLE,   /* Snapshot */
-       [0x75] = KEY_TIME,      /* Timeshift */
-       [0x71] = KEY_TV2,       /* PIP */
-
-       [0x45] = KEY_REWIND,
-       [0x6f] = KEY_PAUSE,
-       [0x7d] = KEY_FORWARD,
-       [0x79] = KEY_STOP,
-};
-EXPORT_SYMBOL_GPL(ir_codes_encore_enltv2);
+static struct ir_scancode ir_codes_encore_enltv2[] = {
+       { 0x4c, KEY_POWER2 },
+       { 0x4a, KEY_TUNER },
+       { 0x40, KEY_1 },
+       { 0x60, KEY_2 },
+       { 0x50, KEY_3 },
+       { 0x70, KEY_4 },
+       { 0x48, KEY_5 },
+       { 0x68, KEY_6 },
+       { 0x58, KEY_7 },
+       { 0x78, KEY_8 },
+       { 0x44, KEY_9 },
+       { 0x54, KEY_0 },
+
+       { 0x64, KEY_LAST },             /* +100 */
+       { 0x4e, KEY_AGAIN },            /* Recall */
+
+       { 0x6c, KEY_SWITCHVIDEOMODE },  /* Video Source */
+       { 0x5e, KEY_MENU },
+       { 0x56, KEY_SCREEN },
+       { 0x7a, KEY_SETUP },
+
+       { 0x46, KEY_MUTE },
+       { 0x5c, KEY_MODE },             /* Stereo */
+       { 0x74, KEY_INFO },
+       { 0x7c, KEY_CLEAR },
+
+       { 0x55, KEY_UP },
+       { 0x49, KEY_DOWN },
+       { 0x7e, KEY_LEFT },
+       { 0x59, KEY_RIGHT },
+       { 0x6a, KEY_ENTER },
+
+       { 0x42, KEY_VOLUMEUP },
+       { 0x62, KEY_VOLUMEDOWN },
+       { 0x52, KEY_CHANNELUP },
+       { 0x72, KEY_CHANNELDOWN },
+
+       { 0x41, KEY_RECORD },
+       { 0x51, KEY_CAMERA },           /* Snapshot */
+       { 0x75, KEY_TIME },             /* Timeshift */
+       { 0x71, KEY_TV2 },              /* PIP */
+
+       { 0x45, KEY_REWIND },
+       { 0x6f, KEY_PAUSE },
+       { 0x7d, KEY_FORWARD },
+       { 0x79, KEY_STOP },
+};
+
+struct ir_scancode_table ir_codes_encore_enltv2_table = {
+       .scan = ir_codes_encore_enltv2,
+       .size = ARRAY_SIZE(ir_codes_encore_enltv2),
+};
+EXPORT_SYMBOL_GPL(ir_codes_encore_enltv2_table);
 
 /* for the Technotrend 1500 bundled remotes (grey and black): */
-IR_KEYTAB_TYPE ir_codes_tt_1500[IR_KEYTAB_SIZE] = {
-       [ 0x01 ] = KEY_POWER,
-       [ 0x02 ] = KEY_SHUFFLE, /* ? double-arrow key */
-       [ 0x03 ] = KEY_1,
-       [ 0x04 ] = KEY_2,
-       [ 0x05 ] = KEY_3,
-       [ 0x06 ] = KEY_4,
-       [ 0x07 ] = KEY_5,
-       [ 0x08 ] = KEY_6,
-       [ 0x09 ] = KEY_7,
-       [ 0x0a ] = KEY_8,
-       [ 0x0b ] = KEY_9,
-       [ 0x0c ] = KEY_0,
-       [ 0x0d ] = KEY_UP,
-       [ 0x0e ] = KEY_LEFT,
-       [ 0x0f ] = KEY_OK,
-       [ 0x10 ] = KEY_RIGHT,
-       [ 0x11 ] = KEY_DOWN,
-       [ 0x12 ] = KEY_INFO,
-       [ 0x13 ] = KEY_EXIT,
-       [ 0x14 ] = KEY_RED,
-       [ 0x15 ] = KEY_GREEN,
-       [ 0x16 ] = KEY_YELLOW,
-       [ 0x17 ] = KEY_BLUE,
-       [ 0x18 ] = KEY_MUTE,
-       [ 0x19 ] = KEY_TEXT,
-       [ 0x1a ] = KEY_MODE,    /* ? TV/Radio */
-       [ 0x21 ] = KEY_OPTION,
-       [ 0x22 ] = KEY_EPG,
-       [ 0x23 ] = KEY_CHANNELUP,
-       [ 0x24 ] = KEY_CHANNELDOWN,
-       [ 0x25 ] = KEY_VOLUMEUP,
-       [ 0x26 ] = KEY_VOLUMEDOWN,
-       [ 0x27 ] = KEY_SETUP,
-       [ 0x3a ] = KEY_RECORD, /* these keys are only in the black remote */
-       [ 0x3b ] = KEY_PLAY,
-       [ 0x3c ] = KEY_STOP,
-       [ 0x3d ] = KEY_REWIND,
-       [ 0x3e ] = KEY_PAUSE,
-       [ 0x3f ] = KEY_FORWARD,
-};
-
-EXPORT_SYMBOL_GPL(ir_codes_tt_1500);
+static struct ir_scancode ir_codes_tt_1500[] = {
+       { 0x01, KEY_POWER },
+       { 0x02, KEY_SHUFFLE },          /* ? double-arrow key */
+       { 0x03, KEY_1 },
+       { 0x04, KEY_2 },
+       { 0x05, KEY_3 },
+       { 0x06, KEY_4 },
+       { 0x07, KEY_5 },
+       { 0x08, KEY_6 },
+       { 0x09, KEY_7 },
+       { 0x0a, KEY_8 },
+       { 0x0b, KEY_9 },
+       { 0x0c, KEY_0 },
+       { 0x0d, KEY_UP },
+       { 0x0e, KEY_LEFT },
+       { 0x0f, KEY_OK },
+       { 0x10, KEY_RIGHT },
+       { 0x11, KEY_DOWN },
+       { 0x12, KEY_INFO },
+       { 0x13, KEY_EXIT },
+       { 0x14, KEY_RED },
+       { 0x15, KEY_GREEN },
+       { 0x16, KEY_YELLOW },
+       { 0x17, KEY_BLUE },
+       { 0x18, KEY_MUTE },
+       { 0x19, KEY_TEXT },
+       { 0x1a, KEY_MODE },             /* ? TV/Radio */
+       { 0x21, KEY_OPTION },
+       { 0x22, KEY_EPG },
+       { 0x23, KEY_CHANNELUP },
+       { 0x24, KEY_CHANNELDOWN },
+       { 0x25, KEY_VOLUMEUP },
+       { 0x26, KEY_VOLUMEDOWN },
+       { 0x27, KEY_SETUP },
+       { 0x3a, KEY_RECORD },           /* these keys are only in the black remote */
+       { 0x3b, KEY_PLAY },
+       { 0x3c, KEY_STOP },
+       { 0x3d, KEY_REWIND },
+       { 0x3e, KEY_PAUSE },
+       { 0x3f, KEY_FORWARD },
+};
+
+struct ir_scancode_table ir_codes_tt_1500_table = {
+       .scan = ir_codes_tt_1500,
+       .size = ARRAY_SIZE(ir_codes_tt_1500),
+};
+EXPORT_SYMBOL_GPL(ir_codes_tt_1500_table);
 
 /* DViCO FUSION HDTV MCE remote */
-IR_KEYTAB_TYPE ir_codes_fusionhdtv_mce[IR_KEYTAB_SIZE] = {
-
-       [ 0x0b ] = KEY_1,
-       [ 0x17 ] = KEY_2,
-       [ 0x1b ] = KEY_3,
-       [ 0x07 ] = KEY_4,
-       [ 0x50 ] = KEY_5,
-       [ 0x54 ] = KEY_6,
-       [ 0x48 ] = KEY_7,
-       [ 0x4c ] = KEY_8,
-       [ 0x58 ] = KEY_9,
-       [ 0x03 ] = KEY_0,
-
-       [ 0x5e ] = KEY_OK,
-       [ 0x51 ] = KEY_UP,
-       [ 0x53 ] = KEY_DOWN,
-       [ 0x5b ] = KEY_LEFT,
-       [ 0x5f ] = KEY_RIGHT,
-
-       [ 0x02 ] = KEY_TV,              /* Labeled DTV on remote */
-       [ 0x0e ] = KEY_MP3,
-       [ 0x1a ] = KEY_DVD,
-       [ 0x1e ] = KEY_FAVORITES,       /* Labeled CPF on remote */
-       [ 0x16 ] = KEY_SETUP,
-       [ 0x46 ] = KEY_POWER2,          /* TV On/Off button on remote */
-       [ 0x0a ] = KEY_EPG,             /* Labeled Guide on remote */
-
-       [ 0x49 ] = KEY_BACK,
-       [ 0x59 ] = KEY_INFO,            /* Labeled MORE on remote */
-       [ 0x4d ] = KEY_MENU,            /* Labeled DVDMENU on remote */
-       [ 0x55 ] = KEY_CYCLEWINDOWS,    /* Labeled ALT-TAB on remote */
-
-       [ 0x0f ] = KEY_PREVIOUSSONG,    /* Labeled |<< REPLAY on remote */
-       [ 0x12 ] = KEY_NEXTSONG,        /* Labeled >>| SKIP on remote */
-       [ 0x42 ] = KEY_ENTER,           /* Labeled START with a green
-                                        * MS windows logo on remote */
-
-       [ 0x15 ] = KEY_VOLUMEUP,
-       [ 0x05 ] = KEY_VOLUMEDOWN,
-       [ 0x11 ] = KEY_CHANNELUP,
-       [ 0x09 ] = KEY_CHANNELDOWN,
-
-       [ 0x52 ] = KEY_CAMERA,
-       [ 0x5a ] = KEY_TUNER,
-       [ 0x19 ] = KEY_OPEN,
-
-       [ 0x13 ] = KEY_MODE,            /* 4:3 16:9 select */
-       [ 0x1f ] = KEY_ZOOM,
-
-       [ 0x43 ] = KEY_REWIND,
-       [ 0x47 ] = KEY_PLAYPAUSE,
-       [ 0x4f ] = KEY_FASTFORWARD,
-       [ 0x57 ] = KEY_MUTE,
-       [ 0x0d ] = KEY_STOP,
-       [ 0x01 ] = KEY_RECORD,
-       [ 0x4e ] = KEY_POWER,
-};
-
-EXPORT_SYMBOL_GPL(ir_codes_fusionhdtv_mce);
+static struct ir_scancode ir_codes_fusionhdtv_mce[] = {
+
+       { 0x0b, KEY_1 },
+       { 0x17, KEY_2 },
+       { 0x1b, KEY_3 },
+       { 0x07, KEY_4 },
+       { 0x50, KEY_5 },
+       { 0x54, KEY_6 },
+       { 0x48, KEY_7 },
+       { 0x4c, KEY_8 },
+       { 0x58, KEY_9 },
+       { 0x03, KEY_0 },
+
+       { 0x5e, KEY_OK },
+       { 0x51, KEY_UP },
+       { 0x53, KEY_DOWN },
+       { 0x5b, KEY_LEFT },
+       { 0x5f, KEY_RIGHT },
+
+       { 0x02, KEY_TV },               /* Labeled DTV on remote */
+       { 0x0e, KEY_MP3 },
+       { 0x1a, KEY_DVD },
+       { 0x1e, KEY_FAVORITES },        /* Labeled CPF on remote */
+       { 0x16, KEY_SETUP },
+       { 0x46, KEY_POWER2 },           /* TV On/Off button on remote */
+       { 0x0a, KEY_EPG },              /* Labeled Guide on remote */
+
+       { 0x49, KEY_BACK },
+       { 0x59, KEY_INFO },             /* Labeled MORE on remote */
+       { 0x4d, KEY_MENU },             /* Labeled DVDMENU on remote */
+       { 0x55, KEY_CYCLEWINDOWS },     /* Labeled ALT-TAB on remote */
+
+       { 0x0f, KEY_PREVIOUSSONG },     /* Labeled |<< REPLAY on remote */
+       { 0x12, KEY_NEXTSONG },         /* Labeled >>| SKIP on remote */
+       { 0x42, KEY_ENTER },            /* Labeled START with a green
+                                          MS windows logo on remote */
+
+       { 0x15, KEY_VOLUMEUP },
+       { 0x05, KEY_VOLUMEDOWN },
+       { 0x11, KEY_CHANNELUP },
+       { 0x09, KEY_CHANNELDOWN },
+
+       { 0x52, KEY_CAMERA },
+       { 0x5a, KEY_TUNER },
+       { 0x19, KEY_OPEN },
+
+       { 0x13, KEY_MODE },             /* 4:3 16:9 select */
+       { 0x1f, KEY_ZOOM },
+
+       { 0x43, KEY_REWIND },
+       { 0x47, KEY_PLAYPAUSE },
+       { 0x4f, KEY_FASTFORWARD },
+       { 0x57, KEY_MUTE },
+       { 0x0d, KEY_STOP },
+       { 0x01, KEY_RECORD },
+       { 0x4e, KEY_POWER },
+};
+
+struct ir_scancode_table ir_codes_fusionhdtv_mce_table = {
+       .scan = ir_codes_fusionhdtv_mce,
+       .size = ARRAY_SIZE(ir_codes_fusionhdtv_mce),
+};
+EXPORT_SYMBOL_GPL(ir_codes_fusionhdtv_mce_table);
 
 /* Pinnacle PCTV HD 800i mini remote */
-IR_KEYTAB_TYPE ir_codes_pinnacle_pctv_hd[IR_KEYTAB_SIZE] = {
-
-       [0x0f] = KEY_1,
-       [0x15] = KEY_2,
-       [0x10] = KEY_3,
-       [0x18] = KEY_4,
-       [0x1b] = KEY_5,
-       [0x1e] = KEY_6,
-       [0x11] = KEY_7,
-       [0x21] = KEY_8,
-       [0x12] = KEY_9,
-       [0x27] = KEY_0,
-
-       [0x24] = KEY_ZOOM,
-       [0x2a] = KEY_SUBTITLE,
-
-       [0x00] = KEY_MUTE,
-       [0x01] = KEY_ENTER,     /* Pinnacle Logo */
-       [0x39] = KEY_POWER,
-
-       [0x03] = KEY_VOLUMEUP,
-       [0x09] = KEY_VOLUMEDOWN,
-       [0x06] = KEY_CHANNELUP,
-       [0x0c] = KEY_CHANNELDOWN,
-
-       [0x2d] = KEY_REWIND,
-       [0x30] = KEY_PLAYPAUSE,
-       [0x33] = KEY_FASTFORWARD,
-       [0x3c] = KEY_STOP,
-       [0x36] = KEY_RECORD,
-       [0x3f] = KEY_EPG,       /* Labeled "?" */
-};
-EXPORT_SYMBOL_GPL(ir_codes_pinnacle_pctv_hd);
+static struct ir_scancode ir_codes_pinnacle_pctv_hd[] = {
+
+       { 0x0f, KEY_1 },
+       { 0x15, KEY_2 },
+       { 0x10, KEY_3 },
+       { 0x18, KEY_4 },
+       { 0x1b, KEY_5 },
+       { 0x1e, KEY_6 },
+       { 0x11, KEY_7 },
+       { 0x21, KEY_8 },
+       { 0x12, KEY_9 },
+       { 0x27, KEY_0 },
+
+       { 0x24, KEY_ZOOM },
+       { 0x2a, KEY_SUBTITLE },
+
+       { 0x00, KEY_MUTE },
+       { 0x01, KEY_ENTER },    /* Pinnacle Logo */
+       { 0x39, KEY_POWER },
+
+       { 0x03, KEY_VOLUMEUP },
+       { 0x09, KEY_VOLUMEDOWN },
+       { 0x06, KEY_CHANNELUP },
+       { 0x0c, KEY_CHANNELDOWN },
+
+       { 0x2d, KEY_REWIND },
+       { 0x30, KEY_PLAYPAUSE },
+       { 0x33, KEY_FASTFORWARD },
+       { 0x3c, KEY_STOP },
+       { 0x36, KEY_RECORD },
+       { 0x3f, KEY_EPG },      /* Labeled "?" */
+};
+
+struct ir_scancode_table ir_codes_pinnacle_pctv_hd_table = {
+       .scan = ir_codes_pinnacle_pctv_hd,
+       .size = ARRAY_SIZE(ir_codes_pinnacle_pctv_hd),
+};
+EXPORT_SYMBOL_GPL(ir_codes_pinnacle_pctv_hd_table);
 
 /*
  * Igor Kuznetsov <igk72@ya.ru>
@@ -2198,13 +2365,13 @@ EXPORT_SYMBOL_GPL(ir_codes_pinnacle_pctv_hd);
  * the button labels (several variants when appropriate)
  * helps to descide which keycodes to assign to the buttons.
  */
-IR_KEYTAB_TYPE ir_codes_behold[IR_KEYTAB_SIZE] = {
+static struct ir_scancode ir_codes_behold[] = {
 
        /*  0x1c            0x12  *
         *  TV/FM          POWER  *
         *                        */
-       [ 0x1c ] = KEY_TUNER,   /*XXX KEY_TV KEY_RADIO */
-       [ 0x12 ] = KEY_POWER,
+       { 0x1c, KEY_TUNER },    /* XXX KEY_TV / KEY_RADIO */
+       { 0x12, KEY_POWER },
 
        /*  0x01    0x02    0x03  *
         *   1       2       3    *
@@ -2215,28 +2382,28 @@ IR_KEYTAB_TYPE ir_codes_behold[IR_KEYTAB_SIZE] = {
         *  0x07    0x08    0x09  *
         *   7       8       9    *
         *                        */
-       [ 0x01 ] = KEY_1,
-       [ 0x02 ] = KEY_2,
-       [ 0x03 ] = KEY_3,
-       [ 0x04 ] = KEY_4,
-       [ 0x05 ] = KEY_5,
-       [ 0x06 ] = KEY_6,
-       [ 0x07 ] = KEY_7,
-       [ 0x08 ] = KEY_8,
-       [ 0x09 ] = KEY_9,
+       { 0x01, KEY_1 },
+       { 0x02, KEY_2 },
+       { 0x03, KEY_3 },
+       { 0x04, KEY_4 },
+       { 0x05, KEY_5 },
+       { 0x06, KEY_6 },
+       { 0x07, KEY_7 },
+       { 0x08, KEY_8 },
+       { 0x09, KEY_9 },
 
        /*  0x0a    0x00    0x17  *
         * RECALL    0      MODE  *
         *                        */
-       [ 0x0a ] = KEY_AGAIN,
-       [ 0x00 ] = KEY_0,
-       [ 0x17 ] = KEY_MODE,
+       { 0x0a, KEY_AGAIN },
+       { 0x00, KEY_0 },
+       { 0x17, KEY_MODE },
 
        /*  0x14          0x10    *
         * ASPECT      FULLSCREEN *
         *                        */
-       [ 0x14 ] = KEY_SCREEN,
-       [ 0x10 ] = KEY_ZOOM,
+       { 0x14, KEY_SCREEN },
+       { 0x10, KEY_ZOOM },
 
        /*          0x0b          *
         *           Up           *
@@ -2247,17 +2414,17 @@ IR_KEYTAB_TYPE ir_codes_behold[IR_KEYTAB_SIZE] = {
         *         0x015          *
         *         Down           *
         *                        */
-       [ 0x0b ] = KEY_CHANNELUP,       /*XXX KEY_UP */
-       [ 0x18 ] = KEY_VOLUMEDOWN,      /*XXX KEY_LEFT */
-       [ 0x16 ] = KEY_OK,              /*XXX KEY_ENTER */
-       [ 0x0c ] = KEY_VOLUMEUP,        /*XXX KEY_RIGHT */
-       [ 0x15 ] = KEY_CHANNELDOWN,     /*XXX KEY_DOWN */
+       { 0x0b, KEY_CHANNELUP },
+       { 0x18, KEY_VOLUMEDOWN },
+       { 0x16, KEY_OK },               /* XXX KEY_ENTER */
+       { 0x0c, KEY_VOLUMEUP },
+       { 0x15, KEY_CHANNELDOWN },
 
        /*  0x11            0x0d  *
         *  MUTE            INFO  *
         *                        */
-       [ 0x11 ] = KEY_MUTE,
-       [ 0x0d ] = KEY_INFO,
+       { 0x11, KEY_MUTE },
+       { 0x0d, KEY_INFO },
 
        /*  0x0f    0x1b    0x1a  *
         * RECORD PLAY/PAUSE STOP *
@@ -2266,30 +2433,34 @@ IR_KEYTAB_TYPE ir_codes_behold[IR_KEYTAB_SIZE] = {
         *TELETEXT  AUDIO  SOURCE *
         *           RED   YELLOW *
         *                        */
-       [ 0x0f ] = KEY_RECORD,
-       [ 0x1b ] = KEY_PLAYPAUSE,
-       [ 0x1a ] = KEY_STOP,
-       [ 0x0e ] = KEY_TEXT,
-       [ 0x1f ] = KEY_RED,     /*XXX KEY_AUDIO */
-       [ 0x1e ] = KEY_YELLOW,  /*XXX KEY_SOURCE */
+       { 0x0f, KEY_RECORD },
+       { 0x1b, KEY_PLAYPAUSE },
+       { 0x1a, KEY_STOP },
+       { 0x0e, KEY_TEXT },
+       { 0x1f, KEY_RED },      /*XXX KEY_AUDIO */
+       { 0x1e, KEY_YELLOW },   /*XXX KEY_SOURCE        */
 
        /*  0x1d   0x13     0x19  *
         * SLEEP  PREVIEW   DVB   *
         *         GREEN    BLUE  *
         *                        */
-       [ 0x1d ] = KEY_SLEEP,
-       [ 0x13 ] = KEY_GREEN,
-       [ 0x19 ] = KEY_BLUE,    /*XXX KEY_SAT */
+       { 0x1d, KEY_SLEEP },
+       { 0x13, KEY_GREEN },
+       { 0x19, KEY_BLUE },     /* XXX KEY_SAT  */
 
        /*  0x58           0x5c   *
         * FREEZE        SNAPSHOT *
         *                        */
-       [ 0x58 ] = KEY_SLOW,
-       [ 0x5c ] = KEY_SAVE,
+       { 0x58, KEY_SLOW },
+       { 0x5c, KEY_CAMERA },
 
 };
 
-EXPORT_SYMBOL_GPL(ir_codes_behold);
+struct ir_scancode_table ir_codes_behold_table = {
+       .scan = ir_codes_behold,
+       .size = ARRAY_SIZE(ir_codes_behold),
+};
+EXPORT_SYMBOL_GPL(ir_codes_behold_table);
 
 /* Beholder Intl. Ltd. 2008
  * Dmitry Belimov d.belimov@google.com
@@ -2299,16 +2470,16 @@ EXPORT_SYMBOL_GPL(ir_codes_behold);
  * the button labels (several variants when appropriate)
  * helps to descide which keycodes to assign to the buttons.
  */
-IR_KEYTAB_TYPE ir_codes_behold_columbus[IR_KEYTAB_SIZE] = {
+static struct ir_scancode ir_codes_behold_columbus[] = {
 
        /*  0x13   0x11   0x1C   0x12  *
         *  Mute  Source  TV/FM  Power *
         *                             */
 
-       [0x13] = KEY_MUTE,
-       [0x11] = KEY_PROPS,
-       [0x1C] = KEY_TUNER,     /* KEY_TV/KEY_RADIO */
-       [0x12] = KEY_POWER,
+       { 0x13, KEY_MUTE },
+       { 0x11, KEY_PROPS },
+       { 0x1C, KEY_TUNER },    /* KEY_TV/KEY_RADIO     */
+       { 0x12, KEY_POWER },
 
        /*  0x01    0x02    0x03  0x0D    *
         *   1       2       3   Stereo   *
@@ -2319,173 +2490,188 @@ IR_KEYTAB_TYPE ir_codes_behold_columbus[IR_KEYTAB_SIZE] = {
         *  0x07    0x08    0x09  0x10    *
         *   7       8       9    Zoom    *
         *                                */
-       [0x01] = KEY_1,
-       [0x02] = KEY_2,
-       [0x03] = KEY_3,
-       [0x0D] = KEY_SETUP,       /* Setup key */
-       [0x04] = KEY_4,
-       [0x05] = KEY_5,
-       [0x06] = KEY_6,
-       [0x19] = KEY_BOOKMARKS, /* Snapshot key */
-       [0x07] = KEY_7,
-       [0x08] = KEY_8,
-       [0x09] = KEY_9,
-       [0x10] = KEY_ZOOM,
+       { 0x01, KEY_1 },
+       { 0x02, KEY_2 },
+       { 0x03, KEY_3 },
+       { 0x0D, KEY_SETUP },      /* Setup key */
+       { 0x04, KEY_4 },
+       { 0x05, KEY_5 },
+       { 0x06, KEY_6 },
+       { 0x19, KEY_CAMERA },   /* Snapshot key */
+       { 0x07, KEY_7 },
+       { 0x08, KEY_8 },
+       { 0x09, KEY_9 },
+       { 0x10, KEY_ZOOM },
 
        /*  0x0A    0x00    0x0B       0x0C   *
         * RECALL    0    ChannelUp  VolumeUp *
         *                                    */
-       [0x0A] = KEY_AGAIN,
-       [0x00] = KEY_0,
-       [0x0B] = KEY_CHANNELUP,
-       [0x0C] = KEY_VOLUMEUP,
+       { 0x0A, KEY_AGAIN },
+       { 0x00, KEY_0 },
+       { 0x0B, KEY_CHANNELUP },
+       { 0x0C, KEY_VOLUMEUP },
 
        /*   0x1B      0x1D      0x15        0x18     *
         * Timeshift  Record  ChannelDown  VolumeDown *
         *                                            */
 
-       [0x1B] = KEY_REWIND,
-       [0x1D] = KEY_RECORD,
-       [0x15] = KEY_CHANNELDOWN,
-       [0x18] = KEY_VOLUMEDOWN,
+       { 0x1B, KEY_TIME },
+       { 0x1D, KEY_RECORD },
+       { 0x15, KEY_CHANNELDOWN },
+       { 0x18, KEY_VOLUMEDOWN },
 
        /*   0x0E   0x1E     0x0F     0x1A  *
         *   Stop   Pause  Previouse  Next  *
         *                                  */
 
-       [0x0E] = KEY_STOP,
-       [0x1E] = KEY_PAUSE,
-       [0x0F] = KEY_PREVIOUS,
-       [0x1A] = KEY_NEXT,
+       { 0x0E, KEY_STOP },
+       { 0x1E, KEY_PAUSE },
+       { 0x0F, KEY_PREVIOUS },
+       { 0x1A, KEY_NEXT },
+
+};
 
+struct ir_scancode_table ir_codes_behold_columbus_table = {
+       .scan = ir_codes_behold_columbus,
+       .size = ARRAY_SIZE(ir_codes_behold_columbus),
 };
-EXPORT_SYMBOL_GPL(ir_codes_behold_columbus);
+EXPORT_SYMBOL_GPL(ir_codes_behold_columbus_table);
 
 /*
  * Remote control for the Genius TVGO A11MCE
  * Adrian Pardini <pardo.bsso@gmail.com>
  */
-IR_KEYTAB_TYPE ir_codes_genius_tvgo_a11mce[IR_KEYTAB_SIZE] = {
+static struct ir_scancode ir_codes_genius_tvgo_a11mce[] = {
        /* Keys 0 to 9 */
-       [0x48] = KEY_0,
-       [0x09] = KEY_1,
-       [0x1d] = KEY_2,
-       [0x1f] = KEY_3,
-       [0x19] = KEY_4,
-       [0x1b] = KEY_5,
-       [0x11] = KEY_6,
-       [0x17] = KEY_7,
-       [0x12] = KEY_8,
-       [0x16] = KEY_9,
-
-       [0x54] = KEY_RECORD,            /* recording */
-       [0x06] = KEY_MUTE,              /* mute */
-       [0x10] = KEY_POWER,
-       [0x40] = KEY_LAST,              /* recall */
-       [0x4c] = KEY_CHANNELUP,         /* channel / program + */
-       [0x00] = KEY_CHANNELDOWN,       /* channel / program - */
-       [0x0d] = KEY_VOLUMEUP,
-       [0x15] = KEY_VOLUMEDOWN,
-       [0x4d] = KEY_OK,                /* also labeled as Pause */
-       [0x1c] = KEY_ZOOM,              /* full screen and Stop*/
-       [0x02] = KEY_MODE,              /* AV Source or Rewind*/
-       [0x04] = KEY_LIST,              /* -/-- */
+       { 0x48, KEY_0 },
+       { 0x09, KEY_1 },
+       { 0x1d, KEY_2 },
+       { 0x1f, KEY_3 },
+       { 0x19, KEY_4 },
+       { 0x1b, KEY_5 },
+       { 0x11, KEY_6 },
+       { 0x17, KEY_7 },
+       { 0x12, KEY_8 },
+       { 0x16, KEY_9 },
+
+       { 0x54, KEY_RECORD },           /* recording */
+       { 0x06, KEY_MUTE },             /* mute */
+       { 0x10, KEY_POWER },
+       { 0x40, KEY_LAST },             /* recall */
+       { 0x4c, KEY_CHANNELUP },        /* channel / program + */
+       { 0x00, KEY_CHANNELDOWN },      /* channel / program - */
+       { 0x0d, KEY_VOLUMEUP },
+       { 0x15, KEY_VOLUMEDOWN },
+       { 0x4d, KEY_OK },               /* also labeled as Pause */
+       { 0x1c, KEY_ZOOM },             /* full screen and Stop*/
+       { 0x02, KEY_MODE },             /* AV Source or Rewind*/
+       { 0x04, KEY_LIST },             /* -/-- */
        /* small arrows above numbers */
-       [0x1a] = KEY_NEXT,              /* also Fast Forward */
-       [0x0e] = KEY_PREVIOUS,  /* also Rewind */
+       { 0x1a, KEY_NEXT },             /* also Fast Forward */
+       { 0x0e, KEY_PREVIOUS },         /* also Rewind */
        /* these are in a rather non standard layout and have
        an alternate name written */
-       [0x1e] = KEY_UP,                /* Video Setting */
-       [0x0a] = KEY_DOWN,              /* Video Default */
-       [0x05] = KEY_LEFT,              /* Snapshot */
-       [0x0c] = KEY_RIGHT,             /* Hide Panel */
+       { 0x1e, KEY_UP },               /* Video Setting */
+       { 0x0a, KEY_DOWN },             /* Video Default */
+       { 0x05, KEY_CAMERA },           /* Snapshot */
+       { 0x0c, KEY_RIGHT },            /* Hide Panel */
        /* Four buttons without label */
-       [0x49] = KEY_RED,
-       [0x0b] = KEY_GREEN,
-       [0x13] = KEY_YELLOW,
-       [0x50] = KEY_BLUE,
+       { 0x49, KEY_RED },
+       { 0x0b, KEY_GREEN },
+       { 0x13, KEY_YELLOW },
+       { 0x50, KEY_BLUE },
+};
+
+struct ir_scancode_table ir_codes_genius_tvgo_a11mce_table = {
+       .scan = ir_codes_genius_tvgo_a11mce,
+       .size = ARRAY_SIZE(ir_codes_genius_tvgo_a11mce),
 };
-EXPORT_SYMBOL_GPL(ir_codes_genius_tvgo_a11mce);
+EXPORT_SYMBOL_GPL(ir_codes_genius_tvgo_a11mce_table);
 
 /*
  * Remote control for Powercolor Real Angel 330
  * Daniel Fraga <fragabr@gmail.com>
  */
-IR_KEYTAB_TYPE ir_codes_powercolor_real_angel[IR_KEYTAB_SIZE] = {
-       [0x38] = KEY_SWITCHVIDEOMODE,   /* switch inputs */
-       [0x0c] = KEY_MEDIA,             /* Turn ON/OFF App */
-       [0x00] = KEY_0,
-       [0x01] = KEY_1,
-       [0x02] = KEY_2,
-       [0x03] = KEY_3,
-       [0x04] = KEY_4,
-       [0x05] = KEY_5,
-       [0x06] = KEY_6,
-       [0x07] = KEY_7,
-       [0x08] = KEY_8,
-       [0x09] = KEY_9,
-       [0x0a] = KEY_DIGITS,            /* single, double, tripple digit */
-       [0x29] = KEY_PREVIOUS,          /* previous channel */
-       [0x12] = KEY_BRIGHTNESSUP,
-       [0x13] = KEY_BRIGHTNESSDOWN,
-       [0x2b] = KEY_MODE,              /* stereo/mono */
-       [0x2c] = KEY_TEXT,              /* teletext */
-       [0x20] = KEY_UP,                /* channel up */
-       [0x21] = KEY_DOWN,              /* channel down */
-       [0x10] = KEY_RIGHT,             /* volume up */
-       [0x11] = KEY_LEFT,              /* volume down */
-       [0x0d] = KEY_MUTE,
-       [0x1f] = KEY_RECORD,
-       [0x17] = KEY_PLAY,
-       [0x16] = KEY_PAUSE,
-       [0x0b] = KEY_STOP,
-       [0x27] = KEY_FASTFORWARD,
-       [0x26] = KEY_REWIND,
-       [0x1e] = KEY_SEARCH,            /* autoscan */
-       [0x0e] = KEY_SHUFFLE,           /* snapshot */
-       [0x2d] = KEY_SETUP,
-       [0x0f] = KEY_SCREEN,            /* full screen */
-       [0x14] = KEY_RADIO,             /* FM radio */
-       [0x25] = KEY_POWER,             /* power */
-};
-EXPORT_SYMBOL_GPL(ir_codes_powercolor_real_angel);
+static struct ir_scancode ir_codes_powercolor_real_angel[] = {
+       { 0x38, KEY_SWITCHVIDEOMODE },  /* switch inputs */
+       { 0x0c, KEY_MEDIA },            /* Turn ON/OFF App */
+       { 0x00, KEY_0 },
+       { 0x01, KEY_1 },
+       { 0x02, KEY_2 },
+       { 0x03, KEY_3 },
+       { 0x04, KEY_4 },
+       { 0x05, KEY_5 },
+       { 0x06, KEY_6 },
+       { 0x07, KEY_7 },
+       { 0x08, KEY_8 },
+       { 0x09, KEY_9 },
+       { 0x0a, KEY_DIGITS },           /* single, double, tripple digit */
+       { 0x29, KEY_PREVIOUS },         /* previous channel */
+       { 0x12, KEY_BRIGHTNESSUP },
+       { 0x13, KEY_BRIGHTNESSDOWN },
+       { 0x2b, KEY_MODE },             /* stereo/mono */
+       { 0x2c, KEY_TEXT },             /* teletext */
+       { 0x20, KEY_CHANNELUP },        /* channel up */
+       { 0x21, KEY_CHANNELDOWN },      /* channel down */
+       { 0x10, KEY_VOLUMEUP },         /* volume up */
+       { 0x11, KEY_VOLUMEDOWN },       /* volume down */
+       { 0x0d, KEY_MUTE },
+       { 0x1f, KEY_RECORD },
+       { 0x17, KEY_PLAY },
+       { 0x16, KEY_PAUSE },
+       { 0x0b, KEY_STOP },
+       { 0x27, KEY_FASTFORWARD },
+       { 0x26, KEY_REWIND },
+       { 0x1e, KEY_SEARCH },           /* autoscan */
+       { 0x0e, KEY_CAMERA },           /* snapshot */
+       { 0x2d, KEY_SETUP },
+       { 0x0f, KEY_SCREEN },           /* full screen */
+       { 0x14, KEY_RADIO },            /* FM radio */
+       { 0x25, KEY_POWER },            /* power */
+};
+
+struct ir_scancode_table ir_codes_powercolor_real_angel_table = {
+       .scan = ir_codes_powercolor_real_angel,
+       .size = ARRAY_SIZE(ir_codes_powercolor_real_angel),
+};
+EXPORT_SYMBOL_GPL(ir_codes_powercolor_real_angel_table);
 
 /* Kworld Plus TV Analog Lite PCI IR
    Mauro Carvalho Chehab <mchehab@infradead.org>
  */
-IR_KEYTAB_TYPE ir_codes_kworld_plus_tv_analog[IR_KEYTAB_SIZE] = {
-       [0x0c] = KEY_PROG1,             /* Kworld key */
-       [0x16] = KEY_CLOSECD,           /* -> ) */
-       [0x1d] = KEY_POWER2,
-
-       [0x00] = KEY_1,
-       [0x01] = KEY_2,
-       [0x02] = KEY_3,                 /* Two keys have the same code: 3 and left */
-       [0x03] = KEY_4,                 /* Two keys have the same code: 3 and right */
-       [0x04] = KEY_5,
-       [0x05] = KEY_6,
-       [0x06] = KEY_7,
-       [0x07] = KEY_8,
-       [0x08] = KEY_9,
-       [0x0a] = KEY_0,
-
-       [0x09] = KEY_AGAIN,
-       [0x14] = KEY_MUTE,
-
-       [0x20] = KEY_UP,
-       [0x21] = KEY_DOWN,
-       [0x0b] = KEY_ENTER,
-
-       [0x10] = KEY_CHANNELUP,
-       [0x11] = KEY_CHANNELDOWN,
+static struct ir_scancode ir_codes_kworld_plus_tv_analog[] = {
+       { 0x0c, KEY_PROG1 },            /* Kworld key */
+       { 0x16, KEY_CLOSECD },          /* -> ) */
+       { 0x1d, KEY_POWER2 },
+
+       { 0x00, KEY_1 },
+       { 0x01, KEY_2 },
+       { 0x02, KEY_3 },                /* Two keys have the same code: 3 and left */
+       { 0x03, KEY_4 },                /* Two keys have the same code: 3 and right */
+       { 0x04, KEY_5 },
+       { 0x05, KEY_6 },
+       { 0x06, KEY_7 },
+       { 0x07, KEY_8 },
+       { 0x08, KEY_9 },
+       { 0x0a, KEY_0 },
+
+       { 0x09, KEY_AGAIN },
+       { 0x14, KEY_MUTE },
+
+       { 0x20, KEY_UP },
+       { 0x21, KEY_DOWN },
+       { 0x0b, KEY_ENTER },
+
+       { 0x10, KEY_CHANNELUP },
+       { 0x11, KEY_CHANNELDOWN },
 
        /* Couldn't map key left/key right since those
           conflict with '3' and '4' scancodes
           I dunno what the original driver does
         */
 
-       [0x13] = KEY_VOLUMEUP,
-       [0x12] = KEY_VOLUMEDOWN,
+       { 0x13, KEY_VOLUMEUP },
+       { 0x12, KEY_VOLUMEDOWN },
 
        /* The lower part of the IR
           There are several duplicated keycodes there.
@@ -2496,280 +2682,468 @@ IR_KEYTAB_TYPE ir_codes_kworld_plus_tv_analog[IR_KEYTAB_SIZE] = {
           Also, it is not related to the time between keyup
           and keydown.
         */
-       [0x19] = KEY_PAUSE,             /* Timeshift */
-       [0x1a] = KEY_STOP,
-       [0x1b] = KEY_RECORD,
+       { 0x19, KEY_TIME},              /* Timeshift */
+       { 0x1a, KEY_STOP},
+       { 0x1b, KEY_RECORD},
 
-       [0x22] = KEY_TEXT,
+       { 0x22, KEY_TEXT},
 
-       [0x15] = KEY_AUDIO,             /* ((*)) */
-       [0x0f] = KEY_ZOOM,
-       [0x1c] = KEY_SHUFFLE,           /* snapshot */
+       { 0x15, KEY_AUDIO},             /* ((*)) */
+       { 0x0f, KEY_ZOOM},
+       { 0x1c, KEY_CAMERA},            /* snapshot */
 
-       [0x18] = KEY_RED,               /* B */
-       [0x23] = KEY_GREEN,             /* C */
+       { 0x18, KEY_RED},               /* B */
+       { 0x23, KEY_GREEN},             /* C */
 };
-EXPORT_SYMBOL_GPL(ir_codes_kworld_plus_tv_analog);
+struct ir_scancode_table ir_codes_kworld_plus_tv_analog_table = {
+       .scan = ir_codes_kworld_plus_tv_analog,
+       .size = ARRAY_SIZE(ir_codes_kworld_plus_tv_analog),
+};
+EXPORT_SYMBOL_GPL(ir_codes_kworld_plus_tv_analog_table);
 
 /* Kaiomy TVnPC U2
    Mauro Carvalho Chehab <mchehab@infradead.org>
  */
-IR_KEYTAB_TYPE ir_codes_kaiomy[IR_KEYTAB_SIZE] = {
-       [0x43] = KEY_POWER2,
-       [0x01] = KEY_LIST,
-       [0x0b] = KEY_ZOOM,
-       [0x03] = KEY_POWER,
-
-       [0x04] = KEY_1,
-       [0x08] = KEY_2,
-       [0x02] = KEY_3,
-
-       [0x0f] = KEY_4,
-       [0x05] = KEY_5,
-       [0x06] = KEY_6,
-
-       [0x0c] = KEY_7,
-       [0x0d] = KEY_8,
-       [0x0a] = KEY_9,
-
-       [0x11] = KEY_0,
-
-       [0x09] = KEY_CHANNELUP,
-       [0x07] = KEY_CHANNELDOWN,
-
-       [0x0e] = KEY_VOLUMEUP,
-       [0x13] = KEY_VOLUMEDOWN,
-
-       [0x10] = KEY_HOME,
-       [0x12] = KEY_ENTER,
-
-       [0x14] = KEY_RECORD,
-       [0x15] = KEY_STOP,
-       [0x16] = KEY_PLAY,
-       [0x17] = KEY_MUTE,
-
-       [0x18] = KEY_UP,
-       [0x19] = KEY_DOWN,
-       [0x1a] = KEY_LEFT,
-       [0x1b] = KEY_RIGHT,
-
-       [0x1c] = KEY_RED,
-       [0x1d] = KEY_GREEN,
-       [0x1e] = KEY_YELLOW,
-       [0x1f] = KEY_BLUE,
-};
-EXPORT_SYMBOL_GPL(ir_codes_kaiomy);
-
-IR_KEYTAB_TYPE ir_codes_avermedia_a16d[IR_KEYTAB_SIZE] = {
-       [0x20] = KEY_LIST,
-       [0x00] = KEY_POWER,
-       [0x28] = KEY_1,
-       [0x18] = KEY_2,
-       [0x38] = KEY_3,
-       [0x24] = KEY_4,
-       [0x14] = KEY_5,
-       [0x34] = KEY_6,
-       [0x2c] = KEY_7,
-       [0x1c] = KEY_8,
-       [0x3c] = KEY_9,
-       [0x12] = KEY_SUBTITLE,
-       [0x22] = KEY_0,
-       [0x32] = KEY_REWIND,
-       [0x3a] = KEY_SHUFFLE,
-       [0x02] = KEY_PRINT,
-       [0x11] = KEY_CHANNELDOWN,
-       [0x31] = KEY_CHANNELUP,
-       [0x0c] = KEY_ZOOM,
-       [0x1e] = KEY_VOLUMEDOWN,
-       [0x3e] = KEY_VOLUMEUP,
-       [0x0a] = KEY_MUTE,
-       [0x04] = KEY_AUDIO,
-       [0x26] = KEY_RECORD,
-       [0x06] = KEY_PLAY,
-       [0x36] = KEY_STOP,
-       [0x16] = KEY_PAUSE,
-       [0x2e] = KEY_REWIND,
-       [0x0e] = KEY_FASTFORWARD,
-       [0x30] = KEY_TEXT,
-       [0x21] = KEY_GREEN,
-       [0x01] = KEY_BLUE,
-       [0x08] = KEY_EPG,
-       [0x2a] = KEY_MENU,
-};
-EXPORT_SYMBOL_GPL(ir_codes_avermedia_a16d);
+static struct ir_scancode ir_codes_kaiomy[] = {
+       { 0x43, KEY_POWER2},
+       { 0x01, KEY_LIST},
+       { 0x0b, KEY_ZOOM},
+       { 0x03, KEY_POWER},
 
-/* Encore ENLTV-FM v5.3
-   Mauro Carvalho Chehab <mchehab@infradead.org>
- */
-IR_KEYTAB_TYPE ir_codes_encore_enltv_fm53[IR_KEYTAB_SIZE] = {
-       [0x10] = KEY_POWER2,
-       [0x06] = KEY_MUTE,
-
-       [0x09] = KEY_1,
-       [0x1d] = KEY_2,
-       [0x1f] = KEY_3,
-       [0x19] = KEY_4,
-       [0x1b] = KEY_5,
-       [0x11] = KEY_6,
-       [0x17] = KEY_7,
-       [0x12] = KEY_8,
-       [0x16] = KEY_9,
-       [0x48] = KEY_0,
-
-       [0x04] = KEY_LIST,              /* -/-- */
-       [0x40] = KEY_LAST,              /* recall */
-
-       [0x02] = KEY_MODE,              /* TV/AV */
-       [0x05] = KEY_SHUFFLE,           /* SNAPSHOT */
-
-       [0x4c] = KEY_CHANNELUP,         /* UP */
-       [0x00] = KEY_CHANNELDOWN,       /* DOWN */
-       [0x0d] = KEY_VOLUMEUP,          /* RIGHT */
-       [0x15] = KEY_VOLUMEDOWN,        /* LEFT */
-       [0x49] = KEY_ENTER,             /* OK */
-
-       [0x54] = KEY_RECORD,
-       [0x4d] = KEY_PLAY,              /* pause */
-
-       [0x1e] = KEY_UP,                /* video setting */
-       [0x0e] = KEY_RIGHT,             /* <- */
-       [0x1a] = KEY_LEFT,              /* -> */
-
-       [0x0a] = KEY_DOWN,              /* video default */
-       [0x0c] = KEY_ZOOM,              /* hide pannel */
-       [0x47] = KEY_SLEEP,             /* shutdown */
-};
-EXPORT_SYMBOL_GPL(ir_codes_encore_enltv_fm53);
+       { 0x04, KEY_1},
+       { 0x08, KEY_2},
+       { 0x02, KEY_3},
 
-/* Zogis Real Audio 220 - 32 keys IR */
-IR_KEYTAB_TYPE ir_codes_real_audio_220_32_keys[IR_KEYTAB_SIZE] = {
-       [0x1c] = KEY_RADIO,
-       [0x12] = KEY_POWER2,
+       { 0x0f, KEY_4},
+       { 0x05, KEY_5},
+       { 0x06, KEY_6},
+
+       { 0x0c, KEY_7},
+       { 0x0d, KEY_8},
+       { 0x0a, KEY_9},
 
-       [0x01] = KEY_1,
-       [0x02] = KEY_2,
-       [0x03] = KEY_3,
-       [0x04] = KEY_4,
-       [0x05] = KEY_5,
-       [0x06] = KEY_6,
-       [0x07] = KEY_7,
-       [0x08] = KEY_8,
-       [0x09] = KEY_9,
-       [0x00] = KEY_0,
+       { 0x11, KEY_0},
 
-       [0x0c] = KEY_VOLUMEUP,
-       [0x18] = KEY_VOLUMEDOWN,
-       [0x0b] = KEY_CHANNELUP,
-       [0x15] = KEY_CHANNELDOWN,
-       [0x16] = KEY_ENTER,
+       { 0x09, KEY_CHANNELUP},
+       { 0x07, KEY_CHANNELDOWN},
 
-       [0x11] = KEY_LIST,              /* Source */
-       [0x0d] = KEY_AUDIO,             /* stereo */
+       { 0x0e, KEY_VOLUMEUP},
+       { 0x13, KEY_VOLUMEDOWN},
 
-       [0x0f] = KEY_PREVIOUS,          /* Prev */
-       [0x1b] = KEY_PAUSE,             /* Timeshift */
-       [0x1a] = KEY_NEXT,              /* Next */
+       { 0x10, KEY_HOME},
+       { 0x12, KEY_ENTER},
 
-       [0x0e] = KEY_STOP,
-       [0x1f] = KEY_PLAY,
-       [0x1e] = KEY_PLAYPAUSE,         /* Pause */
+       { 0x14, KEY_RECORD},
+       { 0x15, KEY_STOP},
+       { 0x16, KEY_PLAY},
+       { 0x17, KEY_MUTE},
 
-       [0x1d] = KEY_RECORD,
-       [0x13] = KEY_MUTE,
-       [0x19] = KEY_SHUFFLE,           /* Snapshot */
+       { 0x18, KEY_UP},
+       { 0x19, KEY_DOWN},
+       { 0x1a, KEY_LEFT},
+       { 0x1b, KEY_RIGHT},
 
+       { 0x1c, KEY_RED},
+       { 0x1d, KEY_GREEN},
+       { 0x1e, KEY_YELLOW},
+       { 0x1f, KEY_BLUE},
+};
+struct ir_scancode_table ir_codes_kaiomy_table = {
+       .scan = ir_codes_kaiomy,
+       .size = ARRAY_SIZE(ir_codes_kaiomy),
+};
+EXPORT_SYMBOL_GPL(ir_codes_kaiomy_table);
+
+static struct ir_scancode ir_codes_avermedia_a16d[] = {
+       { 0x20, KEY_LIST},
+       { 0x00, KEY_POWER},
+       { 0x28, KEY_1},
+       { 0x18, KEY_2},
+       { 0x38, KEY_3},
+       { 0x24, KEY_4},
+       { 0x14, KEY_5},
+       { 0x34, KEY_6},
+       { 0x2c, KEY_7},
+       { 0x1c, KEY_8},
+       { 0x3c, KEY_9},
+       { 0x12, KEY_SUBTITLE},
+       { 0x22, KEY_0},
+       { 0x32, KEY_REWIND},
+       { 0x3a, KEY_SHUFFLE},
+       { 0x02, KEY_PRINT},
+       { 0x11, KEY_CHANNELDOWN},
+       { 0x31, KEY_CHANNELUP},
+       { 0x0c, KEY_ZOOM},
+       { 0x1e, KEY_VOLUMEDOWN},
+       { 0x3e, KEY_VOLUMEUP},
+       { 0x0a, KEY_MUTE},
+       { 0x04, KEY_AUDIO},
+       { 0x26, KEY_RECORD},
+       { 0x06, KEY_PLAY},
+       { 0x36, KEY_STOP},
+       { 0x16, KEY_PAUSE},
+       { 0x2e, KEY_REWIND},
+       { 0x0e, KEY_FASTFORWARD},
+       { 0x30, KEY_TEXT},
+       { 0x21, KEY_GREEN},
+       { 0x01, KEY_BLUE},
+       { 0x08, KEY_EPG},
+       { 0x2a, KEY_MENU},
+};
+struct ir_scancode_table ir_codes_avermedia_a16d_table = {
+       .scan = ir_codes_avermedia_a16d,
+       .size = ARRAY_SIZE(ir_codes_avermedia_a16d),
 };
-EXPORT_SYMBOL_GPL(ir_codes_real_audio_220_32_keys);
+EXPORT_SYMBOL_GPL(ir_codes_avermedia_a16d_table);
+
+/* Encore ENLTV-FM v5.3
+   Mauro Carvalho Chehab <mchehab@infradead.org>
+ */
+static struct ir_scancode ir_codes_encore_enltv_fm53[] = {
+       { 0x10, KEY_POWER2},
+       { 0x06, KEY_MUTE},
+
+       { 0x09, KEY_1},
+       { 0x1d, KEY_2},
+       { 0x1f, KEY_3},
+       { 0x19, KEY_4},
+       { 0x1b, KEY_5},
+       { 0x11, KEY_6},
+       { 0x17, KEY_7},
+       { 0x12, KEY_8},
+       { 0x16, KEY_9},
+       { 0x48, KEY_0},
+
+       { 0x04, KEY_LIST},              /* -/-- */
+       { 0x40, KEY_LAST},              /* recall */
+
+       { 0x02, KEY_MODE},              /* TV/AV */
+       { 0x05, KEY_CAMERA},            /* SNAPSHOT */
+
+       { 0x4c, KEY_CHANNELUP},         /* UP */
+       { 0x00, KEY_CHANNELDOWN},       /* DOWN */
+       { 0x0d, KEY_VOLUMEUP},          /* RIGHT */
+       { 0x15, KEY_VOLUMEDOWN},        /* LEFT */
+       { 0x49, KEY_ENTER},             /* OK */
+
+       { 0x54, KEY_RECORD},
+       { 0x4d, KEY_PLAY},              /* pause */
+
+       { 0x1e, KEY_MENU},              /* video setting */
+       { 0x0e, KEY_RIGHT},             /* <- */
+       { 0x1a, KEY_LEFT},              /* -> */
+
+       { 0x0a, KEY_CLEAR},             /* video default */
+       { 0x0c, KEY_ZOOM},              /* hide pannel */
+       { 0x47, KEY_SLEEP},             /* shutdown */
+};
+struct ir_scancode_table ir_codes_encore_enltv_fm53_table = {
+       .scan = ir_codes_encore_enltv_fm53,
+       .size = ARRAY_SIZE(ir_codes_encore_enltv_fm53),
+};
+EXPORT_SYMBOL_GPL(ir_codes_encore_enltv_fm53_table);
+
+/* Zogis Real Audio 220 - 32 keys IR */
+static struct ir_scancode ir_codes_real_audio_220_32_keys[] = {
+       { 0x1c, KEY_RADIO},
+       { 0x12, KEY_POWER2},
+
+       { 0x01, KEY_1},
+       { 0x02, KEY_2},
+       { 0x03, KEY_3},
+       { 0x04, KEY_4},
+       { 0x05, KEY_5},
+       { 0x06, KEY_6},
+       { 0x07, KEY_7},
+       { 0x08, KEY_8},
+       { 0x09, KEY_9},
+       { 0x00, KEY_0},
+
+       { 0x0c, KEY_VOLUMEUP},
+       { 0x18, KEY_VOLUMEDOWN},
+       { 0x0b, KEY_CHANNELUP},
+       { 0x15, KEY_CHANNELDOWN},
+       { 0x16, KEY_ENTER},
+
+       { 0x11, KEY_LIST},              /* Source */
+       { 0x0d, KEY_AUDIO},             /* stereo */
+
+       { 0x0f, KEY_PREVIOUS},          /* Prev */
+       { 0x1b, KEY_TIME},              /* Timeshift */
+       { 0x1a, KEY_NEXT},              /* Next */
+
+       { 0x0e, KEY_STOP},
+       { 0x1f, KEY_PLAY},
+       { 0x1e, KEY_PLAYPAUSE},         /* Pause */
+
+       { 0x1d, KEY_RECORD},
+       { 0x13, KEY_MUTE},
+       { 0x19, KEY_CAMERA},            /* Snapshot */
+
+};
+struct ir_scancode_table ir_codes_real_audio_220_32_keys_table = {
+       .scan = ir_codes_real_audio_220_32_keys,
+       .size = ARRAY_SIZE(ir_codes_real_audio_220_32_keys),
+};
+EXPORT_SYMBOL_GPL(ir_codes_real_audio_220_32_keys_table);
 
 /* ATI TV Wonder HD 600 USB
    Devin Heitmueller <devin.heitmueller@gmail.com>
  */
-IR_KEYTAB_TYPE ir_codes_ati_tv_wonder_hd_600[IR_KEYTAB_SIZE] = {
-       [0x00] = KEY_RECORD,            /* Row 1 */
-       [0x01] = KEY_PLAYPAUSE,
-       [0x02] = KEY_STOP,
-       [0x03] = KEY_POWER,
-       [0x04] = KEY_PREVIOUS,  /* Row 2 */
-       [0x05] = KEY_REWIND,
-       [0x06] = KEY_FORWARD,
-       [0x07] = KEY_NEXT,
-       [0x08] = KEY_EPG,               /* Row 3 */
-       [0x09] = KEY_HOME,
-       [0x0a] = KEY_MENU,
-       [0x0b] = KEY_CHANNELUP,
-       [0x0c] = KEY_BACK,              /* Row 4 */
-       [0x0d] = KEY_UP,
-       [0x0e] = KEY_INFO,
-       [0x0f] = KEY_CHANNELDOWN,
-       [0x10] = KEY_LEFT,              /* Row 5 */
-       [0x11] = KEY_SELECT,
-       [0x12] = KEY_RIGHT,
-       [0x13] = KEY_VOLUMEUP,
-       [0x14] = KEY_LAST,              /* Row 6 */
-       [0x15] = KEY_DOWN,
-       [0x16] = KEY_MUTE,
-       [0x17] = KEY_VOLUMEDOWN,
-};
-
-EXPORT_SYMBOL_GPL(ir_codes_ati_tv_wonder_hd_600);
+static struct ir_scancode ir_codes_ati_tv_wonder_hd_600[] = {
+       { 0x00, KEY_RECORD},            /* Row 1 */
+       { 0x01, KEY_PLAYPAUSE},
+       { 0x02, KEY_STOP},
+       { 0x03, KEY_POWER},
+       { 0x04, KEY_PREVIOUS},  /* Row 2 */
+       { 0x05, KEY_REWIND},
+       { 0x06, KEY_FORWARD},
+       { 0x07, KEY_NEXT},
+       { 0x08, KEY_EPG},               /* Row 3 */
+       { 0x09, KEY_HOME},
+       { 0x0a, KEY_MENU},
+       { 0x0b, KEY_CHANNELUP},
+       { 0x0c, KEY_BACK},              /* Row 4 */
+       { 0x0d, KEY_UP},
+       { 0x0e, KEY_INFO},
+       { 0x0f, KEY_CHANNELDOWN},
+       { 0x10, KEY_LEFT},              /* Row 5 */
+       { 0x11, KEY_SELECT},
+       { 0x12, KEY_RIGHT},
+       { 0x13, KEY_VOLUMEUP},
+       { 0x14, KEY_LAST},              /* Row 6 */
+       { 0x15, KEY_DOWN},
+       { 0x16, KEY_MUTE},
+       { 0x17, KEY_VOLUMEDOWN},
+};
+struct ir_scancode_table ir_codes_ati_tv_wonder_hd_600_table = {
+       .scan = ir_codes_ati_tv_wonder_hd_600,
+       .size = ARRAY_SIZE(ir_codes_ati_tv_wonder_hd_600),
+};
+EXPORT_SYMBOL_GPL(ir_codes_ati_tv_wonder_hd_600_table);
 
 /* DVBWorld remotes
    Igor M. Liplianin <liplianin@me.by>
  */
-IR_KEYTAB_TYPE ir_codes_dm1105_nec[IR_KEYTAB_SIZE] = {
-       [0x0a] = KEY_Q,         /*power*/
-       [0x0c] = KEY_M,         /*mute*/
-       [0x11] = KEY_1,
-       [0x12] = KEY_2,
-       [0x13] = KEY_3,
-       [0x14] = KEY_4,
-       [0x15] = KEY_5,
-       [0x16] = KEY_6,
-       [0x17] = KEY_7,
-       [0x18] = KEY_8,
-       [0x19] = KEY_9,
-       [0x10] = KEY_0,
-       [0x1c] = KEY_PAGEUP,    /*ch+*/
-       [0x0f] = KEY_PAGEDOWN,  /*ch-*/
-       [0x1a] = KEY_O,         /*vol+*/
-       [0x0e] = KEY_Z,         /*vol-*/
-       [0x04] = KEY_R,         /*rec*/
-       [0x09] = KEY_D,         /*fav*/
-       [0x08] = KEY_BACKSPACE, /*rewind*/
-       [0x07] = KEY_A,         /*fast*/
-       [0x0b] = KEY_P,         /*pause*/
-       [0x02] = KEY_ESC,       /*cancel*/
-       [0x03] = KEY_G,         /*tab*/
-       [0x00] = KEY_UP,        /*up*/
-       [0x1f] = KEY_ENTER,     /*ok*/
-       [0x01] = KEY_DOWN,      /*down*/
-       [0x05] = KEY_C,         /*cap*/
-       [0x06] = KEY_S,         /*stop*/
-       [0x40] = KEY_F,         /*full*/
-       [0x1e] = KEY_W,         /*tvmode*/
-       [0x1b] = KEY_B,         /*recall*/
-};
-EXPORT_SYMBOL_GPL(ir_codes_dm1105_nec);
+static struct ir_scancode ir_codes_dm1105_nec[] = {
+       { 0x0a, KEY_POWER2},            /* power */
+       { 0x0c, KEY_MUTE},              /* mute */
+       { 0x11, KEY_1},
+       { 0x12, KEY_2},
+       { 0x13, KEY_3},
+       { 0x14, KEY_4},
+       { 0x15, KEY_5},
+       { 0x16, KEY_6},
+       { 0x17, KEY_7},
+       { 0x18, KEY_8},
+       { 0x19, KEY_9},
+       { 0x10, KEY_0},
+       { 0x1c, KEY_CHANNELUP},         /* ch+ */
+       { 0x0f, KEY_CHANNELDOWN},       /* ch- */
+       { 0x1a, KEY_VOLUMEUP},          /* vol+ */
+       { 0x0e, KEY_VOLUMEDOWN},        /* vol- */
+       { 0x04, KEY_RECORD},            /* rec */
+       { 0x09, KEY_CHANNEL},           /* fav */
+       { 0x08, KEY_BACKSPACE},         /* rewind */
+       { 0x07, KEY_FASTFORWARD},       /* fast */
+       { 0x0b, KEY_PAUSE},             /* pause */
+       { 0x02, KEY_ESC},               /* cancel */
+       { 0x03, KEY_TAB},               /* tab */
+       { 0x00, KEY_UP},                /* up */
+       { 0x1f, KEY_ENTER},             /* ok */
+       { 0x01, KEY_DOWN},              /* down */
+       { 0x05, KEY_RECORD},            /* cap */
+       { 0x06, KEY_STOP},              /* stop */
+       { 0x40, KEY_ZOOM},              /* full */
+       { 0x1e, KEY_TV},                /* tvmode */
+       { 0x1b, KEY_B},                 /* recall */
+};
+struct ir_scancode_table ir_codes_dm1105_nec_table = {
+       .scan = ir_codes_dm1105_nec,
+       .size = ARRAY_SIZE(ir_codes_dm1105_nec),
+};
+EXPORT_SYMBOL_GPL(ir_codes_dm1105_nec_table);
+
+/* Terratec Cinergy Hybrid T USB XS
+   Devin Heitmueller <dheitmueller@linuxtv.org>
+ */
+static struct ir_scancode ir_codes_terratec_cinergy_xs[] = {
+       { 0x41, KEY_HOME},
+       { 0x01, KEY_POWER},
+       { 0x42, KEY_MENU},
+       { 0x02, KEY_1},
+       { 0x03, KEY_2},
+       { 0x04, KEY_3},
+       { 0x43, KEY_SUBTITLE},
+       { 0x05, KEY_4},
+       { 0x06, KEY_5},
+       { 0x07, KEY_6},
+       { 0x44, KEY_TEXT},
+       { 0x08, KEY_7},
+       { 0x09, KEY_8},
+       { 0x0a, KEY_9},
+       { 0x45, KEY_DELETE},
+       { 0x0b, KEY_TUNER},
+       { 0x0c, KEY_0},
+       { 0x0d, KEY_MODE},
+       { 0x46, KEY_TV},
+       { 0x47, KEY_DVD},
+       { 0x49, KEY_VIDEO},
+       { 0x4b, KEY_AUX},
+       { 0x10, KEY_UP},
+       { 0x11, KEY_LEFT},
+       { 0x12, KEY_OK},
+       { 0x13, KEY_RIGHT},
+       { 0x14, KEY_DOWN},
+       { 0x0f, KEY_EPG},
+       { 0x16, KEY_INFO},
+       { 0x4d, KEY_BACKSPACE},
+       { 0x1c, KEY_VOLUMEUP},
+       { 0x4c, KEY_PLAY},
+       { 0x1b, KEY_CHANNELUP},
+       { 0x1e, KEY_VOLUMEDOWN},
+       { 0x1d, KEY_MUTE},
+       { 0x1f, KEY_CHANNELDOWN},
+       { 0x17, KEY_RED},
+       { 0x18, KEY_GREEN},
+       { 0x19, KEY_YELLOW},
+       { 0x1a, KEY_BLUE},
+       { 0x58, KEY_RECORD},
+       { 0x48, KEY_STOP},
+       { 0x40, KEY_PAUSE},
+       { 0x54, KEY_LAST},
+       { 0x4e, KEY_REWIND},
+       { 0x4f, KEY_FASTFORWARD},
+       { 0x5c, KEY_NEXT},
+};
+struct ir_scancode_table ir_codes_terratec_cinergy_xs_table = {
+       .scan = ir_codes_terratec_cinergy_xs,
+       .size = ARRAY_SIZE(ir_codes_terratec_cinergy_xs),
+};
+EXPORT_SYMBOL_GPL(ir_codes_terratec_cinergy_xs_table);
 
 /* EVGA inDtube
    Devin Heitmueller <devin.heitmueller@gmail.com>
  */
-IR_KEYTAB_TYPE ir_codes_evga_indtube[IR_KEYTAB_SIZE] = {
-       [0x12] = KEY_POWER,
-       [0x02] = KEY_MODE,      /* TV */
-       [0x14] = KEY_MUTE,
-       [0x1a] = KEY_CHANNELUP,
-       [0x16] = KEY_TV2,       /* PIP */
-       [0x1d] = KEY_VOLUMEUP,
-       [0x05] = KEY_CHANNELDOWN,
-       [0x0f] = KEY_PLAYPAUSE,
-       [0x19] = KEY_VOLUMEDOWN,
-       [0x1c] = KEY_REWIND,
-       [0x0d] = KEY_RECORD,
-       [0x18] = KEY_FORWARD,
-       [0x1e] = KEY_PREVIOUS,
-       [0x1b] = KEY_STOP,
-       [0x1f] = KEY_NEXT,
-       [0x13] = KEY_CAMERA,
-};
-EXPORT_SYMBOL_GPL(ir_codes_evga_indtube);
+static struct ir_scancode ir_codes_evga_indtube[] = {
+       { 0x12, KEY_POWER},
+       { 0x02, KEY_MODE},      /* TV */
+       { 0x14, KEY_MUTE},
+       { 0x1a, KEY_CHANNELUP},
+       { 0x16, KEY_TV2},       /* PIP */
+       { 0x1d, KEY_VOLUMEUP},
+       { 0x05, KEY_CHANNELDOWN},
+       { 0x0f, KEY_PLAYPAUSE},
+       { 0x19, KEY_VOLUMEDOWN},
+       { 0x1c, KEY_REWIND},
+       { 0x0d, KEY_RECORD},
+       { 0x18, KEY_FORWARD},
+       { 0x1e, KEY_PREVIOUS},
+       { 0x1b, KEY_STOP},
+       { 0x1f, KEY_NEXT},
+       { 0x13, KEY_CAMERA},
+};
+struct ir_scancode_table ir_codes_evga_indtube_table = {
+       .scan = ir_codes_evga_indtube,
+       .size = ARRAY_SIZE(ir_codes_evga_indtube),
+};
+EXPORT_SYMBOL_GPL(ir_codes_evga_indtube_table);
+
+static struct ir_scancode ir_codes_videomate_s350[] = {
+       { 0x00, KEY_TV},
+       { 0x01, KEY_DVD},
+       { 0x04, KEY_RECORD},
+       { 0x05, KEY_VIDEO},     /* TV/Video */
+       { 0x07, KEY_STOP},
+       { 0x08, KEY_PLAYPAUSE},
+       { 0x0a, KEY_REWIND},
+       { 0x0f, KEY_FASTFORWARD},
+       { 0x10, KEY_CHANNELUP},
+       { 0x12, KEY_VOLUMEUP},
+       { 0x13, KEY_CHANNELDOWN},
+       { 0x14, KEY_MUTE},
+       { 0x15, KEY_VOLUMEDOWN},
+       { 0x16, KEY_1},
+       { 0x17, KEY_2},
+       { 0x18, KEY_3},
+       { 0x19, KEY_4},
+       { 0x1a, KEY_5},
+       { 0x1b, KEY_6},
+       { 0x1c, KEY_7},
+       { 0x1d, KEY_8},
+       { 0x1e, KEY_9},
+       { 0x1f, KEY_0},
+       { 0x21, KEY_SLEEP},
+       { 0x24, KEY_ZOOM},
+       { 0x25, KEY_LAST},      /* Recall */
+       { 0x26, KEY_SUBTITLE},  /* CC */
+       { 0x27, KEY_LANGUAGE},  /* MTS */
+       { 0x29, KEY_CHANNEL},   /* SURF */
+       { 0x2b, KEY_A},
+       { 0x2c, KEY_B},
+       { 0x2f, KEY_CAMERA},    /* Snapshot */
+       { 0x23, KEY_RADIO},
+       { 0x02, KEY_PREVIOUSSONG},
+       { 0x06, KEY_NEXTSONG},
+       { 0x03, KEY_EPG},
+       { 0x09, KEY_SETUP},
+       { 0x22, KEY_BACKSPACE},
+       { 0x0c, KEY_UP},
+       { 0x0e, KEY_DOWN},
+       { 0x0b, KEY_LEFT},
+       { 0x0d, KEY_RIGHT},
+       { 0x11, KEY_ENTER},
+       { 0x20, KEY_TEXT},
+};
+struct ir_scancode_table ir_codes_videomate_s350_table = {
+       .scan = ir_codes_videomate_s350,
+       .size = ARRAY_SIZE(ir_codes_videomate_s350),
+};
+EXPORT_SYMBOL_GPL(ir_codes_videomate_s350_table);
+
+/* GADMEI UTV330+ RM008Z remote
+   Shine Liu <shinel@foxmail.com>
+ */
+static struct ir_scancode ir_codes_gadmei_rm008z[] = {
+       { 0x14, KEY_POWER2},            /* POWER OFF */
+       { 0x0c, KEY_MUTE},              /* MUTE */
+
+       { 0x18, KEY_TV},                /* TV */
+       { 0x0e, KEY_VIDEO},             /* AV */
+       { 0x0b, KEY_AUDIO},             /* SV */
+       { 0x0f, KEY_RADIO},             /* FM */
+
+       { 0x00, KEY_1},
+       { 0x01, KEY_2},
+       { 0x02, KEY_3},
+       { 0x03, KEY_4},
+       { 0x04, KEY_5},
+       { 0x05, KEY_6},
+       { 0x06, KEY_7},
+       { 0x07, KEY_8},
+       { 0x08, KEY_9},
+       { 0x09, KEY_0},
+       { 0x0a, KEY_INFO},              /* OSD */
+       { 0x1c, KEY_BACKSPACE},         /* LAST */
+
+       { 0x0d, KEY_PLAY},              /* PLAY */
+       { 0x1e, KEY_CAMERA},            /* SNAPSHOT */
+       { 0x1a, KEY_RECORD},            /* RECORD */
+       { 0x17, KEY_STOP},              /* STOP */
+
+       { 0x1f, KEY_UP},                /* UP */
+       { 0x44, KEY_DOWN},              /* DOWN */
+       { 0x46, KEY_TAB},               /* BACK */
+       { 0x4a, KEY_ZOOM},              /* FULLSECREEN */
+
+       { 0x10, KEY_VOLUMEUP},          /* VOLUMEUP */
+       { 0x11, KEY_VOLUMEDOWN},        /* VOLUMEDOWN */
+       { 0x12, KEY_CHANNELUP},         /* CHANNELUP */
+       { 0x13, KEY_CHANNELDOWN},       /* CHANNELDOWN */
+       { 0x15, KEY_ENTER},             /* OK */
+};
+struct ir_scancode_table ir_codes_gadmei_rm008z_table = {
+       .scan = ir_codes_gadmei_rm008z,
+       .size = ARRAY_SIZE(ir_codes_gadmei_rm008z),
+};
+EXPORT_SYMBOL_GPL(ir_codes_gadmei_rm008z_table);
index b10935630154f94b4845c15f4abf314cdf9eb4ee..bc4b004ba7dbed45f3a07ff0ef4d4411fa159737 100644 (file)
@@ -27,7 +27,7 @@ module_param_named(debug, tda18271_debug, int, 0644);
 MODULE_PARM_DESC(debug, "set debug level "
                 "(info=1, map=2, reg=4, adv=8, cal=16 (or-able))");
 
-static int tda18271_cal_on_startup;
+static int tda18271_cal_on_startup = -1;
 module_param_named(cal, tda18271_cal_on_startup, int, 0644);
 MODULE_PARM_DESC(cal, "perform RF tracking filter calibration on startup");
 
@@ -1192,10 +1192,25 @@ struct dvb_frontend *tda18271_attach(struct dvb_frontend *fe, u8 addr,
        case 0:
                goto fail;
        case 1:
+       {
                /* new tuner instance */
+               int rf_cal_on_startup;
+
                priv->gate = (cfg) ? cfg->gate : TDA18271_GATE_AUTO;
                priv->role = (cfg) ? cfg->role : TDA18271_MASTER;
                priv->config = (cfg) ? cfg->config : 0;
+
+               /* tda18271_cal_on_startup == -1 when cal
+                * module option is unset */
+               if (tda18271_cal_on_startup == -1) {
+                       /* honor attach-time configuration */
+                       rf_cal_on_startup =
+                               ((cfg) && (cfg->rf_cal_on_startup)) ? 1 : 0;
+               } else {
+                       /* module option overrides attach configuration */
+                       rf_cal_on_startup = tda18271_cal_on_startup;
+               }
+
                priv->cal_initialized = false;
                mutex_init(&priv->lock);
 
@@ -1213,11 +1228,12 @@ struct dvb_frontend *tda18271_attach(struct dvb_frontend *fe, u8 addr,
                mutex_lock(&priv->lock);
                tda18271_init_regs(fe);
 
-               if ((tda18271_cal_on_startup) && (priv->id == TDA18271HDC2))
+               if ((rf_cal_on_startup) && (priv->id == TDA18271HDC2))
                        tda18271c2_rf_cal_init(fe);
 
                mutex_unlock(&priv->lock);
                break;
+       }
        default:
                /* existing tuner instance */
                fe->tuner_priv = priv;
index 74beb28806f85bef0cb7ad13cf06bcb0804b1547..e6a80ad0935688a1ddae48a4e1c4655114fe357b 100644 (file)
@@ -137,17 +137,17 @@ extern int tda18271_debug;
 #define tda_printk(kern, fmt, arg...) \
        printk(kern "%s: " fmt, __func__, ##arg)
 
-#define dprintk(kern, lvl, fmt, arg...) do {\
+#define tda_dprintk(lvl, fmt, arg...) do {\
        if (tda18271_debug & lvl) \
-               tda_printk(kern, fmt, ##arg); } while (0)
-
-#define tda_info(fmt, arg...) printk(KERN_INFO              fmt, ##arg)
-#define tda_warn(fmt, arg...) tda_printk(KERN_WARNING,      fmt, ##arg)
-#define tda_err(fmt, arg...)  tda_printk(KERN_ERR,          fmt, ##arg)
-#define tda_dbg(fmt, arg...)  dprintk(KERN_DEBUG, DBG_INFO, fmt, ##arg)
-#define tda_map(fmt, arg...)  dprintk(KERN_DEBUG, DBG_MAP,  fmt, ##arg)
-#define tda_reg(fmt, arg...)  dprintk(KERN_DEBUG, DBG_REG,  fmt, ##arg)
-#define tda_cal(fmt, arg...)  dprintk(KERN_DEBUG, DBG_CAL,  fmt, ##arg)
+               tda_printk(KERN_DEBUG, fmt, ##arg); } while (0)
+
+#define tda_info(fmt, arg...)     printk(KERN_INFO     fmt, ##arg)
+#define tda_warn(fmt, arg...) tda_printk(KERN_WARNING, fmt, ##arg)
+#define tda_err(fmt, arg...)  tda_printk(KERN_ERR,     fmt, ##arg)
+#define tda_dbg(fmt, arg...)  tda_dprintk(DBG_INFO,    fmt, ##arg)
+#define tda_map(fmt, arg...)  tda_dprintk(DBG_MAP,     fmt, ##arg)
+#define tda_reg(fmt, arg...)  tda_dprintk(DBG_REG,     fmt, ##arg)
+#define tda_cal(fmt, arg...)  tda_dprintk(DBG_CAL,     fmt, ##arg)
 
 #define tda_fail(ret)                                                       \
 ({                                                                          \
index 53a9892a18d0fd6ca7c19bf0b1979a7a26155d4e..71bac9593f1ea9246b64a3eb178fca0342fe3d83 100644 (file)
@@ -77,6 +77,9 @@ struct tda18271_config {
        /* use i2c gate provided by analog or digital demod */
        enum tda18271_i2c_gate gate;
 
+       /* force rf tracking filter calibration on startup */
+       unsigned int rf_cal_on_startup:1;
+
        /* some i2c providers cant write all 39 registers at once */
        unsigned int small_i2c:1;
 
index 149d54cdf7b97a4ff92107e3afffbb1c773a1ddc..8abbcc5fcf9542f5787e7dae940441f3dc3a38df 100644 (file)
@@ -144,6 +144,8 @@ static inline int tuner_stereo(const int type, const int status)
        case TUNER_LG_NTSC_TAPE:
        case TUNER_TCL_MF02GIP_5N:
                return ((status & TUNER_SIGNAL) == TUNER_STEREO_MK3);
+       case TUNER_PHILIPS_FM1216MK5:
+               return status | TUNER_STEREO;
        default:
                return status & TUNER_STEREO;
        }
@@ -508,6 +510,10 @@ static int simple_radio_bandswitch(struct dvb_frontend *fe, u8 *buffer)
        case TUNER_TCL_MF02GIP_5N:
                buffer[3] = 0x19;
                break;
+       case TUNER_PHILIPS_FM1216MK5:
+               buffer[2] = 0x88;
+               buffer[3] = 0x09;
+               break;
        case TUNER_TNF_5335MF:
                buffer[3] = 0x11;
                break;
index 6a7f1a417c278eff34d835029b4894fde8cedd48..5c6ef1e23c94367d4cde56f3370fb12ac35671f2 100644 (file)
@@ -1301,6 +1301,25 @@ static struct tuner_params tuner_fq1216lme_mk3_params[] = {
        },
 };
 
+/* ----- TUNER_PARTSNIC_PTI_5NF05 - Partsnic (Daewoo) PTI-5NF05 NTSC ----- */
+
+static struct tuner_range tuner_partsnic_pti_5nf05_ranges[] = {
+       /* The datasheet specified channel ranges and the bandswitch byte */
+       /* The control byte value of 0x8e is just a guess */
+       { 16 * 133.25 /*MHz*/, 0x8e, 0x01, }, /* Channels    2 -    B */
+       { 16 * 367.25 /*MHz*/, 0x8e, 0x02, }, /* Channels    C - W+11 */
+       { 16 * 999.99        , 0x8e, 0x08, }, /* Channels W+12 -   69 */
+};
+
+static struct tuner_params tuner_partsnic_pti_5nf05_params[] = {
+       {
+               .type   = TUNER_PARAM_TYPE_NTSC,
+               .ranges = tuner_partsnic_pti_5nf05_ranges,
+               .count  = ARRAY_SIZE(tuner_partsnic_pti_5nf05_ranges),
+               .cb_first_if_lower_freq = 1, /* not specified but safe to do */
+       },
+};
+
 /* --------------------------------------------------------------------- */
 
 struct tunertype tuners[] = {
@@ -1753,6 +1772,12 @@ struct tunertype tuners[] = {
                .params = tuner_fq1216lme_mk3_params,
                .count  = ARRAY_SIZE(tuner_fq1216lme_mk3_params),
        },
+
+       [TUNER_PARTSNIC_PTI_5NF05] = {
+               .name = "Partsnic (Daewoo) PTI-5NF05",
+               .params = tuner_partsnic_pti_5nf05_params,
+               .count  = ARRAY_SIZE(tuner_partsnic_pti_5nf05_params),
+       },
 };
 EXPORT_SYMBOL(tuners);
 
index b0198691892a4a4ecab85d7febccf554c5dfe381..1d0e4b1ef10c924faeab91e060862454ccde7776 100644 (file)
@@ -2,6 +2,19 @@
 # DVB device configuration
 #
 
+config DVB_MAX_ADAPTERS
+       int "maximum number of DVB/ATSC adapters"
+       depends on DVB_CORE
+       default 8
+       range 1 255
+       help
+         Maximum number of DVB/ATSC adapters. Increasing this number
+         increases the memory consumption of the DVB subsystem even
+         if a much lower number of DVB/ATSC adapters is present.
+         Only values in the range 4-32 are tested.
+
+         If you are unsure about this, use the default value 8
+
 config DVB_DYNAMIC_MINORS
        bool "Dynamic DVB minor allocation"
        depends on DVB_CORE
index 9a6307a347b21e7169a41f4f4a9d1ecbce15dd3f..850a6c606750240f502f82bdf25ca1ce3b675dc0 100644 (file)
@@ -66,7 +66,7 @@ static int flexcop_sleep(struct dvb_frontend* fe)
 #endif
 
 /* SkyStar2 DVB-S rev 2.3 */
-#if FE_SUPPORTED(MT312)
+#if FE_SUPPORTED(MT312) && FE_SUPPORTED(PLL)
 static int flexcop_set_tone(struct dvb_frontend *fe, fe_sec_tone_mode_t tone)
 {
 /* u16 wz_half_period_for_45_mhz[] = { 0x01ff, 0x0154, 0x00ff, 0x00cc }; */
@@ -155,55 +155,34 @@ static struct mt312_config skystar23_samsung_tbdu18132_config = {
        .demod_address = 0x0e,
 };
 
-static int skystar23_samsung_tbdu18132_tuner_set_params(struct dvb_frontend *fe,
-       struct dvb_frontend_parameters *params)
-{
-       u8 buf[4];
-       u32 div;
-       struct i2c_msg msg = { .addr = 0x61, .flags = 0, .buf = buf,
-       .len = sizeof(buf) };
-       struct flexcop_device *fc = fe->dvb->priv;
-       div = (params->frequency + (125/2)) / 125;
-
-       buf[0] = (div >> 8) & 0x7f;
-       buf[1] = (div >> 0) & 0xff;
-       buf[2] = 0x84 | ((div >> 10) & 0x60);
-       buf[3] = 0x80;
-
-       if (params->frequency < 1550000)
-               buf[3] |= 0x02;
-
-       if (fe->ops.i2c_gate_ctrl)
-               fe->ops.i2c_gate_ctrl(fe, 1);
-       if (i2c_transfer(&fc->fc_i2c_adap[0].i2c_adap, &msg, 1) != 1)
-               return -EIO;
-       return 0;
-}
-
 static int skystar2_rev23_attach(struct flexcop_device *fc,
        struct i2c_adapter *i2c)
 {
+       struct dvb_frontend_ops *ops;
+
        fc->fe = dvb_attach(mt312_attach, &skystar23_samsung_tbdu18132_config, i2c);
-       if (fc->fe != NULL) {
-               struct dvb_frontend_ops *ops = &fc->fe->ops;
-               ops->tuner_ops.set_params   =
-                       skystar23_samsung_tbdu18132_tuner_set_params;
-               ops->diseqc_send_master_cmd = flexcop_diseqc_send_master_cmd;
-               ops->diseqc_send_burst      = flexcop_diseqc_send_burst;
-               ops->set_tone               = flexcop_set_tone;
-               ops->set_voltage            = flexcop_set_voltage;
-               fc->fe_sleep                = ops->sleep;
-               ops->sleep                  = flexcop_sleep;
-               return 1;
-       }
-       return 0;
+       if (!fc->fe)
+               return 0;
+
+       if (!dvb_attach(dvb_pll_attach, fc->fe, 0x61, i2c,
+                       DVB_PLL_SAMSUNG_TBDU18132))
+               return 0;
+
+       ops = &fc->fe->ops;
+       ops->diseqc_send_master_cmd = flexcop_diseqc_send_master_cmd;
+       ops->diseqc_send_burst      = flexcop_diseqc_send_burst;
+       ops->set_tone               = flexcop_set_tone;
+       ops->set_voltage            = flexcop_set_voltage;
+       fc->fe_sleep                = ops->sleep;
+       ops->sleep                  = flexcop_sleep;
+       return 1;
 }
 #else
 #define skystar2_rev23_attach NULL
 #endif
 
 /* SkyStar2 DVB-S rev 2.6 */
-#if FE_SUPPORTED(STV0299)
+#if FE_SUPPORTED(STV0299) && FE_SUPPORTED(PLL)
 static int samsung_tbmu24112_set_symbol_rate(struct dvb_frontend *fe,
        u32 srate, u32 ratio)
 {
@@ -232,31 +211,6 @@ static int samsung_tbmu24112_set_symbol_rate(struct dvb_frontend *fe,
        return 0;
 }
 
-static int samsung_tbmu24112_tuner_set_params(struct dvb_frontend *fe,
-       struct dvb_frontend_parameters *params)
-{
-       u8 buf[4];
-       u32 div;
-       struct i2c_msg msg = {
-       .addr = 0x61, .flags = 0, .buf = buf, .len = sizeof(buf) };
-       struct flexcop_device *fc = fe->dvb->priv;
-       div = params->frequency / 125;
-
-       buf[0] = (div >> 8) & 0x7f;
-       buf[1] = div & 0xff;
-       buf[2] = 0x84; /* 0xC4 */
-       buf[3] = 0x08;
-
-       if (params->frequency < 1500000)
-               buf[3] |= 0x10;
-
-       if (fe->ops.i2c_gate_ctrl)
-               fe->ops.i2c_gate_ctrl(fe, 1);
-       if (i2c_transfer(&fc->fc_i2c_adap[0].i2c_adap, &msg, 1) != 1)
-               return -EIO;
-       return 0;
-}
-
 static u8 samsung_tbmu24112_inittab[] = {
        0x01, 0x15,
        0x02, 0x30,
@@ -318,15 +272,18 @@ static int skystar2_rev26_attach(struct flexcop_device *fc,
        struct i2c_adapter *i2c)
 {
        fc->fe = dvb_attach(stv0299_attach, &samsung_tbmu24112_config, i2c);
-       if (fc->fe != NULL) {
-               struct dvb_frontend_ops *ops  = &fc->fe->ops;
-               ops->tuner_ops.set_params = samsung_tbmu24112_tuner_set_params;
-               ops->set_voltage = flexcop_set_voltage;
-               fc->fe_sleep = ops->sleep;
-               ops->sleep = flexcop_sleep;
-               return 1;
-       }
-       return 0;
+       if (!fc->fe)
+               return 0;
+
+       if (!dvb_attach(dvb_pll_attach, fc->fe, 0x61, i2c,
+                       DVB_PLL_SAMSUNG_TBMU24112))
+               return 0;
+
+       fc->fe->ops.set_voltage = flexcop_set_voltage;
+       fc->fe_sleep = fc->fe->ops.sleep;
+       fc->fe->ops.sleep = flexcop_sleep;
+       return 1;
+
 }
 #else
 #define skystar2_rev26_attach NULL
@@ -421,7 +378,7 @@ static int skystar2_rev28_attach(struct flexcop_device *fc,
        if (!fc->fe)
                return 0;
 
-       i2c_tuner = cx24123_get_tuner_i2c_adapter(fc->fe);;
+       i2c_tuner = cx24123_get_tuner_i2c_adapter(fc->fe);
        if (!i2c_tuner)
                return 0;
 
@@ -449,7 +406,7 @@ static int skystar2_rev28_attach(struct flexcop_device *fc,
 #endif
 
 /* AirStar DVB-T */
-#if FE_SUPPORTED(MT352)
+#if FE_SUPPORTED(MT352) && FE_SUPPORTED(PLL)
 static int samsung_tdtc9251dh0_demod_init(struct dvb_frontend *fe)
 {
        static u8 mt352_clock_config[] = { 0x89, 0x18, 0x2d };
@@ -467,32 +424,6 @@ static int samsung_tdtc9251dh0_demod_init(struct dvb_frontend *fe)
        return 0;
 }
 
-static int samsung_tdtc9251dh0_calc_regs(struct dvb_frontend *fe,
-       struct dvb_frontend_parameters *params, u8* pllbuf, int buf_len)
-{
-       u32 div;
-       unsigned char bs = 0;
-
-       if (buf_len < 5)
-               return -EINVAL;
-
-#define IF_FREQUENCYx6 217    /* 6 * 36.16666666667MHz */
-       div = (((params->frequency + 83333) * 3) / 500000) + IF_FREQUENCYx6;
-       if (params->frequency >= 48000000 && params->frequency <= 154000000) \
-               bs = 0x09;
-       if (params->frequency >= 161000000 && params->frequency <= 439000000) \
-               bs = 0x0a;
-       if (params->frequency >= 447000000 && params->frequency <= 863000000) \
-               bs = 0x08;
-
-       pllbuf[0] = 0x61;
-       pllbuf[1] = div >> 8;
-       pllbuf[2] = div & 0xff;
-       pllbuf[3] = 0xcc;
-       pllbuf[4] = bs;
-       return 5;
-}
-
 static struct mt352_config samsung_tdtc9251dh0_config = {
        .demod_address = 0x0f,
        .demod_init    = samsung_tdtc9251dh0_demod_init,
@@ -502,11 +433,11 @@ static int airstar_dvbt_attach(struct flexcop_device *fc,
        struct i2c_adapter *i2c)
 {
        fc->fe = dvb_attach(mt352_attach, &samsung_tdtc9251dh0_config, i2c);
-       if (fc->fe != NULL) {
-               fc->fe->ops.tuner_ops.calc_regs = samsung_tdtc9251dh0_calc_regs;
-               return 1;
-       }
-       return 0;
+       if (!fc->fe)
+               return 0;
+
+       return !!dvb_attach(dvb_pll_attach, fc->fe, 0x61, NULL,
+                           DVB_PLL_SAMSUNG_TDTC9251DH0);
 }
 #else
 #define airstar_dvbt_attach NULL
@@ -580,54 +511,7 @@ static int airstar_atsc3_attach(struct flexcop_device *fc,
 #endif
 
 /* CableStar2 DVB-C */
-#if FE_SUPPORTED(STV0297)
-static int alps_tdee4_stv0297_tuner_set_params(struct dvb_frontend* fe,
-               struct dvb_frontend_parameters *fep)
-{
-       struct flexcop_device *fc = fe->dvb->priv;
-       u8 buf[4];
-       u16 div;
-       int ret;
-
-/* 62.5 kHz * 10 */
-#define REF_FREQ    625
-#define FREQ_OFFSET 36125
-
-       div = ((fep->frequency/1000 + FREQ_OFFSET) * 10) / REF_FREQ;
-/* 4 MHz = 4000 KHz */
-
-       buf[0] = (u8)( div >> 8) & 0x7f;
-       buf[1] = (u8)        div & 0xff;
-
-/* F(osc) = N * Reference Freq. (62.5 kHz)
- * byte 2 :  0 N14 N13 N12 N11 N10 N9  N8
- * byte 3 : N7 N6  N5  N4  N3  N2  N1  N0
- * byte 4 : 1  *   *   AGD R3  R2  R1  R0
- * byte 5 : C1 *   RE  RTS BS4 BS3 BS2 BS1
- * AGD = 1, R3 R2 R1 R0 = 0 1 0 1 => byte 4 = 1**10101 = 0x95 */
-       buf[2] = 0x95;
-
-/* Range(MHz)  C1 *  RE RTS BS4 BS3 BS2 BS1  Byte 5
- *  47 - 153   0  *  0   0   0   0   0   1   0x01
- * 153 - 430   0  *  0   0   0   0   1   0   0x02
- * 430 - 822   0  *  0   0   1   0   0   0   0x08
- * 822 - 862   1  *  0   0   1   0   0   0   0x88 */
-
-            if (fep->frequency <= 153000000) buf[3] = 0x01;
-       else if (fep->frequency <= 430000000) buf[3] = 0x02;
-       else if (fep->frequency <= 822000000) buf[3] = 0x08;
-       else buf[3] = 0x88;
-
-       if (fe->ops.i2c_gate_ctrl)
-               fe->ops.i2c_gate_ctrl(fe, 0);
-       deb_tuner("tuner buffer for %d Hz: %x %x %x %x\n", fep->frequency,
-       buf[0], buf[1], buf[2], buf[3]);
-       ret = fc->i2c_request(&fc->fc_i2c_adap[2],
-                       FC_WRITE, 0x61, buf[0], &buf[1], 3);
-       deb_tuner("tuner write returned: %d\n",ret);
-       return ret;
-}
-
+#if FE_SUPPORTED(STV0297) && FE_SUPPORTED(PLL)
 static u8 alps_tdee4_stv0297_inittab[] = {
        0x80, 0x01,
        0x80, 0x00,
@@ -711,13 +595,25 @@ static int cablestar2_attach(struct flexcop_device *fc,
 {
        fc->fc_i2c_adap[0].no_base_addr = 1;
        fc->fe = dvb_attach(stv0297_attach, &alps_tdee4_stv0297_config, i2c);
-       if (!fc->fe) {
-               /* Reset for next frontend to try */
-               fc->fc_i2c_adap[0].no_base_addr = 0;
-               return 0;
-       }
-       fc->fe->ops.tuner_ops.set_params = alps_tdee4_stv0297_tuner_set_params;
+       if (!fc->fe)
+               goto fail;
+
+       /* This tuner doesn't use the stv0297's I2C gate, but instead the
+        * tuner is connected to a different flexcop I2C adapter.  */
+       if (fc->fe->ops.i2c_gate_ctrl)
+               fc->fe->ops.i2c_gate_ctrl(fc->fe, 0);
+       fc->fe->ops.i2c_gate_ctrl = NULL;
+
+       if (!dvb_attach(dvb_pll_attach, fc->fe, 0x61,
+                       &fc->fc_i2c_adap[2].i2c_adap, DVB_PLL_TDEE4))
+               goto fail;
+
        return 1;
+
+fail:
+       /* Reset for next frontend to try */
+       fc->fc_i2c_adap[0].no_base_addr = 0;
+       return 0;
 }
 #else
 #define cablestar2_attach NULL
index fec1d77fa8555a4ca0c2262443a7bef6f2769a2b..91353a6faf1d253d5cbd13c9fdba5e01b49481d6 100644 (file)
@@ -1059,7 +1059,7 @@ static int dst_get_tuner_info(struct dst_state *state)
                dprintk(verbose, DST_ERROR, 1, "DST type has TS=188");
        }
        if (state->board_info[0] == 0xbc) {
-               if (state->type_flags != DST_TYPE_IS_ATSC)
+               if (state->dst_type != DST_TYPE_IS_ATSC)
                        state->type_flags |= DST_TYPE_HAS_TS188;
                else
                        state->type_flags |= DST_TYPE_HAS_NEWTUNE_2;
index 4dbd7d4185af2dba90dd610c62e49f1738cdda1d..2d099e27175199db5bc6af91cf6d47a5861cddef 100644 (file)
 #include "cx24116.h"
 #include "z0194a.h"
 
+#define UNSET (-1U)
+
+#define DM1105_BOARD_NOAUTO            UNSET
+#define DM1105_BOARD_UNKNOWN           0
+#define DM1105_BOARD_DVBWORLD_2002     1
+#define DM1105_BOARD_DVBWORLD_2004     2
+#define DM1105_BOARD_AXESS_DM05                3
+
 /* ----------------------------------------------- */
 /*
  * PCI ID's
 
 /* GPIO's for LNB power control */
 #define DM1105_LNB_MASK                                0x00000000
+#define DM1105_LNB_OFF                         0x00020000
 #define DM1105_LNB_13V                         0x00010100
 #define DM1105_LNB_18V                         0x00000100
 
 /* GPIO's for LNB power control for Axess DM05 */
 #define DM05_LNB_MASK                          0x00000000
+#define DM05_LNB_OFF                           0x00020000/* actually 13v */
 #define DM05_LNB_13V                           0x00020000
 #define DM05_LNB_18V                           0x00030000
 
+static unsigned int card[]  = {[0 ... 3] = UNSET };
+module_param_array(card,  int, NULL, 0444);
+MODULE_PARM_DESC(card, "card type");
+
 static int ir_debug;
 module_param(ir_debug, int, 0644);
 MODULE_PARM_DESC(ir_debug, "enable debugging information for IR decoding");
 
+static unsigned int dm1105_devcount;
+
 DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr);
 
+struct dm1105_board {
+       char                    *name;
+};
+
+struct dm1105_subid {
+       u16     subvendor;
+       u16     subdevice;
+       u32     card;
+};
+
+static const struct dm1105_board dm1105_boards[] = {
+       [DM1105_BOARD_UNKNOWN] = {
+               .name           = "UNKNOWN/GENERIC",
+       },
+       [DM1105_BOARD_DVBWORLD_2002] = {
+               .name           = "DVBWorld PCI 2002",
+       },
+       [DM1105_BOARD_DVBWORLD_2004] = {
+               .name           = "DVBWorld PCI 2004",
+       },
+       [DM1105_BOARD_AXESS_DM05] = {
+               .name           = "Axess/EasyTv DM05",
+       },
+};
+
+static const struct dm1105_subid dm1105_subids[] = {
+       {
+               .subvendor = 0x0000,
+               .subdevice = 0x2002,
+               .card      = DM1105_BOARD_DVBWORLD_2002,
+       }, {
+               .subvendor = 0x0001,
+               .subdevice = 0x2002,
+               .card      = DM1105_BOARD_DVBWORLD_2002,
+       }, {
+               .subvendor = 0x0000,
+               .subdevice = 0x2004,
+               .card      = DM1105_BOARD_DVBWORLD_2004,
+       }, {
+               .subvendor = 0x0001,
+               .subdevice = 0x2004,
+               .card      = DM1105_BOARD_DVBWORLD_2004,
+       }, {
+               .subvendor = 0x195d,
+               .subdevice = 0x1105,
+               .card      = DM1105_BOARD_AXESS_DM05,
+       },
+};
+
+static void dm1105_card_list(struct pci_dev *pci)
+{
+       int i;
+
+       if (0 == pci->subsystem_vendor &&
+                       0 == pci->subsystem_device) {
+               printk(KERN_ERR
+                       "dm1105: Your board has no valid PCI Subsystem ID\n"
+                       "dm1105: and thus can't be autodetected\n"
+                       "dm1105: Please pass card=<n> insmod option to\n"
+                       "dm1105: workaround that.  Redirect complaints to\n"
+                       "dm1105: the vendor of the TV card.  Best regards,\n"
+                       "dm1105: -- tux\n");
+       } else {
+               printk(KERN_ERR
+                       "dm1105: Your board isn't known (yet) to the driver.\n"
+                       "dm1105: You can try to pick one of the existing\n"
+                       "dm1105: card configs via card=<n> insmod option.\n"
+                       "dm1105: Updating to the latest version might help\n"
+                       "dm1105: as well.\n");
+       }
+       printk(KERN_ERR "Here is a list of valid choices for the card=<n> "
+                  "insmod option:\n");
+       for (i = 0; i < ARRAY_SIZE(dm1105_boards); i++)
+               printk(KERN_ERR "dm1105:    card=%d -> %s\n",
+                               i, dm1105_boards[i].name);
+}
+
 /* infrared remote control */
 struct infrared {
        struct input_dev        *input_dev;
@@ -193,6 +286,8 @@ struct dm1105dvb {
        struct dvb_frontend *fe;
        struct dvb_net dvbnet;
        unsigned int full_ts_users;
+       unsigned int boardnr;
+       int nr;
 
        /* i2c */
        struct i2c_adapter i2c_adap;
@@ -211,7 +306,6 @@ struct dm1105dvb {
        unsigned int    PacketErrorCount;
        unsigned int dmarst;
        spinlock_t lock;
-
 };
 
 #define dm_io_mem(reg) ((unsigned long)(&dm1105dvb->io_mem[reg]))
@@ -326,16 +420,20 @@ static inline struct dm1105dvb *frontend_to_dm1105dvb(struct dvb_frontend *fe)
 static int dm1105dvb_set_voltage(struct dvb_frontend *fe, fe_sec_voltage_t voltage)
 {
        struct dm1105dvb *dm1105dvb = frontend_to_dm1105dvb(fe);
-       u32 lnb_mask, lnb_13v, lnb_18v;
+       u32 lnb_mask, lnb_13v, lnb_18v, lnb_off;
 
-       switch (dm1105dvb->pdev->subsystem_device) {
-       case PCI_DEVICE_ID_DM05:
+       switch (dm1105dvb->boardnr) {
+       case DM1105_BOARD_AXESS_DM05:
                lnb_mask = DM05_LNB_MASK;
+               lnb_off = DM05_LNB_OFF;
                lnb_13v = DM05_LNB_13V;
                lnb_18v = DM05_LNB_18V;
                break;
+       case DM1105_BOARD_DVBWORLD_2002:
+       case DM1105_BOARD_DVBWORLD_2004:
        default:
                lnb_mask = DM1105_LNB_MASK;
+               lnb_off = DM1105_LNB_OFF;
                lnb_13v = DM1105_LNB_13V;
                lnb_18v = DM1105_LNB_18V;
        }
@@ -343,8 +441,10 @@ static int dm1105dvb_set_voltage(struct dvb_frontend *fe, fe_sec_voltage_t volta
        outl(lnb_mask, dm_io_mem(DM1105_GPIOCTR));
        if (voltage == SEC_VOLTAGE_18)
                outl(lnb_18v , dm_io_mem(DM1105_GPIOVAL));
-       else
+       else if (voltage == SEC_VOLTAGE_13)
                outl(lnb_13v, dm_io_mem(DM1105_GPIOVAL));
+       else
+               outl(lnb_off, dm_io_mem(DM1105_GPIOVAL));
 
        return 0;
 }
@@ -477,7 +577,7 @@ static irqreturn_t dm1105dvb_irq(int irq, void *dev_id)
 int __devinit dm1105_ir_init(struct dm1105dvb *dm1105)
 {
        struct input_dev *input_dev;
-       IR_KEYTAB_TYPE *ir_codes = ir_codes_dm1105_nec;
+       struct ir_scancode_table *ir_codes = &ir_codes_dm1105_nec_table;
        int ir_type = IR_TYPE_OTHER;
        int err = -ENOMEM;
 
@@ -589,8 +689,8 @@ static int __devinit frontend_init(struct dm1105dvb *dm1105dvb)
 {
        int ret;
 
-       switch (dm1105dvb->pdev->subsystem_device) {
-       case PCI_DEVICE_ID_DW2004:
+       switch (dm1105dvb->boardnr) {
+       case DM1105_BOARD_DVBWORLD_2004:
                dm1105dvb->fe = dvb_attach(
                        cx24116_attach, &serit_sp2633_config,
                        &dm1105dvb->i2c_adap);
@@ -598,6 +698,8 @@ static int __devinit frontend_init(struct dm1105dvb *dm1105dvb)
                        dm1105dvb->fe->ops.set_voltage = dm1105dvb_set_voltage;
 
                break;
+       case DM1105_BOARD_DVBWORLD_2002:
+       case DM1105_BOARD_AXESS_DM05:
        default:
                dm1105dvb->fe = dvb_attach(
                        stv0299_attach, &sharp_z0194a_config,
@@ -676,11 +778,31 @@ static int __devinit dm1105_probe(struct pci_dev *pdev,
        struct dvb_demux *dvbdemux;
        struct dmx_demux *dmx;
        int ret = -ENOMEM;
+       int i;
 
        dm1105dvb = kzalloc(sizeof(struct dm1105dvb), GFP_KERNEL);
        if (!dm1105dvb)
                return -ENOMEM;
 
+       /* board config */
+       dm1105dvb->nr = dm1105_devcount;
+       dm1105dvb->boardnr = UNSET;
+       if (card[dm1105dvb->nr] < ARRAY_SIZE(dm1105_boards))
+               dm1105dvb->boardnr = card[dm1105dvb->nr];
+       for (i = 0; UNSET == dm1105dvb->boardnr &&
+                               i < ARRAY_SIZE(dm1105_subids); i++)
+               if (pdev->subsystem_vendor ==
+                       dm1105_subids[i].subvendor &&
+                               pdev->subsystem_device ==
+                                       dm1105_subids[i].subdevice)
+                       dm1105dvb->boardnr = dm1105_subids[i].card;
+
+       if (UNSET == dm1105dvb->boardnr) {
+               dm1105dvb->boardnr = DM1105_BOARD_UNKNOWN;
+               dm1105_card_list(pdev);
+       }
+
+       dm1105_devcount++;
        dm1105dvb->pdev = pdev;
        dm1105dvb->buffer_size = 5 * DM1105_DMA_BYTES;
        dm1105dvb->PacketErrorCount = 0;
@@ -853,6 +975,7 @@ static void __devexit dm1105_remove(struct pci_dev *pdev)
        pci_release_regions(pdev);
        pci_disable_device(pdev);
        pci_set_drvdata(pdev, NULL);
+       dm1105_devcount--;
        kfree(dm1105dvb);
 }
 
@@ -861,17 +984,12 @@ static struct pci_device_id dm1105_id_table[] __devinitdata = {
                .vendor = PCI_VENDOR_ID_TRIGEM,
                .device = PCI_DEVICE_ID_DM1105,
                .subvendor = PCI_ANY_ID,
-               .subdevice = PCI_DEVICE_ID_DW2002,
-       }, {
-               .vendor = PCI_VENDOR_ID_TRIGEM,
-               .device = PCI_DEVICE_ID_DM1105,
-               .subvendor = PCI_ANY_ID,
-               .subdevice = PCI_DEVICE_ID_DW2004,
+               .subdevice = PCI_ANY_ID,
        }, {
                .vendor = PCI_VENDOR_ID_AXESS,
                .device = PCI_DEVICE_ID_DM05,
-               .subvendor = PCI_VENDOR_ID_AXESS,
-               .subdevice = PCI_DEVICE_ID_DM05,
+               .subvendor = PCI_ANY_ID,
+               .subdevice = PCI_ANY_ID,
        }, {
                /* empty */
        },
index 6d6121eb5d592ea9157f0a8610069abc8ab4d8c9..3750ff48cba1e75097c99daf4697931b2f9b0a3f 100644 (file)
@@ -430,6 +430,8 @@ static int dvb_dmxdev_ts_callback(const u8 *buffer1, size_t buffer1_len,
 /* stop feed but only mark the specified filter as stopped (state set) */
 static int dvb_dmxdev_feed_stop(struct dmxdev_filter *dmxdevfilter)
 {
+       struct dmxdev_feed *feed;
+
        dvb_dmxdev_filter_state_set(dmxdevfilter, DMXDEV_STATE_SET);
 
        switch (dmxdevfilter->type) {
@@ -438,7 +440,8 @@ static int dvb_dmxdev_feed_stop(struct dmxdev_filter *dmxdevfilter)
                dmxdevfilter->feed.sec->stop_filtering(dmxdevfilter->feed.sec);
                break;
        case DMXDEV_TYPE_PES:
-               dmxdevfilter->feed.ts->stop_filtering(dmxdevfilter->feed.ts);
+               list_for_each_entry(feed, &dmxdevfilter->feed.ts, next)
+                       feed->ts->stop_filtering(feed->ts);
                break;
        default:
                return -EINVAL;
@@ -449,13 +452,23 @@ static int dvb_dmxdev_feed_stop(struct dmxdev_filter *dmxdevfilter)
 /* start feed associated with the specified filter */
 static int dvb_dmxdev_feed_start(struct dmxdev_filter *filter)
 {
+       struct dmxdev_feed *feed;
+       int ret;
+
        dvb_dmxdev_filter_state_set(filter, DMXDEV_STATE_GO);
 
        switch (filter->type) {
        case DMXDEV_TYPE_SEC:
                return filter->feed.sec->start_filtering(filter->feed.sec);
        case DMXDEV_TYPE_PES:
-               return filter->feed.ts->start_filtering(filter->feed.ts);
+               list_for_each_entry(feed, &filter->feed.ts, next) {
+                       ret = feed->ts->start_filtering(feed->ts);
+                       if (ret < 0) {
+                               dvb_dmxdev_feed_stop(filter);
+                               return ret;
+                       }
+               }
+               break;
        default:
                return -EINVAL;
        }
@@ -487,6 +500,9 @@ static int dvb_dmxdev_feed_restart(struct dmxdev_filter *filter)
 
 static int dvb_dmxdev_filter_stop(struct dmxdev_filter *dmxdevfilter)
 {
+       struct dmxdev_feed *feed;
+       struct dmx_demux *demux;
+
        if (dmxdevfilter->state < DMXDEV_STATE_GO)
                return 0;
 
@@ -503,13 +519,12 @@ static int dvb_dmxdev_filter_stop(struct dmxdev_filter *dmxdevfilter)
                dmxdevfilter->feed.sec = NULL;
                break;
        case DMXDEV_TYPE_PES:
-               if (!dmxdevfilter->feed.ts)
-                       break;
                dvb_dmxdev_feed_stop(dmxdevfilter);
-               dmxdevfilter->dev->demux->
-                   release_ts_feed(dmxdevfilter->dev->demux,
-                                   dmxdevfilter->feed.ts);
-               dmxdevfilter->feed.ts = NULL;
+               demux = dmxdevfilter->dev->demux;
+               list_for_each_entry(feed, &dmxdevfilter->feed.ts, next) {
+                       demux->release_ts_feed(demux, feed->ts);
+                       feed->ts = NULL;
+               }
                break;
        default:
                if (dmxdevfilter->state == DMXDEV_STATE_ALLOCATED)
@@ -521,19 +536,88 @@ static int dvb_dmxdev_filter_stop(struct dmxdev_filter *dmxdevfilter)
        return 0;
 }
 
+static void dvb_dmxdev_delete_pids(struct dmxdev_filter *dmxdevfilter)
+{
+       struct dmxdev_feed *feed, *tmp;
+
+       /* delete all PIDs */
+       list_for_each_entry_safe(feed, tmp, &dmxdevfilter->feed.ts, next) {
+               list_del(&feed->next);
+               kfree(feed);
+       }
+
+       BUG_ON(!list_empty(&dmxdevfilter->feed.ts));
+}
+
 static inline int dvb_dmxdev_filter_reset(struct dmxdev_filter *dmxdevfilter)
 {
        if (dmxdevfilter->state < DMXDEV_STATE_SET)
                return 0;
 
+       if (dmxdevfilter->type == DMXDEV_TYPE_PES)
+               dvb_dmxdev_delete_pids(dmxdevfilter);
+
        dmxdevfilter->type = DMXDEV_TYPE_NONE;
        dvb_dmxdev_filter_state_set(dmxdevfilter, DMXDEV_STATE_ALLOCATED);
        return 0;
 }
 
+static int dvb_dmxdev_start_feed(struct dmxdev *dmxdev,
+                                struct dmxdev_filter *filter,
+                                struct dmxdev_feed *feed)
+{
+       struct timespec timeout = { 0 };
+       struct dmx_pes_filter_params *para = &filter->params.pes;
+       dmx_output_t otype;
+       int ret;
+       int ts_type;
+       enum dmx_ts_pes ts_pes;
+       struct dmx_ts_feed *tsfeed;
+
+       feed->ts = NULL;
+       otype = para->output;
+
+       ts_pes = (enum dmx_ts_pes)para->pes_type;
+
+       if (ts_pes < DMX_PES_OTHER)
+               ts_type = TS_DECODER;
+       else
+               ts_type = 0;
+
+       if (otype == DMX_OUT_TS_TAP)
+               ts_type |= TS_PACKET;
+       else if (otype == DMX_OUT_TSDEMUX_TAP)
+               ts_type |= TS_PACKET | TS_DEMUX;
+       else if (otype == DMX_OUT_TAP)
+               ts_type |= TS_PACKET | TS_DEMUX | TS_PAYLOAD_ONLY;
+
+       ret = dmxdev->demux->allocate_ts_feed(dmxdev->demux, &feed->ts,
+                                             dvb_dmxdev_ts_callback);
+       if (ret < 0)
+               return ret;
+
+       tsfeed = feed->ts;
+       tsfeed->priv = filter;
+
+       ret = tsfeed->set(tsfeed, feed->pid, ts_type, ts_pes, 32768, timeout);
+       if (ret < 0) {
+               dmxdev->demux->release_ts_feed(dmxdev->demux, tsfeed);
+               return ret;
+       }
+
+       ret = tsfeed->start_filtering(tsfeed);
+       if (ret < 0) {
+               dmxdev->demux->release_ts_feed(dmxdev->demux, tsfeed);
+               return ret;
+       }
+
+       return 0;
+}
+
 static int dvb_dmxdev_filter_start(struct dmxdev_filter *filter)
 {
        struct dmxdev *dmxdev = filter->dev;
+       struct dmxdev_feed *feed;
        void *mem;
        int ret, i;
 
@@ -631,56 +715,14 @@ static int dvb_dmxdev_filter_start(struct dmxdev_filter *filter)
                break;
        }
        case DMXDEV_TYPE_PES:
-       {
-               struct timespec timeout = { 0 };
-               struct dmx_pes_filter_params *para = &filter->params.pes;
-               dmx_output_t otype;
-               int ts_type;
-               enum dmx_ts_pes ts_pes;
-               struct dmx_ts_feed **tsfeed = &filter->feed.ts;
-
-               filter->feed.ts = NULL;
-               otype = para->output;
-
-               ts_pes = (enum dmx_ts_pes)para->pes_type;
-
-               if (ts_pes < DMX_PES_OTHER)
-                       ts_type = TS_DECODER;
-               else
-                       ts_type = 0;
-
-               if (otype == DMX_OUT_TS_TAP)
-                       ts_type |= TS_PACKET;
-               else if (otype == DMX_OUT_TSDEMUX_TAP)
-                       ts_type |= TS_PACKET | TS_DEMUX;
-               else if (otype == DMX_OUT_TAP)
-                       ts_type |= TS_PACKET | TS_DEMUX | TS_PAYLOAD_ONLY;
-
-               ret = dmxdev->demux->allocate_ts_feed(dmxdev->demux,
-                                                     tsfeed,
-                                                     dvb_dmxdev_ts_callback);
-               if (ret < 0)
-                       return ret;
-
-               (*tsfeed)->priv = filter;
-
-               ret = (*tsfeed)->set(*tsfeed, para->pid, ts_type, ts_pes,
-                                    32768, timeout);
-               if (ret < 0) {
-                       dmxdev->demux->release_ts_feed(dmxdev->demux,
-                                                      *tsfeed);
-                       return ret;
-               }
-
-               ret = filter->feed.ts->start_filtering(filter->feed.ts);
-               if (ret < 0) {
-                       dmxdev->demux->release_ts_feed(dmxdev->demux,
-                                                      *tsfeed);
-                       return ret;
+               list_for_each_entry(feed, &filter->feed.ts, next) {
+                       ret = dvb_dmxdev_start_feed(dmxdev, filter, feed);
+                       if (ret < 0) {
+                               dvb_dmxdev_filter_stop(filter);
+                               return ret;
+                       }
                }
-
                break;
-       }
        default:
                return -EINVAL;
        }
@@ -718,7 +760,7 @@ static int dvb_demux_open(struct inode *inode, struct file *file)
        dvb_ringbuffer_init(&dmxdevfilter->buffer, NULL, 8192);
        dmxdevfilter->type = DMXDEV_TYPE_NONE;
        dvb_dmxdev_filter_state_set(dmxdevfilter, DMXDEV_STATE_ALLOCATED);
-       dmxdevfilter->feed.ts = NULL;
+       INIT_LIST_HEAD(&dmxdevfilter->feed.ts);
        init_timer(&dmxdevfilter->timer);
 
        dvbdev->users++;
@@ -760,6 +802,55 @@ static inline void invert_mode(dmx_filter_t *filter)
                filter->mode[i] ^= 0xff;
 }
 
+static int dvb_dmxdev_add_pid(struct dmxdev *dmxdev,
+                             struct dmxdev_filter *filter, u16 pid)
+{
+       struct dmxdev_feed *feed;
+
+       if ((filter->type != DMXDEV_TYPE_PES) ||
+           (filter->state < DMXDEV_STATE_SET))
+               return -EINVAL;
+
+       /* only TS packet filters may have multiple PIDs */
+       if ((filter->params.pes.output != DMX_OUT_TSDEMUX_TAP) &&
+           (!list_empty(&filter->feed.ts)))
+               return -EINVAL;
+
+       feed = kzalloc(sizeof(struct dmxdev_feed), GFP_KERNEL);
+       if (feed == NULL)
+               return -ENOMEM;
+
+       feed->pid = pid;
+       list_add(&feed->next, &filter->feed.ts);
+
+       if (filter->state >= DMXDEV_STATE_GO)
+               return dvb_dmxdev_start_feed(dmxdev, filter, feed);
+
+       return 0;
+}
+
+static int dvb_dmxdev_remove_pid(struct dmxdev *dmxdev,
+                                 struct dmxdev_filter *filter, u16 pid)
+{
+       struct dmxdev_feed *feed, *tmp;
+
+       if ((filter->type != DMXDEV_TYPE_PES) ||
+           (filter->state < DMXDEV_STATE_SET))
+               return -EINVAL;
+
+       list_for_each_entry_safe(feed, tmp, &filter->feed.ts, next) {
+               if ((feed->pid == pid) && (feed->ts != NULL)) {
+                       feed->ts->stop_filtering(feed->ts);
+                       filter->dev->demux->release_ts_feed(filter->dev->demux,
+                                                           feed->ts);
+                       list_del(&feed->next);
+                       kfree(feed);
+               }
+       }
+
+       return 0;
+}
+
 static int dvb_dmxdev_filter_set(struct dmxdev *dmxdev,
                                 struct dmxdev_filter *dmxdevfilter,
                                 struct dmx_sct_filter_params *params)
@@ -784,7 +875,10 @@ static int dvb_dmxdev_pes_filter_set(struct dmxdev *dmxdev,
                                     struct dmxdev_filter *dmxdevfilter,
                                     struct dmx_pes_filter_params *params)
 {
+       int ret;
+
        dvb_dmxdev_filter_stop(dmxdevfilter);
+       dvb_dmxdev_filter_reset(dmxdevfilter);
 
        if (params->pes_type > DMX_PES_OTHER || params->pes_type < 0)
                return -EINVAL;
@@ -795,6 +889,11 @@ static int dvb_dmxdev_pes_filter_set(struct dmxdev *dmxdev,
 
        dvb_dmxdev_filter_state_set(dmxdevfilter, DMXDEV_STATE_SET);
 
+       ret = dvb_dmxdev_add_pid(dmxdev, dmxdevfilter,
+                                dmxdevfilter->params.pes.pid);
+       if (ret < 0)
+               return ret;
+
        if (params->flags & DMX_IMMEDIATE_START)
                return dvb_dmxdev_filter_start(dmxdevfilter);
 
@@ -958,6 +1057,24 @@ static int dvb_demux_do_ioctl(struct inode *inode, struct file *file,
                                             &((struct dmx_stc *)parg)->base);
                break;
 
+       case DMX_ADD_PID:
+               if (mutex_lock_interruptible(&dmxdevfilter->mutex)) {
+                       ret = -ERESTARTSYS;
+                       break;
+               }
+               ret = dvb_dmxdev_add_pid(dmxdev, dmxdevfilter, *(u16 *)parg);
+               mutex_unlock(&dmxdevfilter->mutex);
+               break;
+
+       case DMX_REMOVE_PID:
+               if (mutex_lock_interruptible(&dmxdevfilter->mutex)) {
+                       ret = -ERESTARTSYS;
+                       break;
+               }
+               ret = dvb_dmxdev_remove_pid(dmxdev, dmxdevfilter, *(u16 *)parg);
+               mutex_unlock(&dmxdevfilter->mutex);
+               break;
+
        default:
                ret = -EINVAL;
                break;
index 29746e70d3252dedaa2a40856b91472e55934603..c1379b56dfb4d47f4da21caa8c6c399a51c8003e 100644 (file)
@@ -53,13 +53,20 @@ enum dmxdev_state {
        DMXDEV_STATE_TIMEDOUT
 };
 
+struct dmxdev_feed {
+       u16 pid;
+       struct dmx_ts_feed *ts;
+       struct list_head next;
+};
+
 struct dmxdev_filter {
        union {
                struct dmx_section_filter *sec;
        } filter;
 
        union {
-               struct dmx_ts_feed *ts;
+               /* list of TS and PES feeds (struct dmxdev_feed) */
+               struct list_head ts;
                struct dmx_section_feed *sec;
        } feed;
 
index cfe2768d24af58133ecd47ba8461e25aa062d12b..eef6d36166268f77883b2fb454eb6dcd698ca1fa 100644 (file)
@@ -425,13 +425,9 @@ no_dvb_demux_tscheck:
                if ((DVR_FEED(feed)) && (dvr_done++))
                        continue;
 
-               if (feed->pid == pid) {
+               if (feed->pid == pid)
                        dvb_dmx_swfilter_packet_type(feed, buf);
-                       if (DVR_FEED(feed))
-                               continue;
-               }
-
-               if (feed->pid == 0x2000)
+               else if (feed->pid == 0x2000)
                        feed->cb.ts(buf, 188, NULL, 0, &feed->feed.ts, DMX_OK);
        }
 }
index f50ca7292a7d4e8bd6c69ffd58368db0c749b923..d13ebcb0c6b650f5dda000631f4985c7d7bcb171 100644 (file)
@@ -72,6 +72,7 @@ MODULE_PARM_DESC(dvb_mfe_wait_time, "Wait up to <mfe_wait_time> seconds on open(
 #define FESTATE_ZIGZAG_FAST 32
 #define FESTATE_ZIGZAG_SLOW 64
 #define FESTATE_DISEQC 128
+#define FESTATE_ERROR 256
 #define FESTATE_WAITFORLOCK (FESTATE_TUNING_FAST | FESTATE_TUNING_SLOW | FESTATE_ZIGZAG_FAST | FESTATE_ZIGZAG_SLOW | FESTATE_DISEQC)
 #define FESTATE_SEARCHING_FAST (FESTATE_TUNING_FAST | FESTATE_ZIGZAG_FAST)
 #define FESTATE_SEARCHING_SLOW (FESTATE_TUNING_SLOW | FESTATE_ZIGZAG_SLOW)
@@ -269,6 +270,7 @@ static int dvb_frontend_swzigzag_autotune(struct dvb_frontend *fe, int check_wra
 {
        int autoinversion;
        int ready = 0;
+       int fe_set_err = 0;
        struct dvb_frontend_private *fepriv = fe->frontend_priv;
        int original_inversion = fepriv->parameters.inversion;
        u32 original_frequency = fepriv->parameters.frequency;
@@ -345,7 +347,11 @@ static int dvb_frontend_swzigzag_autotune(struct dvb_frontend *fe, int check_wra
        if (autoinversion)
                fepriv->parameters.inversion = fepriv->inversion;
        if (fe->ops.set_frontend)
-               fe->ops.set_frontend(fe, &fepriv->parameters);
+               fe_set_err = fe->ops.set_frontend(fe, &fepriv->parameters);
+       if (fe_set_err < 0) {
+               fepriv->state = FESTATE_ERROR;
+               return fe_set_err;
+       }
 
        fepriv->parameters.frequency = original_frequency;
        fepriv->parameters.inversion = original_inversion;
@@ -357,6 +363,7 @@ static int dvb_frontend_swzigzag_autotune(struct dvb_frontend *fe, int check_wra
 static void dvb_frontend_swzigzag(struct dvb_frontend *fe)
 {
        fe_status_t s = 0;
+       int retval = 0;
        struct dvb_frontend_private *fepriv = fe->frontend_priv;
 
        /* if we've got no parameters, just keep idling */
@@ -370,8 +377,12 @@ static void dvb_frontend_swzigzag(struct dvb_frontend *fe)
        if (fepriv->tune_mode_flags & FE_TUNE_MODE_ONESHOT) {
                if (fepriv->state & FESTATE_RETUNE) {
                        if (fe->ops.set_frontend)
-                               fe->ops.set_frontend(fe, &fepriv->parameters);
-                       fepriv->state = FESTATE_TUNED;
+                               retval = fe->ops.set_frontend(fe,
+                                                       &fepriv->parameters);
+                       if (retval < 0)
+                               fepriv->state = FESTATE_ERROR;
+                       else
+                               fepriv->state = FESTATE_TUNED;
                }
                fepriv->delay = 3*HZ;
                fepriv->quality = 0;
@@ -449,7 +460,11 @@ static void dvb_frontend_swzigzag(struct dvb_frontend *fe)
                fepriv->delay = fepriv->min_delay;
 
                /* peform a tune */
-               if (dvb_frontend_swzigzag_autotune(fe, fepriv->check_wrapped)) {
+               retval = dvb_frontend_swzigzag_autotune(fe,
+                                                       fepriv->check_wrapped);
+               if (retval < 0) {
+                       return;
+               } else if (retval) {
                        /* OK, if we've run out of trials at the fast speed.
                         * Drop back to slow for the _next_ attempt */
                        fepriv->state = FESTATE_SEARCHING_SLOW;
@@ -823,6 +838,15 @@ static int dvb_frontend_check_parameters(struct dvb_frontend *fe,
                }
        }
 
+       /* check for supported modulation */
+       if (fe->ops.info.type == FE_QAM &&
+           (parms->u.qam.modulation > QAM_AUTO ||
+            !((1 << (parms->u.qam.modulation + 10)) & fe->ops.info.caps))) {
+               printk(KERN_WARNING "DVB: adapter %i frontend %i modulation %u not supported\n",
+                      fe->dvb->num, fe->id, parms->u.qam.modulation);
+                       return -EINVAL;
+       }
+
        return 0;
 }
 
@@ -1499,7 +1523,8 @@ static int dvb_frontend_ioctl_legacy(struct inode *inode, struct file *file,
 
                /* if retune was requested but hasn't occured yet, prevent
                 * that user get signal state from previous tuning */
-               if(fepriv->state == FESTATE_RETUNE) {
+               if (fepriv->state == FESTATE_RETUNE ||
+                   fepriv->state == FESTATE_ERROR) {
                        err=0;
                        *status = 0;
                        break;
index 487919bea7ae0bf147004b6845611f24eea0537f..895e2efca8a974a3c2996b51b5b86ef8a644b76a 100644 (file)
 
 #define DVB_MAJOR 212
 
+#if defined(CONFIG_DVB_MAX_ADAPTERS) && CONFIG_DVB_MAX_ADAPTERS > 0
+#define DVB_MAX_ADAPTERS CONFIG_DVB_MAX_ADAPTERS
+#else
+#warning invalid CONFIG_DVB_MAX_ADAPTERS value
 #define DVB_MAX_ADAPTERS 8
+#endif
 
 #define DVB_UNSET (-1)
 
index 496c1a37034ced8d9ab89aaff3cd2ef30c024b08..8b8bc04ee9806762725fe902bae5bd9dc9312f8b 100644 (file)
@@ -253,7 +253,7 @@ config DVB_USB_AF9005_REMOTE
          Afatech AF9005 based receiver.
 
 config DVB_USB_DW2102
-       tristate "DvbWorld DVB-S/S2 USB2.0 support"
+       tristate "DvbWorld & TeVii DVB-S/S2 USB2.0 support"
        depends on DVB_USB
        select DVB_PLL if !DVB_FE_CUSTOMISE
        select DVB_STV0299 if !DVB_FE_CUSTOMISE
@@ -262,9 +262,11 @@ config DVB_USB_DW2102
        select DVB_CX24116 if !DVB_FE_CUSTOMISE
        select DVB_SI21XX if !DVB_FE_CUSTOMISE
        select DVB_TDA10021 if !DVB_FE_CUSTOMISE
+       select DVB_MT312 if !DVB_FE_CUSTOMISE
+       select DVB_ZL10039 if !DVB_FE_CUSTOMISE
        help
          Say Y here to support the DvbWorld DVB-S/S2 USB2.0 receivers
-         and the TeVii S650.
+         and the TeVii S650, S630.
 
 config DVB_USB_CINERGY_T2
        tristate "Terratec CinergyT2/qanu USB 2.0 DVB-T receiver"
index dc8c8784caa8a8c46e36886acdcbff6e8f3eeb1e..6247239982e91588a442af02f122a5967d3d5bea 100644 (file)
@@ -38,41 +38,41 @@ static int a800_identify_state(struct usb_device *udev, struct dvb_usb_device_pr
 }
 
 static struct dvb_usb_rc_key a800_rc_keys[] = {
-       { 0x02, 0x01, KEY_PROG1 },       /* SOURCE */
-       { 0x02, 0x00, KEY_POWER },       /* POWER */
-       { 0x02, 0x05, KEY_1 },           /* 1 */
-       { 0x02, 0x06, KEY_2 },           /* 2 */
-       { 0x02, 0x07, KEY_3 },           /* 3 */
-       { 0x02, 0x09, KEY_4 },           /* 4 */
-       { 0x02, 0x0a, KEY_5 },           /* 5 */
-       { 0x02, 0x0b, KEY_6 },           /* 6 */
-       { 0x02, 0x0d, KEY_7 },           /* 7 */
-       { 0x02, 0x0e, KEY_8 },           /* 8 */
-       { 0x02, 0x0f, KEY_9 },           /* 9 */
-       { 0x02, 0x12, KEY_LEFT },        /* L / DISPLAY */
-       { 0x02, 0x11, KEY_0 },           /* 0 */
-       { 0x02, 0x13, KEY_RIGHT },       /* R / CH RTN */
-       { 0x02, 0x17, KEY_PROG2 },       /* SNAP SHOT */
-       { 0x02, 0x10, KEY_PROG3 },       /* 16-CH PREV */
-       { 0x02, 0x1e, KEY_VOLUMEDOWN },  /* VOL DOWN */
-       { 0x02, 0x0c, KEY_ZOOM },        /* FULL SCREEN */
-       { 0x02, 0x1f, KEY_VOLUMEUP },    /* VOL UP */
-       { 0x02, 0x14, KEY_MUTE },        /* MUTE */
-       { 0x02, 0x08, KEY_AUDIO },       /* AUDIO */
-       { 0x02, 0x19, KEY_RECORD },      /* RECORD */
-       { 0x02, 0x18, KEY_PLAY },        /* PLAY */
-       { 0x02, 0x1b, KEY_STOP },        /* STOP */
-       { 0x02, 0x1a, KEY_PLAYPAUSE },   /* TIMESHIFT / PAUSE */
-       { 0x02, 0x1d, KEY_BACK },        /* << / RED */
-       { 0x02, 0x1c, KEY_FORWARD },     /* >> / YELLOW */
-       { 0x02, 0x03, KEY_TEXT },        /* TELETEXT */
-       { 0x02, 0x04, KEY_EPG },         /* EPG */
-       { 0x02, 0x15, KEY_MENU },        /* MENU */
-
-       { 0x03, 0x03, KEY_CHANNELUP },   /* CH UP */
-       { 0x03, 0x02, KEY_CHANNELDOWN }, /* CH DOWN */
-       { 0x03, 0x01, KEY_FIRST },       /* |<< / GREEN */
-       { 0x03, 0x00, KEY_LAST },        /* >>| / BLUE */
+       { 0x0201, KEY_PROG1 },       /* SOURCE */
+       { 0x0200, KEY_POWER },       /* POWER */
+       { 0x0205, KEY_1 },           /* 1 */
+       { 0x0206, KEY_2 },           /* 2 */
+       { 0x0207, KEY_3 },           /* 3 */
+       { 0x0209, KEY_4 },           /* 4 */
+       { 0x020a, KEY_5 },           /* 5 */
+       { 0x020b, KEY_6 },           /* 6 */
+       { 0x020d, KEY_7 },           /* 7 */
+       { 0x020e, KEY_8 },           /* 8 */
+       { 0x020f, KEY_9 },           /* 9 */
+       { 0x0212, KEY_LEFT },        /* L / DISPLAY */
+       { 0x0211, KEY_0 },           /* 0 */
+       { 0x0213, KEY_RIGHT },       /* R / CH RTN */
+       { 0x0217, KEY_PROG2 },       /* SNAP SHOT */
+       { 0x0210, KEY_PROG3 },       /* 16-CH PREV */
+       { 0x021e, KEY_VOLUMEDOWN },  /* VOL DOWN */
+       { 0x020c, KEY_ZOOM },        /* FULL SCREEN */
+       { 0x021f, KEY_VOLUMEUP },    /* VOL UP */
+       { 0x0214, KEY_MUTE },        /* MUTE */
+       { 0x0208, KEY_AUDIO },       /* AUDIO */
+       { 0x0219, KEY_RECORD },      /* RECORD */
+       { 0x0218, KEY_PLAY },        /* PLAY */
+       { 0x021b, KEY_STOP },        /* STOP */
+       { 0x021a, KEY_PLAYPAUSE },   /* TIMESHIFT / PAUSE */
+       { 0x021d, KEY_BACK },        /* << / RED */
+       { 0x021c, KEY_FORWARD },     /* >> / YELLOW */
+       { 0x0203, KEY_TEXT },        /* TELETEXT */
+       { 0x0204, KEY_EPG },         /* EPG */
+       { 0x0215, KEY_MENU },        /* MENU */
+
+       { 0x0303, KEY_CHANNELUP },   /* CH UP */
+       { 0x0302, KEY_CHANNELDOWN }, /* CH DOWN */
+       { 0x0301, KEY_FIRST },       /* |<< / GREEN */
+       { 0x0300, KEY_LAST },        /* >>| / BLUE */
 
 };
 
index 7c596f926764376d8ebfdd24c5f7f8f9f576d4e0..f4379c650a196aef468926fe3a620cbde8c51371 100644 (file)
@@ -35,43 +35,43 @@ MODULE_PARM_DESC(debug,
 
 struct dvb_usb_rc_key af9005_rc_keys[] = {
 
-       {0x01, 0xb7, KEY_POWER},
-       {0x01, 0xa7, KEY_VOLUMEUP},
-       {0x01, 0x87, KEY_CHANNELUP},
-       {0x01, 0x7f, KEY_MUTE},
-       {0x01, 0xbf, KEY_VOLUMEDOWN},
-       {0x01, 0x3f, KEY_CHANNELDOWN},
-       {0x01, 0xdf, KEY_1},
-       {0x01, 0x5f, KEY_2},
-       {0x01, 0x9f, KEY_3},
-       {0x01, 0x1f, KEY_4},
-       {0x01, 0xef, KEY_5},
-       {0x01, 0x6f, KEY_6},
-       {0x01, 0xaf, KEY_7},
-       {0x01, 0x27, KEY_8},
-       {0x01, 0x07, KEY_9},
-       {0x01, 0xcf, KEY_ZOOM},
-       {0x01, 0x4f, KEY_0},
-       {0x01, 0x8f, KEY_GOTO}, /* marked jump on the remote */
+       {0x01b7, KEY_POWER},
+       {0x01a7, KEY_VOLUMEUP},
+       {0x0187, KEY_CHANNELUP},
+       {0x017f, KEY_MUTE},
+       {0x01bf, KEY_VOLUMEDOWN},
+       {0x013f, KEY_CHANNELDOWN},
+       {0x01df, KEY_1},
+       {0x015f, KEY_2},
+       {0x019f, KEY_3},
+       {0x011f, KEY_4},
+       {0x01ef, KEY_5},
+       {0x016f, KEY_6},
+       {0x01af, KEY_7},
+       {0x0127, KEY_8},
+       {0x0107, KEY_9},
+       {0x01cf, KEY_ZOOM},
+       {0x014f, KEY_0},
+       {0x018f, KEY_GOTO},     /* marked jump on the remote */
 
-       {0x00, 0xbd, KEY_POWER},
-       {0x00, 0x7d, KEY_VOLUMEUP},
-       {0x00, 0xfd, KEY_CHANNELUP},
-       {0x00, 0x9d, KEY_MUTE},
-       {0x00, 0x5d, KEY_VOLUMEDOWN},
-       {0x00, 0xdd, KEY_CHANNELDOWN},
-       {0x00, 0xad, KEY_1},
-       {0x00, 0x6d, KEY_2},
-       {0x00, 0xed, KEY_3},
-       {0x00, 0x8d, KEY_4},
-       {0x00, 0x4d, KEY_5},
-       {0x00, 0xcd, KEY_6},
-       {0x00, 0xb5, KEY_7},
-       {0x00, 0x75, KEY_8},
-       {0x00, 0xf5, KEY_9},
-       {0x00, 0x95, KEY_ZOOM},
-       {0x00, 0x55, KEY_0},
-       {0x00, 0xd5, KEY_GOTO}, /* marked jump on the remote */
+       {0x00bd, KEY_POWER},
+       {0x007d, KEY_VOLUMEUP},
+       {0x00fd, KEY_CHANNELUP},
+       {0x009d, KEY_MUTE},
+       {0x005d, KEY_VOLUMEDOWN},
+       {0x00dd, KEY_CHANNELDOWN},
+       {0x00ad, KEY_1},
+       {0x006d, KEY_2},
+       {0x00ed, KEY_3},
+       {0x008d, KEY_4},
+       {0x004d, KEY_5},
+       {0x00cd, KEY_6},
+       {0x00b5, KEY_7},
+       {0x0075, KEY_8},
+       {0x00f5, KEY_9},
+       {0x0095, KEY_ZOOM},
+       {0x0055, KEY_0},
+       {0x00d5, KEY_GOTO},     /* marked jump on the remote */
 };
 
 int af9005_rc_keys_size = ARRAY_SIZE(af9005_rc_keys);
@@ -131,8 +131,8 @@ int af9005_rc_decode(struct dvb_usb_device *d, u8 * data, int len, u32 * event,
                                return 0;
                        }
                        for (i = 0; i < af9005_rc_keys_size; i++) {
-                               if (af9005_rc_keys[i].custom == cust
-                                   && af9005_rc_keys[i].data == dat) {
+                               if (rc5_custom(&af9005_rc_keys[i]) == cust
+                                   && rc5_data(&af9005_rc_keys[i]) == dat) {
                                        *event = af9005_rc_keys[i].event;
                                        *state = REMOTE_KEY_PRESSED;
                                        deb_decode
index 26690dfb32601b9fcde1825ba41d18392b663d08..99cdd0d101cac01cc042768eda00db00a7677a57 100644 (file)
@@ -538,24 +538,22 @@ exit:
 /* dump eeprom */
 static int af9015_eeprom_dump(struct dvb_usb_device *d)
 {
-       char buf[4+3*16+1], buf2[4];
        u8 reg, val;
 
        for (reg = 0; ; reg++) {
                if (reg % 16 == 0) {
                        if (reg)
-                               deb_info("%s\n", buf);
-                       sprintf(buf, "%02x: ", reg);
+                               deb_info(KERN_CONT "\n");
+                       deb_info(KERN_DEBUG "%02x:", reg);
                }
                if (af9015_read_reg_i2c(d, AF9015_I2C_EEPROM, reg, &val) == 0)
-                       sprintf(buf2, "%02x ", val);
+                       deb_info(KERN_CONT " %02x", val);
                else
-                       strcpy(buf2, "-- ");
-               strcat(buf, buf2);
+                       deb_info(KERN_CONT " --");
                if (reg == 0xff)
                        break;
        }
-       deb_info("%s\n", buf);
+       deb_info(KERN_CONT "\n");
        return 0;
 }
 
@@ -1045,8 +1043,8 @@ static int af9015_rc_query(struct dvb_usb_device *d, u32 *event, int *state)
        *state = REMOTE_NO_KEY_PRESSED;
 
        for (i = 0; i < d->props.rc_key_map_size; i++) {
-               if (!buf[1] && keymap[i].custom == buf[0] &&
-                   keymap[i].data == buf[2]) {
+               if (!buf[1] && rc5_custom(&keymap[i]) == buf[0] &&
+                   rc5_data(&keymap[i]) == buf[2]) {
                        *event = keymap[i].event;
                        *state = REMOTE_KEY_PRESSED;
                        break;
@@ -1266,6 +1264,7 @@ static struct usb_device_id af9015_usb_table[] = {
        {USB_DEVICE(USB_VID_KWORLD_2,  USB_PID_CONCEPTRONIC_CTVDIGRCU)},
        {USB_DEVICE(USB_VID_KWORLD_2,  USB_PID_KWORLD_MC810)},
        {USB_DEVICE(USB_VID_KYE,       USB_PID_GENIUS_TVGO_DVB_T03)},
+/* 25 */{USB_DEVICE(USB_VID_KWORLD_2,  USB_PID_KWORLD_399U_2)},
        {0},
 };
 MODULE_DEVICE_TABLE(usb, af9015_usb_table);
@@ -1346,7 +1345,8 @@ static struct dvb_usb_device_properties af9015_properties[] = {
                        {
                                .name = "KWorld PlusTV Dual DVB-T Stick " \
                                        "(DVB-T 399U)",
-                               .cold_ids = {&af9015_usb_table[4], NULL},
+                               .cold_ids = {&af9015_usb_table[4],
+                                            &af9015_usb_table[25], NULL},
                                .warm_ids = {NULL},
                        },
                        {
index 8d81a17c116d773d6d3df53f7e9737e12cbe1b6a..c41f30e4a1b8c7ba0828f0fedee1163eee4414d3 100644 (file)
@@ -121,21 +121,21 @@ enum af9015_remote {
 
 /* Leadtek WinFast DTV Dongle Gold */
 static struct dvb_usb_rc_key af9015_rc_keys_leadtek[] = {
-       { 0x00, 0x1e, KEY_1 },
-       { 0x00, 0x1f, KEY_2 },
-       { 0x00, 0x20, KEY_3 },
-       { 0x00, 0x21, KEY_4 },
-       { 0x00, 0x22, KEY_5 },
-       { 0x00, 0x23, KEY_6 },
-       { 0x00, 0x24, KEY_7 },
-       { 0x00, 0x25, KEY_8 },
-       { 0x00, 0x26, KEY_9 },
-       { 0x00, 0x27, KEY_0 },
-       { 0x00, 0x28, KEY_ENTER },
-       { 0x00, 0x4f, KEY_VOLUMEUP },
-       { 0x00, 0x50, KEY_VOLUMEDOWN },
-       { 0x00, 0x51, KEY_CHANNELDOWN },
-       { 0x00, 0x52, KEY_CHANNELUP },
+       { 0x001e, KEY_1 },
+       { 0x001f, KEY_2 },
+       { 0x0020, KEY_3 },
+       { 0x0021, KEY_4 },
+       { 0x0022, KEY_5 },
+       { 0x0023, KEY_6 },
+       { 0x0024, KEY_7 },
+       { 0x0025, KEY_8 },
+       { 0x0026, KEY_9 },
+       { 0x0027, KEY_0 },
+       { 0x0028, KEY_ENTER },
+       { 0x004f, KEY_VOLUMEUP },
+       { 0x0050, KEY_VOLUMEDOWN },
+       { 0x0051, KEY_CHANNELDOWN },
+       { 0x0052, KEY_CHANNELUP },
 };
 
 static u8 af9015_ir_table_leadtek[] = {
@@ -193,60 +193,60 @@ static u8 af9015_ir_table_leadtek[] = {
 
 /* TwinHan AzureWave AD-TU700(704J) */
 static struct dvb_usb_rc_key af9015_rc_keys_twinhan[] = {
-       { 0x05, 0x3f, KEY_POWER },
-       { 0x00, 0x19, KEY_FAVORITES },    /* Favorite List */
-       { 0x00, 0x04, KEY_TEXT },         /* Teletext */
-       { 0x00, 0x0e, KEY_POWER },
-       { 0x00, 0x0e, KEY_INFO },         /* Preview */
-       { 0x00, 0x08, KEY_EPG },          /* Info/EPG */
-       { 0x00, 0x0f, KEY_LIST },         /* Record List */
-       { 0x00, 0x1e, KEY_1 },
-       { 0x00, 0x1f, KEY_2 },
-       { 0x00, 0x20, KEY_3 },
-       { 0x00, 0x21, KEY_4 },
-       { 0x00, 0x22, KEY_5 },
-       { 0x00, 0x23, KEY_6 },
-       { 0x00, 0x24, KEY_7 },
-       { 0x00, 0x25, KEY_8 },
-       { 0x00, 0x26, KEY_9 },
-       { 0x00, 0x27, KEY_0 },
-       { 0x00, 0x29, KEY_CANCEL },       /* Cancel */
-       { 0x00, 0x4c, KEY_CLEAR },        /* Clear */
-       { 0x00, 0x2a, KEY_BACK },         /* Back */
-       { 0x00, 0x2b, KEY_TAB },          /* Tab */
-       { 0x00, 0x52, KEY_UP },           /* up arrow */
-       { 0x00, 0x51, KEY_DOWN },         /* down arrow */
-       { 0x00, 0x4f, KEY_RIGHT },        /* right arrow */
-       { 0x00, 0x50, KEY_LEFT },         /* left arrow */
-       { 0x00, 0x28, KEY_ENTER },        /* Enter / ok */
-       { 0x02, 0x52, KEY_VOLUMEUP },
-       { 0x02, 0x51, KEY_VOLUMEDOWN },
-       { 0x00, 0x4e, KEY_CHANNELDOWN },
-       { 0x00, 0x4b, KEY_CHANNELUP },
-       { 0x00, 0x4a, KEY_RECORD },
-       { 0x01, 0x11, KEY_PLAY },
-       { 0x00, 0x17, KEY_PAUSE },
-       { 0x00, 0x0c, KEY_REWIND },       /* FR << */
-       { 0x00, 0x11, KEY_FASTFORWARD },  /* FF >> */
-       { 0x01, 0x15, KEY_PREVIOUS },     /* Replay */
-       { 0x01, 0x0e, KEY_NEXT },         /* Skip */
-       { 0x00, 0x13, KEY_CAMERA },       /* Capture */
-       { 0x01, 0x0f, KEY_LANGUAGE },     /* SAP */
-       { 0x01, 0x13, KEY_TV2 },          /* PIP */
-       { 0x00, 0x1d, KEY_ZOOM },         /* Full Screen */
-       { 0x01, 0x17, KEY_SUBTITLE },     /* Subtitle / CC */
-       { 0x00, 0x10, KEY_MUTE },
-       { 0x01, 0x19, KEY_AUDIO },        /* L/R */ /* TODO better event */
-       { 0x01, 0x16, KEY_SLEEP },        /* Hibernate */
-       { 0x01, 0x16, KEY_SWITCHVIDEOMODE },
+       { 0x053f, KEY_POWER },
+       { 0x0019, KEY_FAVORITES },    /* Favorite List */
+       { 0x0004, KEY_TEXT },         /* Teletext */
+       { 0x000e, KEY_POWER },
+       { 0x000e, KEY_INFO },         /* Preview */
+       { 0x0008, KEY_EPG },          /* Info/EPG */
+       { 0x000f, KEY_LIST },         /* Record List */
+       { 0x001e, KEY_1 },
+       { 0x001f, KEY_2 },
+       { 0x0020, KEY_3 },
+       { 0x0021, KEY_4 },
+       { 0x0022, KEY_5 },
+       { 0x0023, KEY_6 },
+       { 0x0024, KEY_7 },
+       { 0x0025, KEY_8 },
+       { 0x0026, KEY_9 },
+       { 0x0027, KEY_0 },
+       { 0x0029, KEY_CANCEL },       /* Cancel */
+       { 0x004c, KEY_CLEAR },        /* Clear */
+       { 0x002a, KEY_BACK },         /* Back */
+       { 0x002b, KEY_TAB },          /* Tab */
+       { 0x0052, KEY_UP },           /* up arrow */
+       { 0x0051, KEY_DOWN },         /* down arrow */
+       { 0x004f, KEY_RIGHT },        /* right arrow */
+       { 0x0050, KEY_LEFT },         /* left arrow */
+       { 0x0028, KEY_ENTER },        /* Enter / ok */
+       { 0x0252, KEY_VOLUMEUP },
+       { 0x0251, KEY_VOLUMEDOWN },
+       { 0x004e, KEY_CHANNELDOWN },
+       { 0x004b, KEY_CHANNELUP },
+       { 0x004a, KEY_RECORD },
+       { 0x0111, KEY_PLAY },
+       { 0x0017, KEY_PAUSE },
+       { 0x000c, KEY_REWIND },       /* FR << */
+       { 0x0011, KEY_FASTFORWARD },  /* FF >> */
+       { 0x0115, KEY_PREVIOUS },     /* Replay */
+       { 0x010e, KEY_NEXT },         /* Skip */
+       { 0x0013, KEY_CAMERA },       /* Capture */
+       { 0x010f, KEY_LANGUAGE },     /* SAP */
+       { 0x0113, KEY_TV2 },          /* PIP */
+       { 0x001d, KEY_ZOOM },         /* Full Screen */
+       { 0x0117, KEY_SUBTITLE },     /* Subtitle / CC */
+       { 0x0010, KEY_MUTE },
+       { 0x0119, KEY_AUDIO },        /* L/R */ /* TODO better event */
+       { 0x0116, KEY_SLEEP },        /* Hibernate */
+       { 0x0116, KEY_SWITCHVIDEOMODE },
                                          /* A/V */ /* TODO does not work */
-       { 0x00, 0x06, KEY_AGAIN },        /* Recall */
-       { 0x01, 0x16, KEY_KPPLUS },       /* Zoom+ */ /* TODO does not work */
-       { 0x01, 0x16, KEY_KPMINUS },      /* Zoom- */ /* TODO does not work */
-       { 0x02, 0x15, KEY_RED },
-       { 0x02, 0x0a, KEY_GREEN },
-       { 0x02, 0x1c, KEY_YELLOW },
-       { 0x02, 0x05, KEY_BLUE },
+       { 0x0006, KEY_AGAIN },        /* Recall */
+       { 0x0116, KEY_KPPLUS },       /* Zoom+ */ /* TODO does not work */
+       { 0x0116, KEY_KPMINUS },      /* Zoom- */ /* TODO does not work */
+       { 0x0215, KEY_RED },
+       { 0x020a, KEY_GREEN },
+       { 0x021c, KEY_YELLOW },
+       { 0x0205, KEY_BLUE },
 };
 
 static u8 af9015_ir_table_twinhan[] = {
@@ -304,24 +304,24 @@ static u8 af9015_ir_table_twinhan[] = {
 
 /* A-Link DTU(m) */
 static struct dvb_usb_rc_key af9015_rc_keys_a_link[] = {
-       { 0x00, 0x1e, KEY_1 },
-       { 0x00, 0x1f, KEY_2 },
-       { 0x00, 0x20, KEY_3 },
-       { 0x00, 0x21, KEY_4 },
-       { 0x00, 0x22, KEY_5 },
-       { 0x00, 0x23, KEY_6 },
-       { 0x00, 0x24, KEY_7 },
-       { 0x00, 0x25, KEY_8 },
-       { 0x00, 0x26, KEY_9 },
-       { 0x00, 0x27, KEY_0 },
-       { 0x00, 0x2e, KEY_CHANNELUP },
-       { 0x00, 0x2d, KEY_CHANNELDOWN },
-       { 0x04, 0x28, KEY_ZOOM },
-       { 0x00, 0x41, KEY_MUTE },
-       { 0x00, 0x42, KEY_VOLUMEDOWN },
-       { 0x00, 0x43, KEY_VOLUMEUP },
-       { 0x00, 0x44, KEY_GOTO },         /* jump */
-       { 0x05, 0x45, KEY_POWER },
+       { 0x001e, KEY_1 },
+       { 0x001f, KEY_2 },
+       { 0x0020, KEY_3 },
+       { 0x0021, KEY_4 },
+       { 0x0022, KEY_5 },
+       { 0x0023, KEY_6 },
+       { 0x0024, KEY_7 },
+       { 0x0025, KEY_8 },
+       { 0x0026, KEY_9 },
+       { 0x0027, KEY_0 },
+       { 0x002e, KEY_CHANNELUP },
+       { 0x002d, KEY_CHANNELDOWN },
+       { 0x0428, KEY_ZOOM },
+       { 0x0041, KEY_MUTE },
+       { 0x0042, KEY_VOLUMEDOWN },
+       { 0x0043, KEY_VOLUMEUP },
+       { 0x0044, KEY_GOTO },         /* jump */
+       { 0x0545, KEY_POWER },
 };
 
 static u8 af9015_ir_table_a_link[] = {
@@ -347,24 +347,24 @@ static u8 af9015_ir_table_a_link[] = {
 
 /* MSI DIGIVOX mini II V3.0 */
 static struct dvb_usb_rc_key af9015_rc_keys_msi[] = {
-       { 0x00, 0x1e, KEY_1 },
-       { 0x00, 0x1f, KEY_2 },
-       { 0x00, 0x20, KEY_3 },
-       { 0x00, 0x21, KEY_4 },
-       { 0x00, 0x22, KEY_5 },
-       { 0x00, 0x23, KEY_6 },
-       { 0x00, 0x24, KEY_7 },
-       { 0x00, 0x25, KEY_8 },
-       { 0x00, 0x26, KEY_9 },
-       { 0x00, 0x27, KEY_0 },
-       { 0x03, 0x0f, KEY_CHANNELUP },
-       { 0x03, 0x0e, KEY_CHANNELDOWN },
-       { 0x00, 0x42, KEY_VOLUMEDOWN },
-       { 0x00, 0x43, KEY_VOLUMEUP },
-       { 0x05, 0x45, KEY_POWER },
-       { 0x00, 0x52, KEY_UP },           /* up */
-       { 0x00, 0x51, KEY_DOWN },         /* down */
-       { 0x00, 0x28, KEY_ENTER },
+       { 0x001e, KEY_1 },
+       { 0x001f, KEY_2 },
+       { 0x0020, KEY_3 },
+       { 0x0021, KEY_4 },
+       { 0x0022, KEY_5 },
+       { 0x0023, KEY_6 },
+       { 0x0024, KEY_7 },
+       { 0x0025, KEY_8 },
+       { 0x0026, KEY_9 },
+       { 0x0027, KEY_0 },
+       { 0x030f, KEY_CHANNELUP },
+       { 0x030e, KEY_CHANNELDOWN },
+       { 0x0042, KEY_VOLUMEDOWN },
+       { 0x0043, KEY_VOLUMEUP },
+       { 0x0545, KEY_POWER },
+       { 0x0052, KEY_UP },           /* up */
+       { 0x0051, KEY_DOWN },         /* down */
+       { 0x0028, KEY_ENTER },
 };
 
 static u8 af9015_ir_table_msi[] = {
@@ -390,42 +390,42 @@ static u8 af9015_ir_table_msi[] = {
 
 /* MYGICTV U718 */
 static struct dvb_usb_rc_key af9015_rc_keys_mygictv[] = {
-       { 0x00, 0x3d, KEY_SWITCHVIDEOMODE },
+       { 0x003d, KEY_SWITCHVIDEOMODE },
                                          /* TV / AV */
-       { 0x05, 0x45, KEY_POWER },
-       { 0x00, 0x1e, KEY_1 },
-       { 0x00, 0x1f, KEY_2 },
-       { 0x00, 0x20, KEY_3 },
-       { 0x00, 0x21, KEY_4 },
-       { 0x00, 0x22, KEY_5 },
-       { 0x00, 0x23, KEY_6 },
-       { 0x00, 0x24, KEY_7 },
-       { 0x00, 0x25, KEY_8 },
-       { 0x00, 0x26, KEY_9 },
-       { 0x00, 0x27, KEY_0 },
-       { 0x00, 0x41, KEY_MUTE },
-       { 0x00, 0x2a, KEY_ESC },          /* Esc */
-       { 0x00, 0x2e, KEY_CHANNELUP },
-       { 0x00, 0x2d, KEY_CHANNELDOWN },
-       { 0x00, 0x42, KEY_VOLUMEDOWN },
-       { 0x00, 0x43, KEY_VOLUMEUP },
-       { 0x00, 0x52, KEY_UP },           /* up arrow */
-       { 0x00, 0x51, KEY_DOWN },         /* down arrow */
-       { 0x00, 0x4f, KEY_RIGHT },        /* right arrow */
-       { 0x00, 0x50, KEY_LEFT },         /* left arrow */
-       { 0x00, 0x28, KEY_ENTER },        /* ok */
-       { 0x01, 0x15, KEY_RECORD },
-       { 0x03, 0x13, KEY_PLAY },
-       { 0x01, 0x13, KEY_PAUSE },
-       { 0x01, 0x16, KEY_STOP },
-       { 0x03, 0x07, KEY_REWIND },       /* FR << */
-       { 0x03, 0x09, KEY_FASTFORWARD },  /* FF >> */
-       { 0x00, 0x3b, KEY_TIME },         /* TimeShift */
-       { 0x00, 0x3e, KEY_CAMERA },       /* Snapshot */
-       { 0x03, 0x16, KEY_CYCLEWINDOWS }, /* yellow, min / max */
-       { 0x00, 0x00, KEY_ZOOM },         /* 'select' (?) */
-       { 0x03, 0x16, KEY_SHUFFLE },      /* Shuffle */
-       { 0x03, 0x45, KEY_POWER },
+       { 0x0545, KEY_POWER },
+       { 0x001e, KEY_1 },
+       { 0x001f, KEY_2 },
+       { 0x0020, KEY_3 },
+       { 0x0021, KEY_4 },
+       { 0x0022, KEY_5 },
+       { 0x0023, KEY_6 },
+       { 0x0024, KEY_7 },
+       { 0x0025, KEY_8 },
+       { 0x0026, KEY_9 },
+       { 0x0027, KEY_0 },
+       { 0x0041, KEY_MUTE },
+       { 0x002a, KEY_ESC },          /* Esc */
+       { 0x002e, KEY_CHANNELUP },
+       { 0x002d, KEY_CHANNELDOWN },
+       { 0x0042, KEY_VOLUMEDOWN },
+       { 0x0043, KEY_VOLUMEUP },
+       { 0x0052, KEY_UP },           /* up arrow */
+       { 0x0051, KEY_DOWN },         /* down arrow */
+       { 0x004f, KEY_RIGHT },        /* right arrow */
+       { 0x0050, KEY_LEFT },         /* left arrow */
+       { 0x0028, KEY_ENTER },        /* ok */
+       { 0x0115, KEY_RECORD },
+       { 0x0313, KEY_PLAY },
+       { 0x0113, KEY_PAUSE },
+       { 0x0116, KEY_STOP },
+       { 0x0307, KEY_REWIND },       /* FR << */
+       { 0x0309, KEY_FASTFORWARD },  /* FF >> */
+       { 0x003b, KEY_TIME },         /* TimeShift */
+       { 0x003e, KEY_CAMERA },       /* Snapshot */
+       { 0x0316, KEY_CYCLEWINDOWS }, /* yellow, min / max */
+       { 0x0000, KEY_ZOOM },         /* 'select' (?) */
+       { 0x0316, KEY_SHUFFLE },      /* Shuffle */
+       { 0x0345, KEY_POWER },
 };
 
 static u8 af9015_ir_table_mygictv[] = {
@@ -516,41 +516,41 @@ static u8 af9015_ir_table_kworld[] = {
 
 /* AverMedia Volar X */
 static struct dvb_usb_rc_key af9015_rc_keys_avermedia[] = {
-       { 0x05, 0x3d, KEY_PROG1 },       /* SOURCE */
-       { 0x05, 0x12, KEY_POWER },       /* POWER */
-       { 0x05, 0x1e, KEY_1 },           /* 1 */
-       { 0x05, 0x1f, KEY_2 },           /* 2 */
-       { 0x05, 0x20, KEY_3 },           /* 3 */
-       { 0x05, 0x21, KEY_4 },           /* 4 */
-       { 0x05, 0x22, KEY_5 },           /* 5 */
-       { 0x05, 0x23, KEY_6 },           /* 6 */
-       { 0x05, 0x24, KEY_7 },           /* 7 */
-       { 0x05, 0x25, KEY_8 },           /* 8 */
-       { 0x05, 0x26, KEY_9 },           /* 9 */
-       { 0x05, 0x3f, KEY_LEFT },        /* L / DISPLAY */
-       { 0x05, 0x27, KEY_0 },           /* 0 */
-       { 0x05, 0x0f, KEY_RIGHT },       /* R / CH RTN */
-       { 0x05, 0x18, KEY_PROG2 },       /* SNAP SHOT */
-       { 0x05, 0x1c, KEY_PROG3 },       /* 16-CH PREV */
-       { 0x05, 0x2d, KEY_VOLUMEDOWN },  /* VOL DOWN */
-       { 0x05, 0x3e, KEY_ZOOM },        /* FULL SCREEN */
-       { 0x05, 0x2e, KEY_VOLUMEUP },    /* VOL UP */
-       { 0x05, 0x10, KEY_MUTE },        /* MUTE */
-       { 0x05, 0x04, KEY_AUDIO },       /* AUDIO */
-       { 0x05, 0x15, KEY_RECORD },      /* RECORD */
-       { 0x05, 0x11, KEY_PLAY },        /* PLAY */
-       { 0x05, 0x16, KEY_STOP },        /* STOP */
-       { 0x05, 0x0c, KEY_PLAYPAUSE },   /* TIMESHIFT / PAUSE */
-       { 0x05, 0x05, KEY_BACK },        /* << / RED */
-       { 0x05, 0x09, KEY_FORWARD },     /* >> / YELLOW */
-       { 0x05, 0x17, KEY_TEXT },        /* TELETEXT */
-       { 0x05, 0x0a, KEY_EPG },         /* EPG */
-       { 0x05, 0x13, KEY_MENU },        /* MENU */
-
-       { 0x05, 0x0e, KEY_CHANNELUP },   /* CH UP */
-       { 0x05, 0x0d, KEY_CHANNELDOWN }, /* CH DOWN */
-       { 0x05, 0x19, KEY_FIRST },       /* |<< / GREEN */
-       { 0x05, 0x08, KEY_LAST },        /* >>| / BLUE */
+       { 0x053d, KEY_PROG1 },       /* SOURCE */
+       { 0x0512, KEY_POWER },       /* POWER */
+       { 0x051e, KEY_1 },           /* 1 */
+       { 0x051f, KEY_2 },           /* 2 */
+       { 0x0520, KEY_3 },           /* 3 */
+       { 0x0521, KEY_4 },           /* 4 */
+       { 0x0522, KEY_5 },           /* 5 */
+       { 0x0523, KEY_6 },           /* 6 */
+       { 0x0524, KEY_7 },           /* 7 */
+       { 0x0525, KEY_8 },           /* 8 */
+       { 0x0526, KEY_9 },           /* 9 */
+       { 0x053f, KEY_LEFT },        /* L / DISPLAY */
+       { 0x0527, KEY_0 },           /* 0 */
+       { 0x050f, KEY_RIGHT },       /* R / CH RTN */
+       { 0x0518, KEY_PROG2 },       /* SNAP SHOT */
+       { 0x051c, KEY_PROG3 },       /* 16-CH PREV */
+       { 0x052d, KEY_VOLUMEDOWN },  /* VOL DOWN */
+       { 0x053e, KEY_ZOOM },        /* FULL SCREEN */
+       { 0x052e, KEY_VOLUMEUP },    /* VOL UP */
+       { 0x0510, KEY_MUTE },        /* MUTE */
+       { 0x0504, KEY_AUDIO },       /* AUDIO */
+       { 0x0515, KEY_RECORD },      /* RECORD */
+       { 0x0511, KEY_PLAY },        /* PLAY */
+       { 0x0516, KEY_STOP },        /* STOP */
+       { 0x050c, KEY_PLAYPAUSE },   /* TIMESHIFT / PAUSE */
+       { 0x0505, KEY_BACK },        /* << / RED */
+       { 0x0509, KEY_FORWARD },     /* >> / YELLOW */
+       { 0x0517, KEY_TEXT },        /* TELETEXT */
+       { 0x050a, KEY_EPG },         /* EPG */
+       { 0x0513, KEY_MENU },        /* MENU */
+
+       { 0x050e, KEY_CHANNELUP },   /* CH UP */
+       { 0x050d, KEY_CHANNELDOWN }, /* CH DOWN */
+       { 0x0519, KEY_FIRST },       /* |<< / GREEN */
+       { 0x0508, KEY_LAST },        /* >>| / BLUE */
 };
 
 static u8 af9015_ir_table_avermedia[] = {
@@ -622,34 +622,34 @@ static u8 af9015_ir_table_avermedia_ks[] = {
 
 /* Digittrade DVB-T USB Stick */
 static struct dvb_usb_rc_key af9015_rc_keys_digittrade[] = {
-       { 0x01, 0x0f, KEY_LAST },       /* RETURN */
-       { 0x05, 0x17, KEY_TEXT },       /* TELETEXT */
-       { 0x01, 0x08, KEY_EPG },        /* EPG */
-       { 0x05, 0x13, KEY_POWER },      /* POWER */
-       { 0x01, 0x09, KEY_ZOOM },       /* FULLSCREEN */
-       { 0x00, 0x40, KEY_AUDIO },      /* DUAL SOUND */
-       { 0x00, 0x2c, KEY_PRINT },      /* SNAPSHOT */
-       { 0x05, 0x16, KEY_SUBTITLE },   /* SUBTITLE */
-       { 0x00, 0x52, KEY_CHANNELUP },  /* CH Up */
-       { 0x00, 0x51, KEY_CHANNELDOWN },/* Ch Dn */
-       { 0x00, 0x57, KEY_VOLUMEUP },   /* Vol Up */
-       { 0x00, 0x56, KEY_VOLUMEDOWN }, /* Vol Dn */
-       { 0x01, 0x10, KEY_MUTE },       /* MUTE */
-       { 0x00, 0x27, KEY_0 },
-       { 0x00, 0x1e, KEY_1 },
-       { 0x00, 0x1f, KEY_2 },
-       { 0x00, 0x20, KEY_3 },
-       { 0x00, 0x21, KEY_4 },
-       { 0x00, 0x22, KEY_5 },
-       { 0x00, 0x23, KEY_6 },
-       { 0x00, 0x24, KEY_7 },
-       { 0x00, 0x25, KEY_8 },
-       { 0x00, 0x26, KEY_9 },
-       { 0x01, 0x17, KEY_PLAYPAUSE },  /* TIMESHIFT */
-       { 0x01, 0x15, KEY_RECORD },     /* RECORD */
-       { 0x03, 0x13, KEY_PLAY },       /* PLAY */
-       { 0x01, 0x16, KEY_STOP },       /* STOP */
-       { 0x01, 0x13, KEY_PAUSE },      /* PAUSE */
+       { 0x010f, KEY_LAST },   /* RETURN */
+       { 0x0517, KEY_TEXT },   /* TELETEXT */
+       { 0x0108, KEY_EPG },    /* EPG */
+       { 0x0513, KEY_POWER },  /* POWER */
+       { 0x0109, KEY_ZOOM },   /* FULLSCREEN */
+       { 0x0040, KEY_AUDIO },  /* DUAL SOUND */
+       { 0x002c, KEY_PRINT },  /* SNAPSHOT */
+       { 0x0516, KEY_SUBTITLE },       /* SUBTITLE */
+       { 0x0052, KEY_CHANNELUP },      /* CH Up */
+       { 0x0051, KEY_CHANNELDOWN },/* Ch Dn */
+       { 0x0057, KEY_VOLUMEUP },       /* Vol Up */
+       { 0x0056, KEY_VOLUMEDOWN },     /* Vol Dn */
+       { 0x0110, KEY_MUTE },   /* MUTE */
+       { 0x0027, KEY_0 },
+       { 0x001e, KEY_1 },
+       { 0x001f, KEY_2 },
+       { 0x0020, KEY_3 },
+       { 0x0021, KEY_4 },
+       { 0x0022, KEY_5 },
+       { 0x0023, KEY_6 },
+       { 0x0024, KEY_7 },
+       { 0x0025, KEY_8 },
+       { 0x0026, KEY_9 },
+       { 0x0117, KEY_PLAYPAUSE },      /* TIMESHIFT */
+       { 0x0115, KEY_RECORD }, /* RECORD */
+       { 0x0313, KEY_PLAY },   /* PLAY */
+       { 0x0116, KEY_STOP },   /* STOP */
+       { 0x0113, KEY_PAUSE },  /* PAUSE */
 };
 
 static u8 af9015_ir_table_digittrade[] = {
@@ -685,34 +685,34 @@ static u8 af9015_ir_table_digittrade[] = {
 
 /* TREKSTOR DVB-T USB Stick */
 static struct dvb_usb_rc_key af9015_rc_keys_trekstor[] = {
-       { 0x07, 0x04, KEY_AGAIN },              /* Home */
-       { 0x07, 0x05, KEY_MUTE },               /* Mute */
-       { 0x07, 0x06, KEY_UP },                 /* Up */
-       { 0x07, 0x07, KEY_DOWN },               /* Down */
-       { 0x07, 0x09, KEY_RIGHT },              /* Right */
-       { 0x07, 0x0a, KEY_ENTER },              /* OK */
-       { 0x07, 0x0b, KEY_FASTFORWARD },        /* Fast forward */
-       { 0x07, 0x0c, KEY_REWIND },             /* Rewind */
-       { 0x07, 0x0d, KEY_PLAY },               /* Play/Pause */
-       { 0x07, 0x0e, KEY_VOLUMEUP },           /* Volume + */
-       { 0x07, 0x0f, KEY_VOLUMEDOWN },         /* Volume - */
-       { 0x07, 0x10, KEY_RECORD },             /* Record */
-       { 0x07, 0x11, KEY_STOP },               /* Stop */
-       { 0x07, 0x12, KEY_ZOOM },               /* TV */
-       { 0x07, 0x13, KEY_EPG },                /* Info/EPG */
-       { 0x07, 0x14, KEY_CHANNELDOWN },        /* Channel - */
-       { 0x07, 0x15, KEY_CHANNELUP },          /* Channel + */
-       { 0x07, 0x1e, KEY_1 },
-       { 0x07, 0x1f, KEY_2 },
-       { 0x07, 0x20, KEY_3 },
-       { 0x07, 0x21, KEY_4 },
-       { 0x07, 0x22, KEY_5 },
-       { 0x07, 0x23, KEY_6 },
-       { 0x07, 0x24, KEY_7 },
-       { 0x07, 0x25, KEY_8 },
-       { 0x07, 0x26, KEY_9 },
-       { 0x07, 0x08, KEY_LEFT },               /* LEFT */
-       { 0x07, 0x27, KEY_0 },
+       { 0x0704, KEY_AGAIN },          /* Home */
+       { 0x0705, KEY_MUTE },           /* Mute */
+       { 0x0706, KEY_UP },                     /* Up */
+       { 0x0707, KEY_DOWN },           /* Down */
+       { 0x0709, KEY_RIGHT },          /* Right */
+       { 0x070a, KEY_ENTER },          /* OK */
+       { 0x070b, KEY_FASTFORWARD },    /* Fast forward */
+       { 0x070c, KEY_REWIND },         /* Rewind */
+       { 0x070d, KEY_PLAY },           /* Play/Pause */
+       { 0x070e, KEY_VOLUMEUP },               /* Volume + */
+       { 0x070f, KEY_VOLUMEDOWN },             /* Volume - */
+       { 0x0710, KEY_RECORD },         /* Record */
+       { 0x0711, KEY_STOP },           /* Stop */
+       { 0x0712, KEY_ZOOM },           /* TV */
+       { 0x0713, KEY_EPG },            /* Info/EPG */
+       { 0x0714, KEY_CHANNELDOWN },    /* Channel - */
+       { 0x0715, KEY_CHANNELUP },              /* Channel + */
+       { 0x071e, KEY_1 },
+       { 0x071f, KEY_2 },
+       { 0x0720, KEY_3 },
+       { 0x0721, KEY_4 },
+       { 0x0722, KEY_5 },
+       { 0x0723, KEY_6 },
+       { 0x0724, KEY_7 },
+       { 0x0725, KEY_8 },
+       { 0x0726, KEY_9 },
+       { 0x0708, KEY_LEFT },           /* LEFT */
+       { 0x0727, KEY_0 },
 };
 
 static u8 af9015_ir_table_trekstor[] = {
index c6e7b4215d6bffec89c332c9bae297749139c525..7381aff4dcf69a5273fd2fd31d38773b331fb381 100644 (file)
@@ -389,8 +389,8 @@ static int anysee_rc_query(struct dvb_usb_device *d, u32 *event, int *state)
        *state = REMOTE_NO_KEY_PRESSED;
 
        for (i = 0; i < d->props.rc_key_map_size; i++) {
-               if (keymap[i].custom == ircode[0] &&
-                   keymap[i].data == ircode[1]) {
+               if (rc5_custom(&keymap[i]) == ircode[0] &&
+                   rc5_data(&keymap[i]) == ircode[1]) {
                        *event = keymap[i].event;
                        *state = REMOTE_KEY_PRESSED;
                        return 0;
@@ -400,50 +400,50 @@ static int anysee_rc_query(struct dvb_usb_device *d, u32 *event, int *state)
 }
 
 static struct dvb_usb_rc_key anysee_rc_keys[] = {
-       { 0x01, 0x00, KEY_0 },
-       { 0x01, 0x01, KEY_1 },
-       { 0x01, 0x02, KEY_2 },
-       { 0x01, 0x03, KEY_3 },
-       { 0x01, 0x04, KEY_4 },
-       { 0x01, 0x05, KEY_5 },
-       { 0x01, 0x06, KEY_6 },
-       { 0x01, 0x07, KEY_7 },
-       { 0x01, 0x08, KEY_8 },
-       { 0x01, 0x09, KEY_9 },
-       { 0x01, 0x0a, KEY_POWER },
-       { 0x01, 0x0b, KEY_DOCUMENTS },    /* * */
-       { 0x01, 0x19, KEY_FAVORITES },
-       { 0x01, 0x20, KEY_SLEEP },
-       { 0x01, 0x21, KEY_MODE },         /* 4:3 / 16:9 select */
-       { 0x01, 0x22, KEY_ZOOM },
-       { 0x01, 0x47, KEY_TEXT },
-       { 0x01, 0x16, KEY_TV },           /* TV / radio select */
-       { 0x01, 0x1e, KEY_LANGUAGE },     /* Second Audio Program */
-       { 0x01, 0x1a, KEY_SUBTITLE },
-       { 0x01, 0x1b, KEY_CAMERA },       /* screenshot */
-       { 0x01, 0x42, KEY_MUTE },
-       { 0x01, 0x0e, KEY_MENU },
-       { 0x01, 0x0f, KEY_EPG },
-       { 0x01, 0x17, KEY_INFO },
-       { 0x01, 0x10, KEY_EXIT },
-       { 0x01, 0x13, KEY_VOLUMEUP },
-       { 0x01, 0x12, KEY_VOLUMEDOWN },
-       { 0x01, 0x11, KEY_CHANNELUP },
-       { 0x01, 0x14, KEY_CHANNELDOWN },
-       { 0x01, 0x15, KEY_OK },
-       { 0x01, 0x1d, KEY_RED },
-       { 0x01, 0x1f, KEY_GREEN },
-       { 0x01, 0x1c, KEY_YELLOW },
-       { 0x01, 0x44, KEY_BLUE },
-       { 0x01, 0x0c, KEY_SHUFFLE },      /* snapshot */
-       { 0x01, 0x48, KEY_STOP },
-       { 0x01, 0x50, KEY_PLAY },
-       { 0x01, 0x51, KEY_PAUSE },
-       { 0x01, 0x49, KEY_RECORD },
-       { 0x01, 0x18, KEY_PREVIOUS },     /* |<< */
-       { 0x01, 0x0d, KEY_NEXT },         /* >>| */
-       { 0x01, 0x24, KEY_PROG1 },        /* F1 */
-       { 0x01, 0x25, KEY_PROG2 },        /* F2 */
+       { 0x0100, KEY_0 },
+       { 0x0101, KEY_1 },
+       { 0x0102, KEY_2 },
+       { 0x0103, KEY_3 },
+       { 0x0104, KEY_4 },
+       { 0x0105, KEY_5 },
+       { 0x0106, KEY_6 },
+       { 0x0107, KEY_7 },
+       { 0x0108, KEY_8 },
+       { 0x0109, KEY_9 },
+       { 0x010a, KEY_POWER },
+       { 0x010b, KEY_DOCUMENTS },    /* * */
+       { 0x0119, KEY_FAVORITES },
+       { 0x0120, KEY_SLEEP },
+       { 0x0121, KEY_MODE },         /* 4:3 / 16:9 select */
+       { 0x0122, KEY_ZOOM },
+       { 0x0147, KEY_TEXT },
+       { 0x0116, KEY_TV },           /* TV / radio select */
+       { 0x011e, KEY_LANGUAGE },     /* Second Audio Program */
+       { 0x011a, KEY_SUBTITLE },
+       { 0x011b, KEY_CAMERA },       /* screenshot */
+       { 0x0142, KEY_MUTE },
+       { 0x010e, KEY_MENU },
+       { 0x010f, KEY_EPG },
+       { 0x0117, KEY_INFO },
+       { 0x0110, KEY_EXIT },
+       { 0x0113, KEY_VOLUMEUP },
+       { 0x0112, KEY_VOLUMEDOWN },
+       { 0x0111, KEY_CHANNELUP },
+       { 0x0114, KEY_CHANNELDOWN },
+       { 0x0115, KEY_OK },
+       { 0x011d, KEY_RED },
+       { 0x011f, KEY_GREEN },
+       { 0x011c, KEY_YELLOW },
+       { 0x0144, KEY_BLUE },
+       { 0x010c, KEY_SHUFFLE },      /* snapshot */
+       { 0x0148, KEY_STOP },
+       { 0x0150, KEY_PLAY },
+       { 0x0151, KEY_PAUSE },
+       { 0x0149, KEY_RECORD },
+       { 0x0118, KEY_PREVIOUS },     /* |<< */
+       { 0x010d, KEY_NEXT },         /* >>| */
+       { 0x0124, KEY_PROG1 },        /* F1 */
+       { 0x0125, KEY_PROG2 },        /* F2 */
 };
 
 /* DVB USB Driver stuff */
index 80e37a0d0892298c167356d5a0b1b2158c518f6a..e37ac4d48602b606b4c7d53a45d7e37314cf8899 100644 (file)
@@ -85,43 +85,43 @@ static int cinergyt2_frontend_attach(struct dvb_usb_adapter *adap)
 }
 
 static struct dvb_usb_rc_key cinergyt2_rc_keys[] = {
-       { 0x04, 0x01,   KEY_POWER },
-       { 0x04, 0x02,   KEY_1 },
-       { 0x04, 0x03,   KEY_2 },
-       { 0x04, 0x04,   KEY_3 },
-       { 0x04, 0x05,   KEY_4 },
-       { 0x04, 0x06,   KEY_5 },
-       { 0x04, 0x07,   KEY_6 },
-       { 0x04, 0x08,   KEY_7 },
-       { 0x04, 0x09,   KEY_8 },
-       { 0x04, 0x0a,   KEY_9 },
-       { 0x04, 0x0c,   KEY_0 },
-       { 0x04, 0x0b,   KEY_VIDEO },
-       { 0x04, 0x0d,   KEY_REFRESH },
-       { 0x04, 0x0e,   KEY_SELECT },
-       { 0x04, 0x0f,   KEY_EPG },
-       { 0x04, 0x10,   KEY_UP },
-       { 0x04, 0x14,   KEY_DOWN },
-       { 0x04, 0x11,   KEY_LEFT },
-       { 0x04, 0x13,   KEY_RIGHT },
-       { 0x04, 0x12,   KEY_OK },
-       { 0x04, 0x15,   KEY_TEXT },
-       { 0x04, 0x16,   KEY_INFO },
-       { 0x04, 0x17,   KEY_RED },
-       { 0x04, 0x18,   KEY_GREEN },
-       { 0x04, 0x19,   KEY_YELLOW },
-       { 0x04, 0x1a,   KEY_BLUE },
-       { 0x04, 0x1c,   KEY_VOLUMEUP },
-       { 0x04, 0x1e,   KEY_VOLUMEDOWN },
-       { 0x04, 0x1d,   KEY_MUTE },
-       { 0x04, 0x1b,   KEY_CHANNELUP },
-       { 0x04, 0x1f,   KEY_CHANNELDOWN },
-       { 0x04, 0x40,   KEY_PAUSE },
-       { 0x04, 0x4c,   KEY_PLAY },
-       { 0x04, 0x58,   KEY_RECORD },
-       { 0x04, 0x54,   KEY_PREVIOUS },
-       { 0x04, 0x48,   KEY_STOP },
-       { 0x04, 0x5c,   KEY_NEXT }
+       { 0x0401, KEY_POWER },
+       { 0x0402, KEY_1 },
+       { 0x0403, KEY_2 },
+       { 0x0404, KEY_3 },
+       { 0x0405, KEY_4 },
+       { 0x0406, KEY_5 },
+       { 0x0407, KEY_6 },
+       { 0x0408, KEY_7 },
+       { 0x0409, KEY_8 },
+       { 0x040a, KEY_9 },
+       { 0x040c, KEY_0 },
+       { 0x040b, KEY_VIDEO },
+       { 0x040d, KEY_REFRESH },
+       { 0x040e, KEY_SELECT },
+       { 0x040f, KEY_EPG },
+       { 0x0410, KEY_UP },
+       { 0x0414, KEY_DOWN },
+       { 0x0411, KEY_LEFT },
+       { 0x0413, KEY_RIGHT },
+       { 0x0412, KEY_OK },
+       { 0x0415, KEY_TEXT },
+       { 0x0416, KEY_INFO },
+       { 0x0417, KEY_RED },
+       { 0x0418, KEY_GREEN },
+       { 0x0419, KEY_YELLOW },
+       { 0x041a, KEY_BLUE },
+       { 0x041c, KEY_VOLUMEUP },
+       { 0x041e, KEY_VOLUMEDOWN },
+       { 0x041d, KEY_MUTE },
+       { 0x041b, KEY_CHANNELUP },
+       { 0x041f, KEY_CHANNELDOWN },
+       { 0x0440, KEY_PAUSE },
+       { 0x044c, KEY_PLAY },
+       { 0x0458, KEY_RECORD },
+       { 0x0454, KEY_PREVIOUS },
+       { 0x0448, KEY_STOP },
+       { 0x045c, KEY_NEXT }
 };
 
 /* Number of keypresses to ignore before detect repeating */
index 649f25cca49e37feb5de89d5b1ac2881863a6f9f..9cd51ac12076eec16039c77fe6396735da9b559c 100644 (file)
@@ -275,6 +275,7 @@ static int cinergyt2_fe_set_frontend(struct dvb_frontend *fe,
        param.tps = cpu_to_le16(compute_tps(fep));
        param.freq = cpu_to_le32(fep->frequency / 1000);
        param.bandwidth = 8 - fep->u.ofdm.bandwidth - BANDWIDTH_8_MHZ;
+       param.flags = 0;
 
        err = dvb_usb_generic_rw(state->d,
                        (char *)&param, sizeof(param),
index 406d7fba369d6b702e5db34fef48fd133e89c2da..f65591fb7cec36d720d9717b8503c513cbcd3082 100644 (file)
@@ -38,7 +38,7 @@
 #include "mxl5005s.h"
 #include "dib7000p.h"
 #include "dib0070.h"
-#include "lgs8gl5.h"
+#include "lgs8gxx.h"
 
 /* debug */
 static int dvb_usb_cxusb_debug;
@@ -392,8 +392,8 @@ static int cxusb_rc_query(struct dvb_usb_device *d, u32 *event, int *state)
        *state = REMOTE_NO_KEY_PRESSED;
 
        for (i = 0; i < d->props.rc_key_map_size; i++) {
-               if (keymap[i].custom == ircode[2] &&
-                   keymap[i].data == ircode[3]) {
+               if (rc5_custom(&keymap[i]) == ircode[2] &&
+                   rc5_data(&keymap[i]) == ircode[3]) {
                        *event = keymap[i].event;
                        *state = REMOTE_KEY_PRESSED;
 
@@ -420,8 +420,8 @@ static int cxusb_bluebird2_rc_query(struct dvb_usb_device *d, u32 *event,
                return 0;
 
        for (i = 0; i < d->props.rc_key_map_size; i++) {
-               if (keymap[i].custom == ircode[1] &&
-                   keymap[i].data == ircode[2]) {
+               if (rc5_custom(&keymap[i]) == ircode[1] &&
+                   rc5_data(&keymap[i]) == ircode[2]) {
                        *event = keymap[i].event;
                        *state = REMOTE_KEY_PRESSED;
 
@@ -446,8 +446,8 @@ static int cxusb_d680_dmb_rc_query(struct dvb_usb_device *d, u32 *event,
                return 0;
 
        for (i = 0; i < d->props.rc_key_map_size; i++) {
-               if (keymap[i].custom == ircode[0] &&
-                   keymap[i].data == ircode[1]) {
+               if (rc5_custom(&keymap[i]) == ircode[0] &&
+                   rc5_data(&keymap[i]) == ircode[1]) {
                        *event = keymap[i].event;
                        *state = REMOTE_KEY_PRESSED;
 
@@ -459,128 +459,128 @@ static int cxusb_d680_dmb_rc_query(struct dvb_usb_device *d, u32 *event,
 }
 
 static struct dvb_usb_rc_key dvico_mce_rc_keys[] = {
-       { 0xfe, 0x02, KEY_TV },
-       { 0xfe, 0x0e, KEY_MP3 },
-       { 0xfe, 0x1a, KEY_DVD },
-       { 0xfe, 0x1e, KEY_FAVORITES },
-       { 0xfe, 0x16, KEY_SETUP },
-       { 0xfe, 0x46, KEY_POWER2 },
-       { 0xfe, 0x0a, KEY_EPG },
-       { 0xfe, 0x49, KEY_BACK },
-       { 0xfe, 0x4d, KEY_MENU },
-       { 0xfe, 0x51, KEY_UP },
-       { 0xfe, 0x5b, KEY_LEFT },
-       { 0xfe, 0x5f, KEY_RIGHT },
-       { 0xfe, 0x53, KEY_DOWN },
-       { 0xfe, 0x5e, KEY_OK },
-       { 0xfe, 0x59, KEY_INFO },
-       { 0xfe, 0x55, KEY_TAB },
-       { 0xfe, 0x0f, KEY_PREVIOUSSONG },/* Replay */
-       { 0xfe, 0x12, KEY_NEXTSONG },   /* Skip */
-       { 0xfe, 0x42, KEY_ENTER  },     /* Windows/Start */
-       { 0xfe, 0x15, KEY_VOLUMEUP },
-       { 0xfe, 0x05, KEY_VOLUMEDOWN },
-       { 0xfe, 0x11, KEY_CHANNELUP },
-       { 0xfe, 0x09, KEY_CHANNELDOWN },
-       { 0xfe, 0x52, KEY_CAMERA },
-       { 0xfe, 0x5a, KEY_TUNER },      /* Live */
-       { 0xfe, 0x19, KEY_OPEN },
-       { 0xfe, 0x0b, KEY_1 },
-       { 0xfe, 0x17, KEY_2 },
-       { 0xfe, 0x1b, KEY_3 },
-       { 0xfe, 0x07, KEY_4 },
-       { 0xfe, 0x50, KEY_5 },
-       { 0xfe, 0x54, KEY_6 },
-       { 0xfe, 0x48, KEY_7 },
-       { 0xfe, 0x4c, KEY_8 },
-       { 0xfe, 0x58, KEY_9 },
-       { 0xfe, 0x13, KEY_ANGLE },      /* Aspect */
-       { 0xfe, 0x03, KEY_0 },
-       { 0xfe, 0x1f, KEY_ZOOM },
-       { 0xfe, 0x43, KEY_REWIND },
-       { 0xfe, 0x47, KEY_PLAYPAUSE },
-       { 0xfe, 0x4f, KEY_FASTFORWARD },
-       { 0xfe, 0x57, KEY_MUTE },
-       { 0xfe, 0x0d, KEY_STOP },
-       { 0xfe, 0x01, KEY_RECORD },
-       { 0xfe, 0x4e, KEY_POWER },
+       { 0xfe02, KEY_TV },
+       { 0xfe0e, KEY_MP3 },
+       { 0xfe1a, KEY_DVD },
+       { 0xfe1e, KEY_FAVORITES },
+       { 0xfe16, KEY_SETUP },
+       { 0xfe46, KEY_POWER2 },
+       { 0xfe0a, KEY_EPG },
+       { 0xfe49, KEY_BACK },
+       { 0xfe4d, KEY_MENU },
+       { 0xfe51, KEY_UP },
+       { 0xfe5b, KEY_LEFT },
+       { 0xfe5f, KEY_RIGHT },
+       { 0xfe53, KEY_DOWN },
+       { 0xfe5e, KEY_OK },
+       { 0xfe59, KEY_INFO },
+       { 0xfe55, KEY_TAB },
+       { 0xfe0f, KEY_PREVIOUSSONG },/* Replay */
+       { 0xfe12, KEY_NEXTSONG },       /* Skip */
+       { 0xfe42, KEY_ENTER      },     /* Windows/Start */
+       { 0xfe15, KEY_VOLUMEUP },
+       { 0xfe05, KEY_VOLUMEDOWN },
+       { 0xfe11, KEY_CHANNELUP },
+       { 0xfe09, KEY_CHANNELDOWN },
+       { 0xfe52, KEY_CAMERA },
+       { 0xfe5a, KEY_TUNER },  /* Live */
+       { 0xfe19, KEY_OPEN },
+       { 0xfe0b, KEY_1 },
+       { 0xfe17, KEY_2 },
+       { 0xfe1b, KEY_3 },
+       { 0xfe07, KEY_4 },
+       { 0xfe50, KEY_5 },
+       { 0xfe54, KEY_6 },
+       { 0xfe48, KEY_7 },
+       { 0xfe4c, KEY_8 },
+       { 0xfe58, KEY_9 },
+       { 0xfe13, KEY_ANGLE },  /* Aspect */
+       { 0xfe03, KEY_0 },
+       { 0xfe1f, KEY_ZOOM },
+       { 0xfe43, KEY_REWIND },
+       { 0xfe47, KEY_PLAYPAUSE },
+       { 0xfe4f, KEY_FASTFORWARD },
+       { 0xfe57, KEY_MUTE },
+       { 0xfe0d, KEY_STOP },
+       { 0xfe01, KEY_RECORD },
+       { 0xfe4e, KEY_POWER },
 };
 
 static struct dvb_usb_rc_key dvico_portable_rc_keys[] = {
-       { 0xfc, 0x02, KEY_SETUP },       /* Profile */
-       { 0xfc, 0x43, KEY_POWER2 },
-       { 0xfc, 0x06, KEY_EPG },
-       { 0xfc, 0x5a, KEY_BACK },
-       { 0xfc, 0x05, KEY_MENU },
-       { 0xfc, 0x47, KEY_INFO },
-       { 0xfc, 0x01, KEY_TAB },
-       { 0xfc, 0x42, KEY_PREVIOUSSONG },/* Replay */
-       { 0xfc, 0x49, KEY_VOLUMEUP },
-       { 0xfc, 0x09, KEY_VOLUMEDOWN },
-       { 0xfc, 0x54, KEY_CHANNELUP },
-       { 0xfc, 0x0b, KEY_CHANNELDOWN },
-       { 0xfc, 0x16, KEY_CAMERA },
-       { 0xfc, 0x40, KEY_TUNER },      /* ATV/DTV */
-       { 0xfc, 0x45, KEY_OPEN },
-       { 0xfc, 0x19, KEY_1 },
-       { 0xfc, 0x18, KEY_2 },
-       { 0xfc, 0x1b, KEY_3 },
-       { 0xfc, 0x1a, KEY_4 },
-       { 0xfc, 0x58, KEY_5 },
-       { 0xfc, 0x59, KEY_6 },
-       { 0xfc, 0x15, KEY_7 },
-       { 0xfc, 0x14, KEY_8 },
-       { 0xfc, 0x17, KEY_9 },
-       { 0xfc, 0x44, KEY_ANGLE },      /* Aspect */
-       { 0xfc, 0x55, KEY_0 },
-       { 0xfc, 0x07, KEY_ZOOM },
-       { 0xfc, 0x0a, KEY_REWIND },
-       { 0xfc, 0x08, KEY_PLAYPAUSE },
-       { 0xfc, 0x4b, KEY_FASTFORWARD },
-       { 0xfc, 0x5b, KEY_MUTE },
-       { 0xfc, 0x04, KEY_STOP },
-       { 0xfc, 0x56, KEY_RECORD },
-       { 0xfc, 0x57, KEY_POWER },
-       { 0xfc, 0x41, KEY_UNKNOWN },    /* INPUT */
-       { 0xfc, 0x00, KEY_UNKNOWN },    /* HD */
+       { 0xfc02, KEY_SETUP },       /* Profile */
+       { 0xfc43, KEY_POWER2 },
+       { 0xfc06, KEY_EPG },
+       { 0xfc5a, KEY_BACK },
+       { 0xfc05, KEY_MENU },
+       { 0xfc47, KEY_INFO },
+       { 0xfc01, KEY_TAB },
+       { 0xfc42, KEY_PREVIOUSSONG },/* Replay */
+       { 0xfc49, KEY_VOLUMEUP },
+       { 0xfc09, KEY_VOLUMEDOWN },
+       { 0xfc54, KEY_CHANNELUP },
+       { 0xfc0b, KEY_CHANNELDOWN },
+       { 0xfc16, KEY_CAMERA },
+       { 0xfc40, KEY_TUNER },  /* ATV/DTV */
+       { 0xfc45, KEY_OPEN },
+       { 0xfc19, KEY_1 },
+       { 0xfc18, KEY_2 },
+       { 0xfc1b, KEY_3 },
+       { 0xfc1a, KEY_4 },
+       { 0xfc58, KEY_5 },
+       { 0xfc59, KEY_6 },
+       { 0xfc15, KEY_7 },
+       { 0xfc14, KEY_8 },
+       { 0xfc17, KEY_9 },
+       { 0xfc44, KEY_ANGLE },  /* Aspect */
+       { 0xfc55, KEY_0 },
+       { 0xfc07, KEY_ZOOM },
+       { 0xfc0a, KEY_REWIND },
+       { 0xfc08, KEY_PLAYPAUSE },
+       { 0xfc4b, KEY_FASTFORWARD },
+       { 0xfc5b, KEY_MUTE },
+       { 0xfc04, KEY_STOP },
+       { 0xfc56, KEY_RECORD },
+       { 0xfc57, KEY_POWER },
+       { 0xfc41, KEY_UNKNOWN },    /* INPUT */
+       { 0xfc00, KEY_UNKNOWN },    /* HD */
 };
 
 static struct dvb_usb_rc_key d680_dmb_rc_keys[] = {
-       { 0x00, 0x38, KEY_UNKNOWN },    /* TV/AV */
-       { 0x08, 0x0c, KEY_ZOOM },
-       { 0x08, 0x00, KEY_0 },
-       { 0x00, 0x01, KEY_1 },
-       { 0x08, 0x02, KEY_2 },
-       { 0x00, 0x03, KEY_3 },
-       { 0x08, 0x04, KEY_4 },
-       { 0x00, 0x05, KEY_5 },
-       { 0x08, 0x06, KEY_6 },
-       { 0x00, 0x07, KEY_7 },
-       { 0x08, 0x08, KEY_8 },
-       { 0x00, 0x09, KEY_9 },
-       { 0x00, 0x0a, KEY_MUTE },
-       { 0x08, 0x29, KEY_BACK },
-       { 0x00, 0x12, KEY_CHANNELUP },
-       { 0x08, 0x13, KEY_CHANNELDOWN },
-       { 0x00, 0x2b, KEY_VOLUMEUP },
-       { 0x08, 0x2c, KEY_VOLUMEDOWN },
-       { 0x00, 0x20, KEY_UP },
-       { 0x08, 0x21, KEY_DOWN },
-       { 0x00, 0x11, KEY_LEFT },
-       { 0x08, 0x10, KEY_RIGHT },
-       { 0x00, 0x0d, KEY_OK },
-       { 0x08, 0x1f, KEY_RECORD },
-       { 0x00, 0x17, KEY_PLAYPAUSE },
-       { 0x08, 0x16, KEY_PLAYPAUSE },
-       { 0x00, 0x0b, KEY_STOP },
-       { 0x08, 0x27, KEY_FASTFORWARD },
-       { 0x00, 0x26, KEY_REWIND },
-       { 0x08, 0x1e, KEY_UNKNOWN },    /* Time Shift */
-       { 0x00, 0x0e, KEY_UNKNOWN },    /* Snapshot */
-       { 0x08, 0x2d, KEY_UNKNOWN },    /* Mouse Cursor */
-       { 0x00, 0x0f, KEY_UNKNOWN },    /* Minimize/Maximize */
-       { 0x08, 0x14, KEY_UNKNOWN },    /* Shuffle */
-       { 0x00, 0x25, KEY_POWER },
+       { 0x0038, KEY_UNKNOWN },        /* TV/AV */
+       { 0x080c, KEY_ZOOM },
+       { 0x0800, KEY_0 },
+       { 0x0001, KEY_1 },
+       { 0x0802, KEY_2 },
+       { 0x0003, KEY_3 },
+       { 0x0804, KEY_4 },
+       { 0x0005, KEY_5 },
+       { 0x0806, KEY_6 },
+       { 0x0007, KEY_7 },
+       { 0x0808, KEY_8 },
+       { 0x0009, KEY_9 },
+       { 0x000a, KEY_MUTE },
+       { 0x0829, KEY_BACK },
+       { 0x0012, KEY_CHANNELUP },
+       { 0x0813, KEY_CHANNELDOWN },
+       { 0x002b, KEY_VOLUMEUP },
+       { 0x082c, KEY_VOLUMEDOWN },
+       { 0x0020, KEY_UP },
+       { 0x0821, KEY_DOWN },
+       { 0x0011, KEY_LEFT },
+       { 0x0810, KEY_RIGHT },
+       { 0x000d, KEY_OK },
+       { 0x081f, KEY_RECORD },
+       { 0x0017, KEY_PLAYPAUSE },
+       { 0x0816, KEY_PLAYPAUSE },
+       { 0x000b, KEY_STOP },
+       { 0x0827, KEY_FASTFORWARD },
+       { 0x0026, KEY_REWIND },
+       { 0x081e, KEY_UNKNOWN },    /* Time Shift */
+       { 0x000e, KEY_UNKNOWN },    /* Snapshot */
+       { 0x082d, KEY_UNKNOWN },    /* Mouse Cursor */
+       { 0x000f, KEY_UNKNOWN },    /* Minimize/Maximize */
+       { 0x0814, KEY_UNKNOWN },    /* Shuffle */
+       { 0x0025, KEY_POWER },
 };
 
 static int cxusb_dee1601_demod_init(struct dvb_frontend* fe)
@@ -1094,8 +1094,18 @@ static int cxusb_nano2_frontend_attach(struct dvb_usb_adapter *adap)
        return -EIO;
 }
 
-static struct lgs8gl5_config lgs8gl5_cfg = {
+static struct lgs8gxx_config d680_lgs8gl5_cfg = {
+       .prod = LGS8GXX_PROD_LGS8GL5,
        .demod_address = 0x19,
+       .serial_ts = 0,
+       .ts_clk_pol = 0,
+       .ts_clk_gated = 1,
+       .if_clk_freq = 30400, /* 30.4 MHz */
+       .if_freq = 5725, /* 5.725 MHz */
+       .if_neg_center = 0,
+       .ext_adc = 0,
+       .adc_signed = 0,
+       .if_neg_edge = 0,
 };
 
 static int cxusb_d680_dmb_frontend_attach(struct dvb_usb_adapter *adap)
@@ -1135,7 +1145,7 @@ static int cxusb_d680_dmb_frontend_attach(struct dvb_usb_adapter *adap)
        msleep(100);
 
        /* Attach frontend */
-       adap->fe = dvb_attach(lgs8gl5_attach, &lgs8gl5_cfg, &d->i2c_adap);
+       adap->fe = dvb_attach(lgs8gxx_attach, &d680_lgs8gl5_cfg, &d->i2c_adap);
        if (adap->fe == NULL)
                return -EIO;
 
index 818b2ab584bf927bd00d0e1e369a24c94f2b9bca..d1d6f44914037edf6a603bf875c6e378f0850db9 100644 (file)
@@ -310,7 +310,7 @@ static int stk7700d_tuner_attach(struct dvb_usb_adapter *adap)
        struct i2c_adapter *tun_i2c;
        tun_i2c = dib7000p_get_i2c_master(adap->fe, DIBX000_I2C_INTERFACE_TUNER, 1);
        return dvb_attach(mt2266_attach, adap->fe, tun_i2c,
-               &stk7700d_mt2266_config[adap->id]) == NULL ? -ENODEV : 0;;
+               &stk7700d_mt2266_config[adap->id]) == NULL ? -ENODEV : 0;
 }
 
 /* STK7700-PH: Digital/Analog Hybrid Tuner, e.h. Cinergy HT USB HE */
@@ -509,7 +509,8 @@ static int dib0700_rc_query_legacy(struct dvb_usb_device *d, u32 *event,
                        return 0;
                }
                for (i=0;i<d->props.rc_key_map_size; i++) {
-                       if (keymap[i].custom == key[3-2] && keymap[i].data == key[3-3]) {
+                       if (rc5_custom(&keymap[i]) == key[3-2] &&
+                           rc5_data(&keymap[i]) == key[3-3]) {
                                st->rc_counter = 0;
                                *event = keymap[i].event;
                                *state = REMOTE_KEY_PRESSED;
@@ -522,7 +523,8 @@ static int dib0700_rc_query_legacy(struct dvb_usb_device *d, u32 *event,
        default: {
                /* RC-5 protocol changes toggle bit on new keypress */
                for (i = 0; i < d->props.rc_key_map_size; i++) {
-                       if (keymap[i].custom == key[3-2] && keymap[i].data == key[3-3]) {
+                       if (rc5_custom(&keymap[i]) == key[3-2] &&
+                           rc5_data(&keymap[i]) == key[3-3]) {
                                if (d->last_event == keymap[i].event &&
                                        key[3-1] == st->rc_toggle) {
                                        st->rc_counter++;
@@ -616,8 +618,8 @@ static int dib0700_rc_query_v1_20(struct dvb_usb_device *d, u32 *event,
 
        /* Find the key in the map */
        for (i = 0; i < d->props.rc_key_map_size; i++) {
-               if (keymap[i].custom == poll_reply.system_lsb &&
-                   keymap[i].data == poll_reply.data) {
+               if (rc5_custom(&keymap[i]) == poll_reply.system_lsb &&
+                   rc5_data(&keymap[i]) == poll_reply.data) {
                        *event = keymap[i].event;
                        found = 1;
                        break;
@@ -684,193 +686,193 @@ static int dib0700_rc_query(struct dvb_usb_device *d, u32 *event, int *state)
 
 static struct dvb_usb_rc_key dib0700_rc_keys[] = {
        /* Key codes for the tiny Pinnacle remote*/
-       { 0x07, 0x00, KEY_MUTE },
-       { 0x07, 0x01, KEY_MENU }, // Pinnacle logo
-       { 0x07, 0x39, KEY_POWER },
-       { 0x07, 0x03, KEY_VOLUMEUP },
-       { 0x07, 0x09, KEY_VOLUMEDOWN },
-       { 0x07, 0x06, KEY_CHANNELUP },
-       { 0x07, 0x0c, KEY_CHANNELDOWN },
-       { 0x07, 0x0f, KEY_1 },
-       { 0x07, 0x15, KEY_2 },
-       { 0x07, 0x10, KEY_3 },
-       { 0x07, 0x18, KEY_4 },
-       { 0x07, 0x1b, KEY_5 },
-       { 0x07, 0x1e, KEY_6 },
-       { 0x07, 0x11, KEY_7 },
-       { 0x07, 0x21, KEY_8 },
-       { 0x07, 0x12, KEY_9 },
-       { 0x07, 0x27, KEY_0 },
-       { 0x07, 0x24, KEY_SCREEN }, // 'Square' key
-       { 0x07, 0x2a, KEY_TEXT },   // 'T' key
-       { 0x07, 0x2d, KEY_REWIND },
-       { 0x07, 0x30, KEY_PLAY },
-       { 0x07, 0x33, KEY_FASTFORWARD },
-       { 0x07, 0x36, KEY_RECORD },
-       { 0x07, 0x3c, KEY_STOP },
-       { 0x07, 0x3f, KEY_CANCEL }, // '?' key
+       { 0x0700, KEY_MUTE },
+       { 0x0701, KEY_MENU }, /* Pinnacle logo */
+       { 0x0739, KEY_POWER },
+       { 0x0703, KEY_VOLUMEUP },
+       { 0x0709, KEY_VOLUMEDOWN },
+       { 0x0706, KEY_CHANNELUP },
+       { 0x070c, KEY_CHANNELDOWN },
+       { 0x070f, KEY_1 },
+       { 0x0715, KEY_2 },
+       { 0x0710, KEY_3 },
+       { 0x0718, KEY_4 },
+       { 0x071b, KEY_5 },
+       { 0x071e, KEY_6 },
+       { 0x0711, KEY_7 },
+       { 0x0721, KEY_8 },
+       { 0x0712, KEY_9 },
+       { 0x0727, KEY_0 },
+       { 0x0724, KEY_SCREEN }, /* 'Square' key */
+       { 0x072a, KEY_TEXT },   /* 'T' key */
+       { 0x072d, KEY_REWIND },
+       { 0x0730, KEY_PLAY },
+       { 0x0733, KEY_FASTFORWARD },
+       { 0x0736, KEY_RECORD },
+       { 0x073c, KEY_STOP },
+       { 0x073f, KEY_CANCEL }, /* '?' key */
        /* Key codes for the Terratec Cinergy DT XS Diversity, similar to cinergyT2.c */
-       { 0xeb, 0x01, KEY_POWER },
-       { 0xeb, 0x02, KEY_1 },
-       { 0xeb, 0x03, KEY_2 },
-       { 0xeb, 0x04, KEY_3 },
-       { 0xeb, 0x05, KEY_4 },
-       { 0xeb, 0x06, KEY_5 },
-       { 0xeb, 0x07, KEY_6 },
-       { 0xeb, 0x08, KEY_7 },
-       { 0xeb, 0x09, KEY_8 },
-       { 0xeb, 0x0a, KEY_9 },
-       { 0xeb, 0x0b, KEY_VIDEO },
-       { 0xeb, 0x0c, KEY_0 },
-       { 0xeb, 0x0d, KEY_REFRESH },
-       { 0xeb, 0x0f, KEY_EPG },
-       { 0xeb, 0x10, KEY_UP },
-       { 0xeb, 0x11, KEY_LEFT },
-       { 0xeb, 0x12, KEY_OK },
-       { 0xeb, 0x13, KEY_RIGHT },
-       { 0xeb, 0x14, KEY_DOWN },
-       { 0xeb, 0x16, KEY_INFO },
-       { 0xeb, 0x17, KEY_RED },
-       { 0xeb, 0x18, KEY_GREEN },
-       { 0xeb, 0x19, KEY_YELLOW },
-       { 0xeb, 0x1a, KEY_BLUE },
-       { 0xeb, 0x1b, KEY_CHANNELUP },
-       { 0xeb, 0x1c, KEY_VOLUMEUP },
-       { 0xeb, 0x1d, KEY_MUTE },
-       { 0xeb, 0x1e, KEY_VOLUMEDOWN },
-       { 0xeb, 0x1f, KEY_CHANNELDOWN },
-       { 0xeb, 0x40, KEY_PAUSE },
-       { 0xeb, 0x41, KEY_HOME },
-       { 0xeb, 0x42, KEY_MENU }, /* DVD Menu */
-       { 0xeb, 0x43, KEY_SUBTITLE },
-       { 0xeb, 0x44, KEY_TEXT }, /* Teletext */
-       { 0xeb, 0x45, KEY_DELETE },
-       { 0xeb, 0x46, KEY_TV },
-       { 0xeb, 0x47, KEY_DVD },
-       { 0xeb, 0x48, KEY_STOP },
-       { 0xeb, 0x49, KEY_VIDEO },
-       { 0xeb, 0x4a, KEY_AUDIO }, /* Music */
-       { 0xeb, 0x4b, KEY_SCREEN }, /* Pic */
-       { 0xeb, 0x4c, KEY_PLAY },
-       { 0xeb, 0x4d, KEY_BACK },
-       { 0xeb, 0x4e, KEY_REWIND },
-       { 0xeb, 0x4f, KEY_FASTFORWARD },
-       { 0xeb, 0x54, KEY_PREVIOUS },
-       { 0xeb, 0x58, KEY_RECORD },
-       { 0xeb, 0x5c, KEY_NEXT },
+       { 0xeb01, KEY_POWER },
+       { 0xeb02, KEY_1 },
+       { 0xeb03, KEY_2 },
+       { 0xeb04, KEY_3 },
+       { 0xeb05, KEY_4 },
+       { 0xeb06, KEY_5 },
+       { 0xeb07, KEY_6 },
+       { 0xeb08, KEY_7 },
+       { 0xeb09, KEY_8 },
+       { 0xeb0a, KEY_9 },
+       { 0xeb0b, KEY_VIDEO },
+       { 0xeb0c, KEY_0 },
+       { 0xeb0d, KEY_REFRESH },
+       { 0xeb0f, KEY_EPG },
+       { 0xeb10, KEY_UP },
+       { 0xeb11, KEY_LEFT },
+       { 0xeb12, KEY_OK },
+       { 0xeb13, KEY_RIGHT },
+       { 0xeb14, KEY_DOWN },
+       { 0xeb16, KEY_INFO },
+       { 0xeb17, KEY_RED },
+       { 0xeb18, KEY_GREEN },
+       { 0xeb19, KEY_YELLOW },
+       { 0xeb1a, KEY_BLUE },
+       { 0xeb1b, KEY_CHANNELUP },
+       { 0xeb1c, KEY_VOLUMEUP },
+       { 0xeb1d, KEY_MUTE },
+       { 0xeb1e, KEY_VOLUMEDOWN },
+       { 0xeb1f, KEY_CHANNELDOWN },
+       { 0xeb40, KEY_PAUSE },
+       { 0xeb41, KEY_HOME },
+       { 0xeb42, KEY_MENU }, /* DVD Menu */
+       { 0xeb43, KEY_SUBTITLE },
+       { 0xeb44, KEY_TEXT }, /* Teletext */
+       { 0xeb45, KEY_DELETE },
+       { 0xeb46, KEY_TV },
+       { 0xeb47, KEY_DVD },
+       { 0xeb48, KEY_STOP },
+       { 0xeb49, KEY_VIDEO },
+       { 0xeb4a, KEY_AUDIO }, /* Music */
+       { 0xeb4b, KEY_SCREEN }, /* Pic */
+       { 0xeb4c, KEY_PLAY },
+       { 0xeb4d, KEY_BACK },
+       { 0xeb4e, KEY_REWIND },
+       { 0xeb4f, KEY_FASTFORWARD },
+       { 0xeb54, KEY_PREVIOUS },
+       { 0xeb58, KEY_RECORD },
+       { 0xeb5c, KEY_NEXT },
 
        /* Key codes for the Haupauge WinTV Nova-TD, copied from nova-t-usb2.c (Nova-T USB2) */
-       { 0x1e, 0x00, KEY_0 },
-       { 0x1e, 0x01, KEY_1 },
-       { 0x1e, 0x02, KEY_2 },
-       { 0x1e, 0x03, KEY_3 },
-       { 0x1e, 0x04, KEY_4 },
-       { 0x1e, 0x05, KEY_5 },
-       { 0x1e, 0x06, KEY_6 },
-       { 0x1e, 0x07, KEY_7 },
-       { 0x1e, 0x08, KEY_8 },
-       { 0x1e, 0x09, KEY_9 },
-       { 0x1e, 0x0a, KEY_KPASTERISK },
-       { 0x1e, 0x0b, KEY_RED },
-       { 0x1e, 0x0c, KEY_RADIO },
-       { 0x1e, 0x0d, KEY_MENU },
-       { 0x1e, 0x0e, KEY_GRAVE }, /* # */
-       { 0x1e, 0x0f, KEY_MUTE },
-       { 0x1e, 0x10, KEY_VOLUMEUP },
-       { 0x1e, 0x11, KEY_VOLUMEDOWN },
-       { 0x1e, 0x12, KEY_CHANNEL },
-       { 0x1e, 0x14, KEY_UP },
-       { 0x1e, 0x15, KEY_DOWN },
-       { 0x1e, 0x16, KEY_LEFT },
-       { 0x1e, 0x17, KEY_RIGHT },
-       { 0x1e, 0x18, KEY_VIDEO },
-       { 0x1e, 0x19, KEY_AUDIO },
-       { 0x1e, 0x1a, KEY_MEDIA },
-       { 0x1e, 0x1b, KEY_EPG },
-       { 0x1e, 0x1c, KEY_TV },
-       { 0x1e, 0x1e, KEY_NEXT },
-       { 0x1e, 0x1f, KEY_BACK },
-       { 0x1e, 0x20, KEY_CHANNELUP },
-       { 0x1e, 0x21, KEY_CHANNELDOWN },
-       { 0x1e, 0x24, KEY_LAST }, /* Skip backwards */
-       { 0x1e, 0x25, KEY_OK },
-       { 0x1e, 0x29, KEY_BLUE},
-       { 0x1e, 0x2e, KEY_GREEN },
-       { 0x1e, 0x30, KEY_PAUSE },
-       { 0x1e, 0x32, KEY_REWIND },
-       { 0x1e, 0x34, KEY_FASTFORWARD },
-       { 0x1e, 0x35, KEY_PLAY },
-       { 0x1e, 0x36, KEY_STOP },
-       { 0x1e, 0x37, KEY_RECORD },
-       { 0x1e, 0x38, KEY_YELLOW },
-       { 0x1e, 0x3b, KEY_GOTO },
-       { 0x1e, 0x3d, KEY_POWER },
+       { 0x1e00, KEY_0 },
+       { 0x1e01, KEY_1 },
+       { 0x1e02, KEY_2 },
+       { 0x1e03, KEY_3 },
+       { 0x1e04, KEY_4 },
+       { 0x1e05, KEY_5 },
+       { 0x1e06, KEY_6 },
+       { 0x1e07, KEY_7 },
+       { 0x1e08, KEY_8 },
+       { 0x1e09, KEY_9 },
+       { 0x1e0a, KEY_KPASTERISK },
+       { 0x1e0b, KEY_RED },
+       { 0x1e0c, KEY_RADIO },
+       { 0x1e0d, KEY_MENU },
+       { 0x1e0e, KEY_GRAVE }, /* # */
+       { 0x1e0f, KEY_MUTE },
+       { 0x1e10, KEY_VOLUMEUP },
+       { 0x1e11, KEY_VOLUMEDOWN },
+       { 0x1e12, KEY_CHANNEL },
+       { 0x1e14, KEY_UP },
+       { 0x1e15, KEY_DOWN },
+       { 0x1e16, KEY_LEFT },
+       { 0x1e17, KEY_RIGHT },
+       { 0x1e18, KEY_VIDEO },
+       { 0x1e19, KEY_AUDIO },
+       { 0x1e1a, KEY_MEDIA },
+       { 0x1e1b, KEY_EPG },
+       { 0x1e1c, KEY_TV },
+       { 0x1e1e, KEY_NEXT },
+       { 0x1e1f, KEY_BACK },
+       { 0x1e20, KEY_CHANNELUP },
+       { 0x1e21, KEY_CHANNELDOWN },
+       { 0x1e24, KEY_LAST }, /* Skip backwards */
+       { 0x1e25, KEY_OK },
+       { 0x1e29, KEY_BLUE},
+       { 0x1e2e, KEY_GREEN },
+       { 0x1e30, KEY_PAUSE },
+       { 0x1e32, KEY_REWIND },
+       { 0x1e34, KEY_FASTFORWARD },
+       { 0x1e35, KEY_PLAY },
+       { 0x1e36, KEY_STOP },
+       { 0x1e37, KEY_RECORD },
+       { 0x1e38, KEY_YELLOW },
+       { 0x1e3b, KEY_GOTO },
+       { 0x1e3d, KEY_POWER },
 
        /* Key codes for the Leadtek Winfast DTV Dongle */
-       { 0x00, 0x42, KEY_POWER },
-       { 0x07, 0x7c, KEY_TUNER },
-       { 0x0f, 0x4e, KEY_PRINT }, /* PREVIEW */
-       { 0x08, 0x40, KEY_SCREEN }, /* full screen toggle*/
-       { 0x0f, 0x71, KEY_DOT }, /* frequency */
-       { 0x07, 0x43, KEY_0 },
-       { 0x0c, 0x41, KEY_1 },
-       { 0x04, 0x43, KEY_2 },
-       { 0x0b, 0x7f, KEY_3 },
-       { 0x0e, 0x41, KEY_4 },
-       { 0x06, 0x43, KEY_5 },
-       { 0x09, 0x7f, KEY_6 },
-       { 0x0d, 0x7e, KEY_7 },
-       { 0x05, 0x7c, KEY_8 },
-       { 0x0a, 0x40, KEY_9 },
-       { 0x0e, 0x4e, KEY_CLEAR },
-       { 0x04, 0x7c, KEY_CHANNEL }, /* show channel number */
-       { 0x0f, 0x41, KEY_LAST }, /* recall */
-       { 0x03, 0x42, KEY_MUTE },
-       { 0x06, 0x4c, KEY_RESERVED }, /* PIP button*/
-       { 0x01, 0x72, KEY_SHUFFLE }, /* SNAPSHOT */
-       { 0x0c, 0x4e, KEY_PLAYPAUSE }, /* TIMESHIFT */
-       { 0x0b, 0x70, KEY_RECORD },
-       { 0x03, 0x7d, KEY_VOLUMEUP },
-       { 0x01, 0x7d, KEY_VOLUMEDOWN },
-       { 0x02, 0x42, KEY_CHANNELUP },
-       { 0x00, 0x7d, KEY_CHANNELDOWN },
+       { 0x0042, KEY_POWER },
+       { 0x077c, KEY_TUNER },
+       { 0x0f4e, KEY_PRINT }, /* PREVIEW */
+       { 0x0840, KEY_SCREEN }, /* full screen toggle*/
+       { 0x0f71, KEY_DOT }, /* frequency */
+       { 0x0743, KEY_0 },
+       { 0x0c41, KEY_1 },
+       { 0x0443, KEY_2 },
+       { 0x0b7f, KEY_3 },
+       { 0x0e41, KEY_4 },
+       { 0x0643, KEY_5 },
+       { 0x097f, KEY_6 },
+       { 0x0d7e, KEY_7 },
+       { 0x057c, KEY_8 },
+       { 0x0a40, KEY_9 },
+       { 0x0e4e, KEY_CLEAR },
+       { 0x047c, KEY_CHANNEL }, /* show channel number */
+       { 0x0f41, KEY_LAST }, /* recall */
+       { 0x0342, KEY_MUTE },
+       { 0x064c, KEY_RESERVED }, /* PIP button*/
+       { 0x0172, KEY_SHUFFLE }, /* SNAPSHOT */
+       { 0x0c4e, KEY_PLAYPAUSE }, /* TIMESHIFT */
+       { 0x0b70, KEY_RECORD },
+       { 0x037d, KEY_VOLUMEUP },
+       { 0x017d, KEY_VOLUMEDOWN },
+       { 0x0242, KEY_CHANNELUP },
+       { 0x007d, KEY_CHANNELDOWN },
 
        /* Key codes for Nova-TD "credit card" remote control. */
-       { 0x1d, 0x00, KEY_0 },
-       { 0x1d, 0x01, KEY_1 },
-       { 0x1d, 0x02, KEY_2 },
-       { 0x1d, 0x03, KEY_3 },
-       { 0x1d, 0x04, KEY_4 },
-       { 0x1d, 0x05, KEY_5 },
-       { 0x1d, 0x06, KEY_6 },
-       { 0x1d, 0x07, KEY_7 },
-       { 0x1d, 0x08, KEY_8 },
-       { 0x1d, 0x09, KEY_9 },
-       { 0x1d, 0x0a, KEY_TEXT },
-       { 0x1d, 0x0d, KEY_MENU },
-       { 0x1d, 0x0f, KEY_MUTE },
-       { 0x1d, 0x10, KEY_VOLUMEUP },
-       { 0x1d, 0x11, KEY_VOLUMEDOWN },
-       { 0x1d, 0x12, KEY_CHANNEL },
-       { 0x1d, 0x14, KEY_UP },
-       { 0x1d, 0x15, KEY_DOWN },
-       { 0x1d, 0x16, KEY_LEFT },
-       { 0x1d, 0x17, KEY_RIGHT },
-       { 0x1d, 0x1c, KEY_TV },
-       { 0x1d, 0x1e, KEY_NEXT },
-       { 0x1d, 0x1f, KEY_BACK },
-       { 0x1d, 0x20, KEY_CHANNELUP },
-       { 0x1d, 0x21, KEY_CHANNELDOWN },
-       { 0x1d, 0x24, KEY_LAST },
-       { 0x1d, 0x25, KEY_OK },
-       { 0x1d, 0x30, KEY_PAUSE },
-       { 0x1d, 0x32, KEY_REWIND },
-       { 0x1d, 0x34, KEY_FASTFORWARD },
-       { 0x1d, 0x35, KEY_PLAY },
-       { 0x1d, 0x36, KEY_STOP },
-       { 0x1d, 0x37, KEY_RECORD },
-       { 0x1d, 0x3b, KEY_GOTO },
-       { 0x1d, 0x3d, KEY_POWER },
+       { 0x1d00, KEY_0 },
+       { 0x1d01, KEY_1 },
+       { 0x1d02, KEY_2 },
+       { 0x1d03, KEY_3 },
+       { 0x1d04, KEY_4 },
+       { 0x1d05, KEY_5 },
+       { 0x1d06, KEY_6 },
+       { 0x1d07, KEY_7 },
+       { 0x1d08, KEY_8 },
+       { 0x1d09, KEY_9 },
+       { 0x1d0a, KEY_TEXT },
+       { 0x1d0d, KEY_MENU },
+       { 0x1d0f, KEY_MUTE },
+       { 0x1d10, KEY_VOLUMEUP },
+       { 0x1d11, KEY_VOLUMEDOWN },
+       { 0x1d12, KEY_CHANNEL },
+       { 0x1d14, KEY_UP },
+       { 0x1d15, KEY_DOWN },
+       { 0x1d16, KEY_LEFT },
+       { 0x1d17, KEY_RIGHT },
+       { 0x1d1c, KEY_TV },
+       { 0x1d1e, KEY_NEXT },
+       { 0x1d1f, KEY_BACK },
+       { 0x1d20, KEY_CHANNELUP },
+       { 0x1d21, KEY_CHANNELDOWN },
+       { 0x1d24, KEY_LAST },
+       { 0x1d25, KEY_OK },
+       { 0x1d30, KEY_PAUSE },
+       { 0x1d32, KEY_REWIND },
+       { 0x1d34, KEY_FASTFORWARD },
+       { 0x1d35, KEY_PLAY },
+       { 0x1d36, KEY_STOP },
+       { 0x1d37, KEY_RECORD },
+       { 0x1d3b, KEY_GOTO },
+       { 0x1d3d, KEY_POWER },
 };
 
 /* STK7700P: Hauppauge Nova-T Stick, AVerMedia Volar */
@@ -1497,6 +1499,8 @@ struct usb_device_id dib0700_usb_id_table[] = {
        { USB_DEVICE(USB_VID_LEADTEK,   USB_PID_WINFAST_DTV_DONGLE_H) },
        { USB_DEVICE(USB_VID_TERRATEC,  USB_PID_TERRATEC_T3) },
        { USB_DEVICE(USB_VID_TERRATEC,  USB_PID_TERRATEC_T5) },
+       { USB_DEVICE(USB_VID_YUAN,      USB_PID_YUAN_STK7700D) },
+       { USB_DEVICE(USB_VID_YUAN,      USB_PID_YUAN_STK7700D_2) },
        { 0 }           /* Terminating entry */
 };
 MODULE_DEVICE_TABLE(usb, dib0700_usb_id_table);
@@ -1624,7 +1628,7 @@ struct dvb_usb_device_properties dib0700_devices[] = {
                        }
                },
 
-               .num_device_descs = 4,
+               .num_device_descs = 5,
                .devices = {
                        {   "Pinnacle PCTV 2000e",
                                { &dib0700_usb_id_table[11], NULL },
@@ -1642,6 +1646,10 @@ struct dvb_usb_device_properties dib0700_devices[] = {
                                { &dib0700_usb_id_table[14], NULL },
                                { NULL },
                        },
+                       {   "YUAN High-Tech DiBcom STK7700D",
+                               { &dib0700_usb_id_table[55], NULL },
+                               { NULL },
+                       },
 
                },
 
@@ -1822,7 +1830,7 @@ struct dvb_usb_device_properties dib0700_devices[] = {
                        },
                },
 
-               .num_device_descs = 8,
+               .num_device_descs = 9,
                .devices = {
                        {   "Terratec Cinergy HT USB XE",
                                { &dib0700_usb_id_table[27], NULL },
@@ -1856,7 +1864,10 @@ struct dvb_usb_device_properties dib0700_devices[] = {
                                { &dib0700_usb_id_table[51], NULL },
                                { NULL },
                        },
-
+                       {   "YUAN High-Tech STK7700D",
+                               { &dib0700_usb_id_table[54], NULL },
+                               { NULL },
+                       },
                },
                .rc_interval      = DEFAULT_RC_INTERVAL,
                .rc_key_map       = dib0700_rc_keys,
index 8dbad1ec53c404782d16c33e8929976a3ad8e386..da34979b5337732d62084e3d3acb3eae041969e3 100644 (file)
@@ -318,132 +318,132 @@ EXPORT_SYMBOL(dibusb_dib3000mc_tuner_attach);
  */
 struct dvb_usb_rc_key dibusb_rc_keys[] = {
        /* Key codes for the little Artec T1/Twinhan/HAMA/ remote. */
-       { 0x00, 0x16, KEY_POWER },
-       { 0x00, 0x10, KEY_MUTE },
-       { 0x00, 0x03, KEY_1 },
-       { 0x00, 0x01, KEY_2 },
-       { 0x00, 0x06, KEY_3 },
-       { 0x00, 0x09, KEY_4 },
-       { 0x00, 0x1d, KEY_5 },
-       { 0x00, 0x1f, KEY_6 },
-       { 0x00, 0x0d, KEY_7 },
-       { 0x00, 0x19, KEY_8 },
-       { 0x00, 0x1b, KEY_9 },
-       { 0x00, 0x15, KEY_0 },
-       { 0x00, 0x05, KEY_CHANNELUP },
-       { 0x00, 0x02, KEY_CHANNELDOWN },
-       { 0x00, 0x1e, KEY_VOLUMEUP },
-       { 0x00, 0x0a, KEY_VOLUMEDOWN },
-       { 0x00, 0x11, KEY_RECORD },
-       { 0x00, 0x17, KEY_FAVORITES }, /* Heart symbol - Channel list. */
-       { 0x00, 0x14, KEY_PLAY },
-       { 0x00, 0x1a, KEY_STOP },
-       { 0x00, 0x40, KEY_REWIND },
-       { 0x00, 0x12, KEY_FASTFORWARD },
-       { 0x00, 0x0e, KEY_PREVIOUS }, /* Recall - Previous channel. */
-       { 0x00, 0x4c, KEY_PAUSE },
-       { 0x00, 0x4d, KEY_SCREEN }, /* Full screen mode. */
-       { 0x00, 0x54, KEY_AUDIO }, /* MTS - Switch to secondary audio. */
+       { 0x0016, KEY_POWER },
+       { 0x0010, KEY_MUTE },
+       { 0x0003, KEY_1 },
+       { 0x0001, KEY_2 },
+       { 0x0006, KEY_3 },
+       { 0x0009, KEY_4 },
+       { 0x001d, KEY_5 },
+       { 0x001f, KEY_6 },
+       { 0x000d, KEY_7 },
+       { 0x0019, KEY_8 },
+       { 0x001b, KEY_9 },
+       { 0x0015, KEY_0 },
+       { 0x0005, KEY_CHANNELUP },
+       { 0x0002, KEY_CHANNELDOWN },
+       { 0x001e, KEY_VOLUMEUP },
+       { 0x000a, KEY_VOLUMEDOWN },
+       { 0x0011, KEY_RECORD },
+       { 0x0017, KEY_FAVORITES }, /* Heart symbol - Channel list. */
+       { 0x0014, KEY_PLAY },
+       { 0x001a, KEY_STOP },
+       { 0x0040, KEY_REWIND },
+       { 0x0012, KEY_FASTFORWARD },
+       { 0x000e, KEY_PREVIOUS }, /* Recall - Previous channel. */
+       { 0x004c, KEY_PAUSE },
+       { 0x004d, KEY_SCREEN }, /* Full screen mode. */
+       { 0x0054, KEY_AUDIO }, /* MTS - Switch to secondary audio. */
        /* additional keys TwinHan VisionPlus, the Artec seemingly not have */
-       { 0x00, 0x0c, KEY_CANCEL }, /* Cancel */
-       { 0x00, 0x1c, KEY_EPG }, /* EPG */
-       { 0x00, 0x00, KEY_TAB }, /* Tab */
-       { 0x00, 0x48, KEY_INFO }, /* Preview */
-       { 0x00, 0x04, KEY_LIST }, /* RecordList */
-       { 0x00, 0x0f, KEY_TEXT }, /* Teletext */
+       { 0x000c, KEY_CANCEL }, /* Cancel */
+       { 0x001c, KEY_EPG }, /* EPG */
+       { 0x0000, KEY_TAB }, /* Tab */
+       { 0x0048, KEY_INFO }, /* Preview */
+       { 0x0004, KEY_LIST }, /* RecordList */
+       { 0x000f, KEY_TEXT }, /* Teletext */
        /* Key codes for the KWorld/ADSTech/JetWay remote. */
-       { 0x86, 0x12, KEY_POWER },
-       { 0x86, 0x0f, KEY_SELECT }, /* source */
-       { 0x86, 0x0c, KEY_UNKNOWN }, /* scan */
-       { 0x86, 0x0b, KEY_EPG },
-       { 0x86, 0x10, KEY_MUTE },
-       { 0x86, 0x01, KEY_1 },
-       { 0x86, 0x02, KEY_2 },
-       { 0x86, 0x03, KEY_3 },
-       { 0x86, 0x04, KEY_4 },
-       { 0x86, 0x05, KEY_5 },
-       { 0x86, 0x06, KEY_6 },
-       { 0x86, 0x07, KEY_7 },
-       { 0x86, 0x08, KEY_8 },
-       { 0x86, 0x09, KEY_9 },
-       { 0x86, 0x0a, KEY_0 },
-       { 0x86, 0x18, KEY_ZOOM },
-       { 0x86, 0x1c, KEY_UNKNOWN }, /* preview */
-       { 0x86, 0x13, KEY_UNKNOWN }, /* snap */
-       { 0x86, 0x00, KEY_UNDO },
-       { 0x86, 0x1d, KEY_RECORD },
-       { 0x86, 0x0d, KEY_STOP },
-       { 0x86, 0x0e, KEY_PAUSE },
-       { 0x86, 0x16, KEY_PLAY },
-       { 0x86, 0x11, KEY_BACK },
-       { 0x86, 0x19, KEY_FORWARD },
-       { 0x86, 0x14, KEY_UNKNOWN }, /* pip */
-       { 0x86, 0x15, KEY_ESC },
-       { 0x86, 0x1a, KEY_UP },
-       { 0x86, 0x1e, KEY_DOWN },
-       { 0x86, 0x1f, KEY_LEFT },
-       { 0x86, 0x1b, KEY_RIGHT },
+       { 0x8612, KEY_POWER },
+       { 0x860f, KEY_SELECT }, /* source */
+       { 0x860c, KEY_UNKNOWN }, /* scan */
+       { 0x860b, KEY_EPG },
+       { 0x8610, KEY_MUTE },
+       { 0x8601, KEY_1 },
+       { 0x8602, KEY_2 },
+       { 0x8603, KEY_3 },
+       { 0x8604, KEY_4 },
+       { 0x8605, KEY_5 },
+       { 0x8606, KEY_6 },
+       { 0x8607, KEY_7 },
+       { 0x8608, KEY_8 },
+       { 0x8609, KEY_9 },
+       { 0x860a, KEY_0 },
+       { 0x8618, KEY_ZOOM },
+       { 0x861c, KEY_UNKNOWN }, /* preview */
+       { 0x8613, KEY_UNKNOWN }, /* snap */
+       { 0x8600, KEY_UNDO },
+       { 0x861d, KEY_RECORD },
+       { 0x860d, KEY_STOP },
+       { 0x860e, KEY_PAUSE },
+       { 0x8616, KEY_PLAY },
+       { 0x8611, KEY_BACK },
+       { 0x8619, KEY_FORWARD },
+       { 0x8614, KEY_UNKNOWN }, /* pip */
+       { 0x8615, KEY_ESC },
+       { 0x861a, KEY_UP },
+       { 0x861e, KEY_DOWN },
+       { 0x861f, KEY_LEFT },
+       { 0x861b, KEY_RIGHT },
 
        /* Key codes for the DiBcom MOD3000 remote. */
-       { 0x80, 0x00, KEY_MUTE },
-       { 0x80, 0x01, KEY_TEXT },
-       { 0x80, 0x02, KEY_HOME },
-       { 0x80, 0x03, KEY_POWER },
-
-       { 0x80, 0x04, KEY_RED },
-       { 0x80, 0x05, KEY_GREEN },
-       { 0x80, 0x06, KEY_YELLOW },
-       { 0x80, 0x07, KEY_BLUE },
-
-       { 0x80, 0x08, KEY_DVD },
-       { 0x80, 0x09, KEY_AUDIO },
-       { 0x80, 0x0a, KEY_MEDIA },      /* Pictures */
-       { 0x80, 0x0b, KEY_VIDEO },
-
-       { 0x80, 0x0c, KEY_BACK },
-       { 0x80, 0x0d, KEY_UP },
-       { 0x80, 0x0e, KEY_RADIO },
-       { 0x80, 0x0f, KEY_EPG },
-
-       { 0x80, 0x10, KEY_LEFT },
-       { 0x80, 0x11, KEY_OK },
-       { 0x80, 0x12, KEY_RIGHT },
-       { 0x80, 0x13, KEY_UNKNOWN },    /* SAP */
-
-       { 0x80, 0x14, KEY_TV },
-       { 0x80, 0x15, KEY_DOWN },
-       { 0x80, 0x16, KEY_MENU },       /* DVD Menu */
-       { 0x80, 0x17, KEY_LAST },
-
-       { 0x80, 0x18, KEY_RECORD },
-       { 0x80, 0x19, KEY_STOP },
-       { 0x80, 0x1a, KEY_PAUSE },
-       { 0x80, 0x1b, KEY_PLAY },
-
-       { 0x80, 0x1c, KEY_PREVIOUS },
-       { 0x80, 0x1d, KEY_REWIND },
-       { 0x80, 0x1e, KEY_FASTFORWARD },
-       { 0x80, 0x1f, KEY_NEXT},
-
-       { 0x80, 0x40, KEY_1 },
-       { 0x80, 0x41, KEY_2 },
-       { 0x80, 0x42, KEY_3 },
-       { 0x80, 0x43, KEY_CHANNELUP },
-
-       { 0x80, 0x44, KEY_4 },
-       { 0x80, 0x45, KEY_5 },
-       { 0x80, 0x46, KEY_6 },
-       { 0x80, 0x47, KEY_CHANNELDOWN },
-
-       { 0x80, 0x48, KEY_7 },
-       { 0x80, 0x49, KEY_8 },
-       { 0x80, 0x4a, KEY_9 },
-       { 0x80, 0x4b, KEY_VOLUMEUP },
-
-       { 0x80, 0x4c, KEY_CLEAR },
-       { 0x80, 0x4d, KEY_0 },
-       { 0x80, 0x4e, KEY_ENTER },
-       { 0x80, 0x4f, KEY_VOLUMEDOWN },
+       { 0x8000, KEY_MUTE },
+       { 0x8001, KEY_TEXT },
+       { 0x8002, KEY_HOME },
+       { 0x8003, KEY_POWER },
+
+       { 0x8004, KEY_RED },
+       { 0x8005, KEY_GREEN },
+       { 0x8006, KEY_YELLOW },
+       { 0x8007, KEY_BLUE },
+
+       { 0x8008, KEY_DVD },
+       { 0x8009, KEY_AUDIO },
+       { 0x800a, KEY_MEDIA },      /* Pictures */
+       { 0x800b, KEY_VIDEO },
+
+       { 0x800c, KEY_BACK },
+       { 0x800d, KEY_UP },
+       { 0x800e, KEY_RADIO },
+       { 0x800f, KEY_EPG },
+
+       { 0x8010, KEY_LEFT },
+       { 0x8011, KEY_OK },
+       { 0x8012, KEY_RIGHT },
+       { 0x8013, KEY_UNKNOWN },    /* SAP */
+
+       { 0x8014, KEY_TV },
+       { 0x8015, KEY_DOWN },
+       { 0x8016, KEY_MENU },       /* DVD Menu */
+       { 0x8017, KEY_LAST },
+
+       { 0x8018, KEY_RECORD },
+       { 0x8019, KEY_STOP },
+       { 0x801a, KEY_PAUSE },
+       { 0x801b, KEY_PLAY },
+
+       { 0x801c, KEY_PREVIOUS },
+       { 0x801d, KEY_REWIND },
+       { 0x801e, KEY_FASTFORWARD },
+       { 0x801f, KEY_NEXT},
+
+       { 0x8040, KEY_1 },
+       { 0x8041, KEY_2 },
+       { 0x8042, KEY_3 },
+       { 0x8043, KEY_CHANNELUP },
+
+       { 0x8044, KEY_4 },
+       { 0x8045, KEY_5 },
+       { 0x8046, KEY_6 },
+       { 0x8047, KEY_CHANNELDOWN },
+
+       { 0x8048, KEY_7 },
+       { 0x8049, KEY_8 },
+       { 0x804a, KEY_9 },
+       { 0x804b, KEY_VOLUMEUP },
+
+       { 0x804c, KEY_CLEAR },
+       { 0x804d, KEY_0 },
+       { 0x804e, KEY_ENTER },
+       { 0x804f, KEY_VOLUMEDOWN },
 };
 EXPORT_SYMBOL(dibusb_rc_keys);
 
index 059cec95531826aa8128bc3bcdc6e57e371ee6e7..a05b9f875663288f3b32f71e3a019812628744a4 100644 (file)
@@ -42,6 +42,8 @@ static struct usb_device_id dibusb_dib3000mc_table [] = {
 /* 11 */       { USB_DEVICE(USB_VID_ULTIMA_ELECTRONIC, USB_PID_ARTEC_T14_WARM) },
 /* 12 */       { USB_DEVICE(USB_VID_LEADTEK,           USB_PID_WINFAST_DTV_DONGLE_COLD) },
 /* 13 */       { USB_DEVICE(USB_VID_LEADTEK,           USB_PID_WINFAST_DTV_DONGLE_WARM) },
+/* 14 */       { USB_DEVICE(USB_VID_HUMAX_COEX,        USB_PID_DVB_T_USB_STICK_HIGH_SPEED_COLD) },
+/* 15 */       { USB_DEVICE(USB_VID_HUMAX_COEX,        USB_PID_DVB_T_USB_STICK_HIGH_SPEED_WARM) },
                        { }             /* Terminating entry */
 };
 MODULE_DEVICE_TABLE (usb, dibusb_dib3000mc_table);
@@ -66,7 +68,7 @@ static struct dvb_usb_device_properties dibusb_mc_properties = {
        /* parameter for the MPEG2-data transfer */
                        .stream = {
                                .type = USB_BULK,
-                               .count = 7,
+                               .count = 8,
                                .endpoint = 0x06,
                                .u = {
                                        .bulk = {
@@ -88,7 +90,7 @@ static struct dvb_usb_device_properties dibusb_mc_properties = {
 
        .generic_bulk_ctrl_endpoint = 0x01,
 
-       .num_device_descs = 7,
+       .num_device_descs = 8,
        .devices = {
                {   "DiBcom USB2.0 DVB-T reference design (MOD3000P)",
                        { &dibusb_dib3000mc_table[0], NULL },
@@ -119,6 +121,10 @@ static struct dvb_usb_device_properties dibusb_mc_properties = {
                        { &dibusb_dib3000mc_table[12], NULL },
                        { &dibusb_dib3000mc_table[13], NULL },
                },
+               {   "Humax/Coex DVB-T USB Stick 2.0 High Speed",
+                       { &dibusb_dib3000mc_table[14], NULL },
+                       { &dibusb_dib3000mc_table[15], NULL },
+               },
                { NULL },
        }
 };
index b545cf3eab2e5c0a63ac1f48ca67fca3cf8eae21..955147d0075696cd05d1a0aecd7e43194dde2d61 100644 (file)
@@ -162,61 +162,61 @@ static int digitv_tuner_attach(struct dvb_usb_adapter *adap)
 }
 
 static struct dvb_usb_rc_key digitv_rc_keys[] = {
-       { 0x5f, 0x55, KEY_0 },
-       { 0x6f, 0x55, KEY_1 },
-       { 0x9f, 0x55, KEY_2 },
-       { 0xaf, 0x55, KEY_3 },
-       { 0x5f, 0x56, KEY_4 },
-       { 0x6f, 0x56, KEY_5 },
-       { 0x9f, 0x56, KEY_6 },
-       { 0xaf, 0x56, KEY_7 },
-       { 0x5f, 0x59, KEY_8 },
-       { 0x6f, 0x59, KEY_9 },
-       { 0x9f, 0x59, KEY_TV },
-       { 0xaf, 0x59, KEY_AUX },
-       { 0x5f, 0x5a, KEY_DVD },
-       { 0x6f, 0x5a, KEY_POWER },
-       { 0x9f, 0x5a, KEY_MHP },     /* labelled 'Picture' */
-       { 0xaf, 0x5a, KEY_AUDIO },
-       { 0x5f, 0x65, KEY_INFO },
-       { 0x6f, 0x65, KEY_F13 },     /* 16:9 */
-       { 0x9f, 0x65, KEY_F14 },     /* 14:9 */
-       { 0xaf, 0x65, KEY_EPG },
-       { 0x5f, 0x66, KEY_EXIT },
-       { 0x6f, 0x66, KEY_MENU },
-       { 0x9f, 0x66, KEY_UP },
-       { 0xaf, 0x66, KEY_DOWN },
-       { 0x5f, 0x69, KEY_LEFT },
-       { 0x6f, 0x69, KEY_RIGHT },
-       { 0x9f, 0x69, KEY_ENTER },
-       { 0xaf, 0x69, KEY_CHANNELUP },
-       { 0x5f, 0x6a, KEY_CHANNELDOWN },
-       { 0x6f, 0x6a, KEY_VOLUMEUP },
-       { 0x9f, 0x6a, KEY_VOLUMEDOWN },
-       { 0xaf, 0x6a, KEY_RED },
-       { 0x5f, 0x95, KEY_GREEN },
-       { 0x6f, 0x95, KEY_YELLOW },
-       { 0x9f, 0x95, KEY_BLUE },
-       { 0xaf, 0x95, KEY_SUBTITLE },
-       { 0x5f, 0x96, KEY_F15 },     /* AD */
-       { 0x6f, 0x96, KEY_TEXT },
-       { 0x9f, 0x96, KEY_MUTE },
-       { 0xaf, 0x96, KEY_REWIND },
-       { 0x5f, 0x99, KEY_STOP },
-       { 0x6f, 0x99, KEY_PLAY },
-       { 0x9f, 0x99, KEY_FASTFORWARD },
-       { 0xaf, 0x99, KEY_F16 },     /* chapter */
-       { 0x5f, 0x9a, KEY_PAUSE },
-       { 0x6f, 0x9a, KEY_PLAY },
-       { 0x9f, 0x9a, KEY_RECORD },
-       { 0xaf, 0x9a, KEY_F17 },     /* picture in picture */
-       { 0x5f, 0xa5, KEY_KPPLUS },  /* zoom in */
-       { 0x6f, 0xa5, KEY_KPMINUS }, /* zoom out */
-       { 0x9f, 0xa5, KEY_F18 },     /* capture */
-       { 0xaf, 0xa5, KEY_F19 },     /* web */
-       { 0x5f, 0xa6, KEY_EMAIL },
-       { 0x6f, 0xa6, KEY_PHONE },
-       { 0x9f, 0xa6, KEY_PC },
+       { 0x5f55, KEY_0 },
+       { 0x6f55, KEY_1 },
+       { 0x9f55, KEY_2 },
+       { 0xaf55, KEY_3 },
+       { 0x5f56, KEY_4 },
+       { 0x6f56, KEY_5 },
+       { 0x9f56, KEY_6 },
+       { 0xaf56, KEY_7 },
+       { 0x5f59, KEY_8 },
+       { 0x6f59, KEY_9 },
+       { 0x9f59, KEY_TV },
+       { 0xaf59, KEY_AUX },
+       { 0x5f5a, KEY_DVD },
+       { 0x6f5a, KEY_POWER },
+       { 0x9f5a, KEY_MHP },     /* labelled 'Picture' */
+       { 0xaf5a, KEY_AUDIO },
+       { 0x5f65, KEY_INFO },
+       { 0x6f65, KEY_F13 },     /* 16:9 */
+       { 0x9f65, KEY_F14 },     /* 14:9 */
+       { 0xaf65, KEY_EPG },
+       { 0x5f66, KEY_EXIT },
+       { 0x6f66, KEY_MENU },
+       { 0x9f66, KEY_UP },
+       { 0xaf66, KEY_DOWN },
+       { 0x5f69, KEY_LEFT },
+       { 0x6f69, KEY_RIGHT },
+       { 0x9f69, KEY_ENTER },
+       { 0xaf69, KEY_CHANNELUP },
+       { 0x5f6a, KEY_CHANNELDOWN },
+       { 0x6f6a, KEY_VOLUMEUP },
+       { 0x9f6a, KEY_VOLUMEDOWN },
+       { 0xaf6a, KEY_RED },
+       { 0x5f95, KEY_GREEN },
+       { 0x6f95, KEY_YELLOW },
+       { 0x9f95, KEY_BLUE },
+       { 0xaf95, KEY_SUBTITLE },
+       { 0x5f96, KEY_F15 },     /* AD */
+       { 0x6f96, KEY_TEXT },
+       { 0x9f96, KEY_MUTE },
+       { 0xaf96, KEY_REWIND },
+       { 0x5f99, KEY_STOP },
+       { 0x6f99, KEY_PLAY },
+       { 0x9f99, KEY_FASTFORWARD },
+       { 0xaf99, KEY_F16 },     /* chapter */
+       { 0x5f9a, KEY_PAUSE },
+       { 0x6f9a, KEY_PLAY },
+       { 0x9f9a, KEY_RECORD },
+       { 0xaf9a, KEY_F17 },     /* picture in picture */
+       { 0x5fa5, KEY_KPPLUS },  /* zoom in */
+       { 0x6fa5, KEY_KPMINUS }, /* zoom out */
+       { 0x9fa5, KEY_F18 },     /* capture */
+       { 0xafa5, KEY_F19 },     /* web */
+       { 0x5fa6, KEY_EMAIL },
+       { 0x6fa6, KEY_PHONE },
+       { 0x9fa6, KEY_PC },
 };
 
 static int digitv_rc_query(struct dvb_usb_device *d, u32 *event, int *state)
@@ -238,8 +238,8 @@ static int digitv_rc_query(struct dvb_usb_device *d, u32 *event, int *state)
        if (key[1] != 0)
        {
                  for (i = 0; i < d->props.rc_key_map_size; i++) {
-                       if (d->props.rc_key_map[i].custom == key[1] &&
-                           d->props.rc_key_map[i].data == key[2]) {
+                       if (rc5_custom(&d->props.rc_key_map[i]) == key[1] &&
+                           rc5_data(&d->props.rc_key_map[i]) == key[2]) {
                                *event = d->props.rc_key_map[i].event;
                                *state = REMOTE_KEY_PRESSED;
                                return 0;
index 81a6cbf601603a6e8b2313921291350b131bd1ae..a1b12b01cbe4c418bfd6eb47da1ff48326f4e79b 100644 (file)
@@ -58,24 +58,24 @@ static int dtt200u_pid_filter(struct dvb_usb_adapter *adap, int index, u16 pid,
 /* remote control */
 /* key list for the tiny remote control (Yakumo, don't know about the others) */
 static struct dvb_usb_rc_key dtt200u_rc_keys[] = {
-       { 0x80, 0x01, KEY_MUTE },
-       { 0x80, 0x02, KEY_CHANNELDOWN },
-       { 0x80, 0x03, KEY_VOLUMEDOWN },
-       { 0x80, 0x04, KEY_1 },
-       { 0x80, 0x05, KEY_2 },
-       { 0x80, 0x06, KEY_3 },
-       { 0x80, 0x07, KEY_4 },
-       { 0x80, 0x08, KEY_5 },
-       { 0x80, 0x09, KEY_6 },
-       { 0x80, 0x0a, KEY_7 },
-       { 0x80, 0x0c, KEY_ZOOM },
-       { 0x80, 0x0d, KEY_0 },
-       { 0x80, 0x0e, KEY_SELECT },
-       { 0x80, 0x12, KEY_POWER },
-       { 0x80, 0x1a, KEY_CHANNELUP },
-       { 0x80, 0x1b, KEY_8 },
-       { 0x80, 0x1e, KEY_VOLUMEUP },
-       { 0x80, 0x1f, KEY_9 },
+       { 0x8001, KEY_MUTE },
+       { 0x8002, KEY_CHANNELDOWN },
+       { 0x8003, KEY_VOLUMEDOWN },
+       { 0x8004, KEY_1 },
+       { 0x8005, KEY_2 },
+       { 0x8006, KEY_3 },
+       { 0x8007, KEY_4 },
+       { 0x8008, KEY_5 },
+       { 0x8009, KEY_6 },
+       { 0x800a, KEY_7 },
+       { 0x800c, KEY_ZOOM },
+       { 0x800d, KEY_0 },
+       { 0x800e, KEY_SELECT },
+       { 0x8012, KEY_POWER },
+       { 0x801a, KEY_CHANNELUP },
+       { 0x801b, KEY_8 },
+       { 0x801e, KEY_VOLUMEUP },
+       { 0x801f, KEY_9 },
 };
 
 static int dtt200u_rc_query(struct dvb_usb_device *d, u32 *event, int *state)
index 326f7608954b12e36ef72c1d45a152793a89c5be..cead089bbb4ff268cc91c78a97b627fa064cc7eb 100644 (file)
@@ -19,7 +19,7 @@ int dvb_usb_i2c_init(struct dvb_usb_device *d)
                return -EINVAL;
        }
 
-       strncpy(d->i2c_adap.name, d->desc->name, sizeof(d->i2c_adap.name));
+       strlcpy(d->i2c_adap.name, d->desc->name, sizeof(d->i2c_adap.name));
        d->i2c_adap.class = I2C_CLASS_TV_DIGITAL,
        d->i2c_adap.algo      = d->props.i2c_algo;
        d->i2c_adap.algo_data = NULL;
index 9593b72899946c3e3f95f97e6cad7ebe191459b6..185a5069b10bdb26ebf1628ebb095bdd9d425468 100644 (file)
@@ -58,6 +58,7 @@
 #define USB_VID_GIGABYTE                       0x1044
 #define USB_VID_YUAN                           0x1164
 #define USB_VID_XTENSIONS                      0x1ae7
+#define USB_VID_HUMAX_COEX                     0x10b9
 
 /* Product IDs */
 #define USB_PID_ADSTECH_USB2_COLD                      0xa333
 #define USB_PID_GRANDTEC_DVBT_USB_WARM                 0x0fa1
 #define USB_PID_INTEL_CE9500                           0x9500
 #define USB_PID_KWORLD_399U                            0xe399
+#define USB_PID_KWORLD_399U_2                          0xe400
 #define USB_PID_KWORLD_395U                            0xe396
 #define USB_PID_KWORLD_395U_2                          0xe39b
 #define USB_PID_KWORLD_395U_3                          0xe395
 #define USB_PID_YUAN_STK7700PH                         0x1f08
 #define USB_PID_YUAN_PD378S                            0x2edc
 #define USB_PID_YUAN_MC770                             0x0871
+#define USB_PID_YUAN_STK7700D                          0x1efc
+#define USB_PID_YUAN_STK7700D_2                                0x1e8c
 #define USB_PID_DW2102                                 0x2102
 #define USB_PID_XTENSIONS_XD_380                       0x0381
 #define USB_PID_TELESTAR_STARSTICK_2                   0x8000
 #define USB_PID_SONY_PLAYTV                            0x0003
 #define USB_PID_ELGATO_EYETV_DTT                       0x0021
 #define USB_PID_ELGATO_EYETV_DTT_Dlx                   0x0020
+#define USB_PID_DVB_T_USB_STICK_HIGH_SPEED_COLD                0x5000
+#define USB_PID_DVB_T_USB_STICK_HIGH_SPEED_WARM                0x5001
 
 #endif
index c0c2c22ddd835143d087ca450306e90f342310c4..edde87c6aa3a406381b3f88a31731beeea7b4b85 100644 (file)
@@ -8,6 +8,71 @@
 #include "dvb-usb-common.h"
 #include <linux/usb/input.h>
 
+static int dvb_usb_getkeycode(struct input_dev *dev,
+                                   int scancode, int *keycode)
+{
+       struct dvb_usb_device *d = input_get_drvdata(dev);
+
+       struct dvb_usb_rc_key *keymap = d->props.rc_key_map;
+       int i;
+
+       /* See if we can match the raw key code. */
+       for (i = 0; i < d->props.rc_key_map_size; i++)
+               if (keymap[i].scan == scancode) {
+                       *keycode = keymap[i].event;
+                       return 0;
+               }
+
+       /*
+        * If is there extra space, returns KEY_RESERVED,
+        * otherwise, input core won't let dvb_usb_setkeycode
+        * to work
+        */
+       for (i = 0; i < d->props.rc_key_map_size; i++)
+               if (keymap[i].event == KEY_RESERVED ||
+                   keymap[i].event == KEY_UNKNOWN) {
+                       *keycode = KEY_RESERVED;
+                       return 0;
+               }
+
+       return -EINVAL;
+}
+
+static int dvb_usb_setkeycode(struct input_dev *dev,
+                                   int scancode, int keycode)
+{
+       struct dvb_usb_device *d = input_get_drvdata(dev);
+
+       struct dvb_usb_rc_key *keymap = d->props.rc_key_map;
+       int i;
+
+       /* Search if it is replacing an existing keycode */
+       for (i = 0; i < d->props.rc_key_map_size; i++)
+               if (keymap[i].scan == scancode) {
+                       keymap[i].event = keycode;
+                       return 0;
+               }
+
+       /* Search if is there a clean entry. If so, use it */
+       for (i = 0; i < d->props.rc_key_map_size; i++)
+               if (keymap[i].event == KEY_RESERVED ||
+                   keymap[i].event == KEY_UNKNOWN) {
+                       keymap[i].scan = scancode;
+                       keymap[i].event = keycode;
+                       return 0;
+               }
+
+       /*
+        * FIXME: Currently, it is not possible to increase the size of
+        * scancode table. For it to happen, one possibility
+        * would be to allocate a table with key_map_size + 1,
+        * copying data, appending the new key on it, and freeing
+        * the old one - or maybe just allocating some spare space
+        */
+
+       return -EINVAL;
+}
+
 /* Remote-control poll function - called every dib->rc_query_interval ms to see
  * whether the remote control has received anything.
  *
@@ -111,6 +176,8 @@ int dvb_usb_remote_init(struct dvb_usb_device *d)
        input_dev->phys = d->rc_phys;
        usb_to_input_id(d->udev, &input_dev->id);
        input_dev->dev.parent = &d->udev->dev;
+       input_dev->getkeycode = dvb_usb_getkeycode;
+       input_dev->setkeycode = dvb_usb_setkeycode;
 
        /* set the bits for the keys */
        deb_rc("key map size: %d\n", d->props.rc_key_map_size);
@@ -128,6 +195,8 @@ int dvb_usb_remote_init(struct dvb_usb_device *d)
        input_dev->rep[REP_PERIOD] = d->props.rc_interval;
        input_dev->rep[REP_DELAY]  = d->props.rc_interval + 150;
 
+       input_set_drvdata(input_dev, d);
+
        err = input_register_device(input_dev);
        if (err) {
                input_free_device(input_dev);
@@ -178,8 +247,8 @@ int dvb_usb_nec_rc_key_to_event(struct dvb_usb_device *d,
                        }
                        /* See if we can match the raw key code. */
                        for (i = 0; i < d->props.rc_key_map_size; i++)
-                               if (keymap[i].custom == keybuf[1] &&
-                                       keymap[i].data == keybuf[3]) {
+                               if (rc5_custom(&keymap[i]) == keybuf[1] &&
+                                       rc5_data(&keymap[i]) == keybuf[3]) {
                                        *event = keymap[i].event;
                                        *state = REMOTE_KEY_PRESSED;
                                        return 0;
index e441d274e6c117010f1da2ee91f083782f0823e4..fe2b87efb3f1ad81df0be039b9ac9e5303b04d77 100644 (file)
@@ -81,10 +81,25 @@ struct dvb_usb_device_description {
  * @event: the input event assigned to key identified by custom and data
  */
 struct dvb_usb_rc_key {
-       u8 custom,data;
+       u16 scan;
        u32 event;
 };
 
+static inline u8 rc5_custom(struct dvb_usb_rc_key *key)
+{
+       return (key->scan >> 8) & 0xff;
+}
+
+static inline u8 rc5_data(struct dvb_usb_rc_key *key)
+{
+       return key->scan & 0xff;
+}
+
+static inline u8 rc5_scan(struct dvb_usb_rc_key *key)
+{
+       return key->scan & 0xffff;
+}
+
 struct dvb_usb_device;
 struct dvb_usb_adapter;
 struct usb_data_stream;
index 75de49c0d94370e34e3922b398c5847bf55c7361..5bb9479d154ed8bffa673e0af51f4fa316293b77 100644 (file)
@@ -1,6 +1,6 @@
 /* DVB USB framework compliant Linux driver for the
 *      DVBWorld DVB-S 2101, 2102, DVB-S2 2104, DVB-C 3101,
-*      TeVii S600, S650 Cards
+*      TeVii S600, S630, S650 Cards
 * Copyright (C) 2008,2009 Igor M. Liplianin (liplianin@me.by)
 *
 *      This program is free software; you can redistribute it and/or modify it
@@ -18,6 +18,8 @@
 #include "eds1547.h"
 #include "cx24116.h"
 #include "tda1002x.h"
+#include "mt312.h"
+#include "zl10039.h"
 
 #ifndef USB_PID_DW2102
 #define USB_PID_DW2102 0x2102
 #define USB_PID_TEVII_S650 0xd650
 #endif
 
+#ifndef USB_PID_TEVII_S630
+#define USB_PID_TEVII_S630 0xd630
+#endif
+
 #define DW210X_READ_MSG 0
 #define DW210X_WRITE_MSG 1
 
@@ -436,6 +442,69 @@ static int dw3101_i2c_transfer(struct i2c_adapter *adap, struct i2c_msg msg[],
        return num;
 }
 
+static int s630_i2c_transfer(struct i2c_adapter *adap, struct i2c_msg msg[],
+                                                               int num)
+{
+       struct dvb_usb_device *d = i2c_get_adapdata(adap);
+       int ret = 0;
+
+       if (!d)
+               return -ENODEV;
+       if (mutex_lock_interruptible(&d->i2c_mutex) < 0)
+               return -EAGAIN;
+
+       switch (num) {
+       case 2: { /* read */
+               u8 ibuf[msg[1].len], obuf[3];
+               obuf[0] = msg[1].len;
+               obuf[1] = (msg[0].addr << 1);
+               obuf[2] = msg[0].buf[0];
+
+               ret = dw210x_op_rw(d->udev, 0x90, 0, 0,
+                                       obuf, 3, DW210X_WRITE_MSG);
+               msleep(5);
+               ret = dw210x_op_rw(d->udev, 0x91, 0, 0,
+                                       ibuf, msg[1].len, DW210X_READ_MSG);
+               memcpy(msg[1].buf, ibuf, msg[1].len);
+               break;
+       }
+       case 1:
+               switch (msg[0].addr) {
+               case 0x60:
+               case 0x0e: {
+                       /* write to zl10313, zl10039 register, */
+                       u8 obuf[msg[0].len + 2];
+                       obuf[0] = msg[0].len + 1;
+                       obuf[1] = (msg[0].addr << 1);
+                       memcpy(obuf + 2, msg[0].buf, msg[0].len);
+                       ret = dw210x_op_rw(d->udev, 0x80, 0, 0,
+                                       obuf, msg[0].len + 2, DW210X_WRITE_MSG);
+                       break;
+               }
+               case (DW2102_RC_QUERY): {
+                       u8 ibuf[4];
+                       ret  = dw210x_op_rw(d->udev, 0xb8, 0, 0,
+                                       ibuf, 4, DW210X_READ_MSG);
+                       msg[0].buf[0] = ibuf[3];
+                       break;
+               }
+               case (DW2102_VOLTAGE_CTRL): {
+                       u8 obuf[2];
+                       obuf[0] = 0x03;
+                       obuf[1] = msg[0].buf[0];
+                       ret = dw210x_op_rw(d->udev, 0x8a, 0, 0,
+                                       obuf, 2, DW210X_WRITE_MSG);
+                       break;
+               }
+               }
+
+               break;
+       }
+
+       mutex_unlock(&d->i2c_mutex);
+       return num;
+}
+
 static u32 dw210x_i2c_func(struct i2c_adapter *adapter)
 {
        return I2C_FUNC_I2C;
@@ -466,6 +535,11 @@ static struct i2c_algorithm dw3101_i2c_algo = {
        .functionality = dw210x_i2c_func,
 };
 
+static struct i2c_algorithm s630_i2c_algo = {
+       .master_xfer = s630_i2c_transfer,
+       .functionality = dw210x_i2c_func,
+};
+
 static int dw210x_read_mac_address(struct dvb_usb_device *d, u8 mac[6])
 {
        int i;
@@ -490,6 +564,37 @@ static int dw210x_read_mac_address(struct dvb_usb_device *d, u8 mac[6])
        return 0;
 };
 
+static int s630_read_mac_address(struct dvb_usb_device *d, u8 mac[6])
+{
+       int i, ret;
+       u8 buf[3], eeprom[256], eepromline[16];
+
+       for (i = 0; i < 256; i++) {
+               buf[0] = 1;
+               buf[1] = 0xa0;
+               buf[2] = i;
+               ret = dw210x_op_rw(d->udev, 0x90, 0, 0,
+                                       buf, 3, DW210X_WRITE_MSG);
+               ret = dw210x_op_rw(d->udev, 0x91, 0, 0,
+                                       buf, 1, DW210X_READ_MSG);
+               if (ret < 0) {
+                       err("read eeprom failed.");
+                       return -1;
+               } else {
+                       eepromline[i % 16] = buf[0];
+                       eeprom[i] = buf[0];
+               }
+
+               if ((i % 16) == 15) {
+                       deb_xfer("%02x: ", i - 15);
+                       debug_dump(eepromline, 16, deb_xfer);
+               }
+       }
+
+       memcpy(mac, eeprom + 16, 6);
+       return 0;
+};
+
 static int dw210x_set_voltage(struct dvb_frontend *fe, fe_sec_voltage_t voltage)
 {
        static u8 command_13v[1] = {0x00};
@@ -535,6 +640,10 @@ static struct tda10023_config dw3101_tda10023_config = {
        .invert = 1,
 };
 
+static struct mt312_config zl313_config = {
+       .demod_address = 0x0e,
+};
+
 static int dw2104_frontend_attach(struct dvb_usb_adapter *d)
 {
        if ((d->fe = dvb_attach(cx24116_attach, &dw2104_config,
@@ -596,6 +705,18 @@ static int dw3101_frontend_attach(struct dvb_usb_adapter *d)
        return -EIO;
 }
 
+static int s630_frontend_attach(struct dvb_usb_adapter *d)
+{
+       d->fe = dvb_attach(mt312_attach, &zl313_config,
+                               &d->dev->i2c_adap);
+       if (d->fe != NULL) {
+               d->fe->ops.set_voltage = dw210x_set_voltage;
+               info("Attached zl10313!\n");
+               return 0;
+       }
+       return -EIO;
+}
+
 static int dw2102_tuner_attach(struct dvb_usb_adapter *adap)
 {
        dvb_attach(dvb_pll_attach, adap->fe, 0x60,
@@ -619,123 +740,131 @@ static int dw3101_tuner_attach(struct dvb_usb_adapter *adap)
        return 0;
 }
 
+static int s630_zl10039_tuner_attach(struct dvb_usb_adapter *adap)
+{
+       dvb_attach(zl10039_attach, adap->fe, 0x60,
+               &adap->dev->i2c_adap);
+
+       return 0;
+}
+
 static struct dvb_usb_rc_key dw210x_rc_keys[] = {
-       { 0xf8, 0x0a, KEY_Q },          /*power*/
-       { 0xf8, 0x0c, KEY_M },          /*mute*/
-       { 0xf8, 0x11, KEY_1 },
-       { 0xf8, 0x12, KEY_2 },
-       { 0xf8, 0x13, KEY_3 },
-       { 0xf8, 0x14, KEY_4 },
-       { 0xf8, 0x15, KEY_5 },
-       { 0xf8, 0x16, KEY_6 },
-       { 0xf8, 0x17, KEY_7 },
-       { 0xf8, 0x18, KEY_8 },
-       { 0xf8, 0x19, KEY_9 },
-       { 0xf8, 0x10, KEY_0 },
-       { 0xf8, 0x1c, KEY_PAGEUP },     /*ch+*/
-       { 0xf8, 0x0f, KEY_PAGEDOWN },   /*ch-*/
-       { 0xf8, 0x1a, KEY_O },          /*vol+*/
-       { 0xf8, 0x0e, KEY_Z },          /*vol-*/
-       { 0xf8, 0x04, KEY_R },          /*rec*/
-       { 0xf8, 0x09, KEY_D },          /*fav*/
-       { 0xf8, 0x08, KEY_BACKSPACE },  /*rewind*/
-       { 0xf8, 0x07, KEY_A },          /*fast*/
-       { 0xf8, 0x0b, KEY_P },          /*pause*/
-       { 0xf8, 0x02, KEY_ESC },        /*cancel*/
-       { 0xf8, 0x03, KEY_G },          /*tab*/
-       { 0xf8, 0x00, KEY_UP },         /*up*/
-       { 0xf8, 0x1f, KEY_ENTER },      /*ok*/
-       { 0xf8, 0x01, KEY_DOWN },       /*down*/
-       { 0xf8, 0x05, KEY_C },          /*cap*/
-       { 0xf8, 0x06, KEY_S },          /*stop*/
-       { 0xf8, 0x40, KEY_F },          /*full*/
-       { 0xf8, 0x1e, KEY_W },          /*tvmode*/
-       { 0xf8, 0x1b, KEY_B },          /*recall*/
+       { 0xf80a, KEY_Q },              /*power*/
+       { 0xf80c, KEY_M },              /*mute*/
+       { 0xf811, KEY_1 },
+       { 0xf812, KEY_2 },
+       { 0xf813, KEY_3 },
+       { 0xf814, KEY_4 },
+       { 0xf815, KEY_5 },
+       { 0xf816, KEY_6 },
+       { 0xf817, KEY_7 },
+       { 0xf818, KEY_8 },
+       { 0xf819, KEY_9 },
+       { 0xf810, KEY_0 },
+       { 0xf81c, KEY_PAGEUP }, /*ch+*/
+       { 0xf80f, KEY_PAGEDOWN },       /*ch-*/
+       { 0xf81a, KEY_O },              /*vol+*/
+       { 0xf80e, KEY_Z },              /*vol-*/
+       { 0xf804, KEY_R },              /*rec*/
+       { 0xf809, KEY_D },              /*fav*/
+       { 0xf808, KEY_BACKSPACE },      /*rewind*/
+       { 0xf807, KEY_A },              /*fast*/
+       { 0xf80b, KEY_P },              /*pause*/
+       { 0xf802, KEY_ESC },    /*cancel*/
+       { 0xf803, KEY_G },              /*tab*/
+       { 0xf800, KEY_UP },             /*up*/
+       { 0xf81f, KEY_ENTER },  /*ok*/
+       { 0xf801, KEY_DOWN },   /*down*/
+       { 0xf805, KEY_C },              /*cap*/
+       { 0xf806, KEY_S },              /*stop*/
+       { 0xf840, KEY_F },              /*full*/
+       { 0xf81e, KEY_W },              /*tvmode*/
+       { 0xf81b, KEY_B },              /*recall*/
 };
 
 static struct dvb_usb_rc_key tevii_rc_keys[] = {
-       { 0xf8, 0x0a, KEY_POWER },
-       { 0xf8, 0x0c, KEY_MUTE },
-       { 0xf8, 0x11, KEY_1 },
-       { 0xf8, 0x12, KEY_2 },
-       { 0xf8, 0x13, KEY_3 },
-       { 0xf8, 0x14, KEY_4 },
-       { 0xf8, 0x15, KEY_5 },
-       { 0xf8, 0x16, KEY_6 },
-       { 0xf8, 0x17, KEY_7 },
-       { 0xf8, 0x18, KEY_8 },
-       { 0xf8, 0x19, KEY_9 },
-       { 0xf8, 0x10, KEY_0 },
-       { 0xf8, 0x1c, KEY_MENU },
-       { 0xf8, 0x0f, KEY_VOLUMEDOWN },
-       { 0xf8, 0x1a, KEY_LAST },
-       { 0xf8, 0x0e, KEY_OPEN },
-       { 0xf8, 0x04, KEY_RECORD },
-       { 0xf8, 0x09, KEY_VOLUMEUP },
-       { 0xf8, 0x08, KEY_CHANNELUP },
-       { 0xf8, 0x07, KEY_PVR },
-       { 0xf8, 0x0b, KEY_TIME },
-       { 0xf8, 0x02, KEY_RIGHT },
-       { 0xf8, 0x03, KEY_LEFT },
-       { 0xf8, 0x00, KEY_UP },
-       { 0xf8, 0x1f, KEY_OK },
-       { 0xf8, 0x01, KEY_DOWN },
-       { 0xf8, 0x05, KEY_TUNER },
-       { 0xf8, 0x06, KEY_CHANNELDOWN },
-       { 0xf8, 0x40, KEY_PLAYPAUSE },
-       { 0xf8, 0x1e, KEY_REWIND },
-       { 0xf8, 0x1b, KEY_FAVORITES },
-       { 0xf8, 0x1d, KEY_BACK },
-       { 0xf8, 0x4d, KEY_FASTFORWARD },
-       { 0xf8, 0x44, KEY_EPG },
-       { 0xf8, 0x4c, KEY_INFO },
-       { 0xf8, 0x41, KEY_AB },
-       { 0xf8, 0x43, KEY_AUDIO },
-       { 0xf8, 0x45, KEY_SUBTITLE },
-       { 0xf8, 0x4a, KEY_LIST },
-       { 0xf8, 0x46, KEY_F1 },
-       { 0xf8, 0x47, KEY_F2 },
-       { 0xf8, 0x5e, KEY_F3 },
-       { 0xf8, 0x5c, KEY_F4 },
-       { 0xf8, 0x52, KEY_F5 },
-       { 0xf8, 0x5a, KEY_F6 },
-       { 0xf8, 0x56, KEY_MODE },
-       { 0xf8, 0x58, KEY_SWITCHVIDEOMODE },
+       { 0xf80a, KEY_POWER },
+       { 0xf80c, KEY_MUTE },
+       { 0xf811, KEY_1 },
+       { 0xf812, KEY_2 },
+       { 0xf813, KEY_3 },
+       { 0xf814, KEY_4 },
+       { 0xf815, KEY_5 },
+       { 0xf816, KEY_6 },
+       { 0xf817, KEY_7 },
+       { 0xf818, KEY_8 },
+       { 0xf819, KEY_9 },
+       { 0xf810, KEY_0 },
+       { 0xf81c, KEY_MENU },
+       { 0xf80f, KEY_VOLUMEDOWN },
+       { 0xf81a, KEY_LAST },
+       { 0xf80e, KEY_OPEN },
+       { 0xf804, KEY_RECORD },
+       { 0xf809, KEY_VOLUMEUP },
+       { 0xf808, KEY_CHANNELUP },
+       { 0xf807, KEY_PVR },
+       { 0xf80b, KEY_TIME },
+       { 0xf802, KEY_RIGHT },
+       { 0xf803, KEY_LEFT },
+       { 0xf800, KEY_UP },
+       { 0xf81f, KEY_OK },
+       { 0xf801, KEY_DOWN },
+       { 0xf805, KEY_TUNER },
+       { 0xf806, KEY_CHANNELDOWN },
+       { 0xf840, KEY_PLAYPAUSE },
+       { 0xf81e, KEY_REWIND },
+       { 0xf81b, KEY_FAVORITES },
+       { 0xf81d, KEY_BACK },
+       { 0xf84d, KEY_FASTFORWARD },
+       { 0xf844, KEY_EPG },
+       { 0xf84c, KEY_INFO },
+       { 0xf841, KEY_AB },
+       { 0xf843, KEY_AUDIO },
+       { 0xf845, KEY_SUBTITLE },
+       { 0xf84a, KEY_LIST },
+       { 0xf846, KEY_F1 },
+       { 0xf847, KEY_F2 },
+       { 0xf85e, KEY_F3 },
+       { 0xf85c, KEY_F4 },
+       { 0xf852, KEY_F5 },
+       { 0xf85a, KEY_F6 },
+       { 0xf856, KEY_MODE },
+       { 0xf858, KEY_SWITCHVIDEOMODE },
 };
 
 static struct dvb_usb_rc_key tbs_rc_keys[] = {
-       { 0xf8, 0x84, KEY_POWER },
-       { 0xf8, 0x94, KEY_MUTE },
-       { 0xf8, 0x87, KEY_1 },
-       { 0xf8, 0x86, KEY_2 },
-       { 0xf8, 0x85, KEY_3 },
-       { 0xf8, 0x8b, KEY_4 },
-       { 0xf8, 0x8a, KEY_5 },
-       { 0xf8, 0x89, KEY_6 },
-       { 0xf8, 0x8f, KEY_7 },
-       { 0xf8, 0x8e, KEY_8 },
-       { 0xf8, 0x8d, KEY_9 },
-       { 0xf8, 0x92, KEY_0 },
-       { 0xf8, 0x96, KEY_CHANNELUP },
-       { 0xf8, 0x91, KEY_CHANNELDOWN },
-       { 0xf8, 0x93, KEY_VOLUMEUP },
-       { 0xf8, 0x8c, KEY_VOLUMEDOWN },
-       { 0xf8, 0x83, KEY_RECORD },
-       { 0xf8, 0x98, KEY_PAUSE  },
-       { 0xf8, 0x99, KEY_OK },
-       { 0xf8, 0x9a, KEY_SHUFFLE },
-       { 0xf8, 0x81, KEY_UP },
-       { 0xf8, 0x90, KEY_LEFT },
-       { 0xf8, 0x82, KEY_RIGHT },
-       { 0xf8, 0x88, KEY_DOWN },
-       { 0xf8, 0x95, KEY_FAVORITES },
-       { 0xf8, 0x97, KEY_SUBTITLE },
-       { 0xf8, 0x9d, KEY_ZOOM },
-       { 0xf8, 0x9f, KEY_EXIT },
-       { 0xf8, 0x9e, KEY_MENU },
-       { 0xf8, 0x9c, KEY_EPG },
-       { 0xf8, 0x80, KEY_PREVIOUS },
-       { 0xf8, 0x9b, KEY_MODE }
+       { 0xf884, KEY_POWER },
+       { 0xf894, KEY_MUTE },
+       { 0xf887, KEY_1 },
+       { 0xf886, KEY_2 },
+       { 0xf885, KEY_3 },
+       { 0xf88b, KEY_4 },
+       { 0xf88a, KEY_5 },
+       { 0xf889, KEY_6 },
+       { 0xf88f, KEY_7 },
+       { 0xf88e, KEY_8 },
+       { 0xf88d, KEY_9 },
+       { 0xf892, KEY_0 },
+       { 0xf896, KEY_CHANNELUP },
+       { 0xf891, KEY_CHANNELDOWN },
+       { 0xf893, KEY_VOLUMEUP },
+       { 0xf88c, KEY_VOLUMEDOWN },
+       { 0xf883, KEY_RECORD },
+       { 0xf898, KEY_PAUSE  },
+       { 0xf899, KEY_OK },
+       { 0xf89a, KEY_SHUFFLE },
+       { 0xf881, KEY_UP },
+       { 0xf890, KEY_LEFT },
+       { 0xf882, KEY_RIGHT },
+       { 0xf888, KEY_DOWN },
+       { 0xf895, KEY_FAVORITES },
+       { 0xf897, KEY_SUBTITLE },
+       { 0xf89d, KEY_ZOOM },
+       { 0xf89f, KEY_EXIT },
+       { 0xf89e, KEY_MENU },
+       { 0xf89c, KEY_EPG },
+       { 0xf880, KEY_PREVIOUS },
+       { 0xf89b, KEY_MODE }
 };
 
 static struct dvb_usb_rc_keys_table keys_tables[] = {
@@ -763,9 +892,9 @@ static int dw2102_rc_query(struct dvb_usb_device *d, u32 *event, int *state)
        }
 
        *state = REMOTE_NO_KEY_PRESSED;
-       if (dw2102_i2c_transfer(&d->i2c_adap, &msg, 1) == 1) {
+       if (d->props.i2c_algo->master_xfer(&d->i2c_adap, &msg, 1) == 1) {
                for (i = 0; i < keymap_size ; i++) {
-                       if (keymap[i].data == msg.buf[0]) {
+                       if (rc5_data(&keymap[i]) == msg.buf[0]) {
                                *state = REMOTE_KEY_PRESSED;
                                *event = keymap[i].event;
                                break;
@@ -792,6 +921,7 @@ static struct usb_device_id dw2102_table[] = {
        {USB_DEVICE(0x9022, USB_PID_TEVII_S650)},
        {USB_DEVICE(USB_VID_TERRATEC, USB_PID_CINERGY_S)},
        {USB_DEVICE(USB_VID_CYPRESS, USB_PID_DW3101)},
+       {USB_DEVICE(0x9022, USB_PID_TEVII_S630)},
        { }
 };
 
@@ -806,6 +936,7 @@ static int dw2102_load_firmware(struct usb_device *dev,
        u8 reset16[] = {0, 0, 0, 0, 0, 0, 0};
        const struct firmware *fw;
        const char *filename = "dvb-usb-dw2101.fw";
+
        switch (dev->descriptor.idProduct) {
        case 0x2101:
                ret = request_firmware(&fw, filename, &dev->dev);
@@ -1053,6 +1184,48 @@ static struct dvb_usb_device_properties dw3101_properties = {
        }
 };
 
+static struct dvb_usb_device_properties s630_properties = {
+       .caps = DVB_USB_IS_AN_I2C_ADAPTER,
+       .usb_ctrl = DEVICE_SPECIFIC,
+       .firmware = "dvb-usb-s630.fw",
+       .no_reconnect = 1,
+
+       .i2c_algo = &s630_i2c_algo,
+       .rc_key_map = tevii_rc_keys,
+       .rc_key_map_size = ARRAY_SIZE(tevii_rc_keys),
+       .rc_interval = 150,
+       .rc_query = dw2102_rc_query,
+
+       .generic_bulk_ctrl_endpoint = 0x81,
+       .num_adapters = 1,
+       .download_firmware = dw2102_load_firmware,
+       .read_mac_address = s630_read_mac_address,
+       .adapter = {
+               {
+                       .frontend_attach = s630_frontend_attach,
+                       .streaming_ctrl = NULL,
+                       .tuner_attach = s630_zl10039_tuner_attach,
+                       .stream = {
+                               .type = USB_BULK,
+                               .count = 8,
+                               .endpoint = 0x82,
+                               .u = {
+                                       .bulk = {
+                                               .buffersize = 4096,
+                                       }
+                               }
+                       },
+               }
+       },
+       .num_device_descs = 1,
+       .devices = {
+               {"TeVii S630 USB",
+                       {&dw2102_table[6], NULL},
+                       {NULL},
+               },
+       }
+};
+
 static int dw2102_probe(struct usb_interface *intf,
                const struct usb_device_id *id)
 {
@@ -1061,6 +1234,8 @@ static int dw2102_probe(struct usb_interface *intf,
            0 == dvb_usb_device_init(intf, &dw2104_properties,
                        THIS_MODULE, NULL, adapter_nr) ||
            0 == dvb_usb_device_init(intf, &dw3101_properties,
+                       THIS_MODULE, NULL, adapter_nr) ||
+           0 == dvb_usb_device_init(intf, &s630_properties,
                        THIS_MODULE, NULL, adapter_nr)) {
                return 0;
        }
@@ -1094,6 +1269,6 @@ module_exit(dw2102_module_exit);
 MODULE_AUTHOR("Igor M. Liplianin (c) liplianin@me.by");
 MODULE_DESCRIPTION("Driver for DVBWorld DVB-S 2101, 2102, DVB-S2 2104,"
                                " DVB-C 3101 USB2.0,"
-                               " TeVii S600, S650 USB2.0 devices");
+                               " TeVii S600, S630, S650 USB2.0 devices");
 MODULE_VERSION("0.1");
 MODULE_LICENSE("GPL");
index 54626a0dbf68da45274c92fd3f78a18ff48b6857..aec7a1943b668c9d9152878d48850dbd56e00b7c 100644 (file)
@@ -140,7 +140,7 @@ static int m920x_rc_query(struct dvb_usb_device *d, u32 *event, int *state)
                goto unlock;
 
        for (i = 0; i < d->props.rc_key_map_size; i++)
-               if (d->props.rc_key_map[i].data == rc_state[1]) {
+               if (rc5_data(&d->props.rc_key_map[i]) == rc_state[1]) {
                        *event = d->props.rc_key_map[i].event;
 
                        switch(rc_state[0]) {
@@ -562,42 +562,42 @@ static struct m920x_inits tvwalkertwin_rc_init [] = {
 
 /* ir keymaps */
 static struct dvb_usb_rc_key megasky_rc_keys [] = {
-       { 0x0, 0x12, KEY_POWER },
-       { 0x0, 0x1e, KEY_CYCLEWINDOWS }, /* min/max */
-       { 0x0, 0x02, KEY_CHANNELUP },
-       { 0x0, 0x05, KEY_CHANNELDOWN },
-       { 0x0, 0x03, KEY_VOLUMEUP },
-       { 0x0, 0x06, KEY_VOLUMEDOWN },
-       { 0x0, 0x04, KEY_MUTE },
-       { 0x0, 0x07, KEY_OK }, /* TS */
-       { 0x0, 0x08, KEY_STOP },
-       { 0x0, 0x09, KEY_MENU }, /* swap */
-       { 0x0, 0x0a, KEY_REWIND },
-       { 0x0, 0x1b, KEY_PAUSE },
-       { 0x0, 0x1f, KEY_FASTFORWARD },
-       { 0x0, 0x0c, KEY_RECORD },
-       { 0x0, 0x0d, KEY_CAMERA }, /* screenshot */
-       { 0x0, 0x0e, KEY_COFFEE }, /* "MTS" */
+       { 0x0012, KEY_POWER },
+       { 0x001e, KEY_CYCLEWINDOWS }, /* min/max */
+       { 0x0002, KEY_CHANNELUP },
+       { 0x0005, KEY_CHANNELDOWN },
+       { 0x0003, KEY_VOLUMEUP },
+       { 0x0006, KEY_VOLUMEDOWN },
+       { 0x0004, KEY_MUTE },
+       { 0x0007, KEY_OK }, /* TS */
+       { 0x0008, KEY_STOP },
+       { 0x0009, KEY_MENU }, /* swap */
+       { 0x000a, KEY_REWIND },
+       { 0x001b, KEY_PAUSE },
+       { 0x001f, KEY_FASTFORWARD },
+       { 0x000c, KEY_RECORD },
+       { 0x000d, KEY_CAMERA }, /* screenshot */
+       { 0x000e, KEY_COFFEE }, /* "MTS" */
 };
 
 static struct dvb_usb_rc_key tvwalkertwin_rc_keys [] = {
-       { 0x0, 0x01, KEY_ZOOM }, /* Full Screen */
-       { 0x0, 0x02, KEY_CAMERA }, /* snapshot */
-       { 0x0, 0x03, KEY_MUTE },
-       { 0x0, 0x04, KEY_REWIND },
-       { 0x0, 0x05, KEY_PLAYPAUSE }, /* Play/Pause */
-       { 0x0, 0x06, KEY_FASTFORWARD },
-       { 0x0, 0x07, KEY_RECORD },
-       { 0x0, 0x08, KEY_STOP },
-       { 0x0, 0x09, KEY_TIME }, /* Timeshift */
-       { 0x0, 0x0c, KEY_COFFEE }, /* Recall */
-       { 0x0, 0x0e, KEY_CHANNELUP },
-       { 0x0, 0x12, KEY_POWER },
-       { 0x0, 0x15, KEY_MENU }, /* source */
-       { 0x0, 0x18, KEY_CYCLEWINDOWS }, /* TWIN PIP */
-       { 0x0, 0x1a, KEY_CHANNELDOWN },
-       { 0x0, 0x1b, KEY_VOLUMEDOWN },
-       { 0x0, 0x1e, KEY_VOLUMEUP },
+       { 0x0001, KEY_ZOOM }, /* Full Screen */
+       { 0x0002, KEY_CAMERA }, /* snapshot */
+       { 0x0003, KEY_MUTE },
+       { 0x0004, KEY_REWIND },
+       { 0x0005, KEY_PLAYPAUSE }, /* Play/Pause */
+       { 0x0006, KEY_FASTFORWARD },
+       { 0x0007, KEY_RECORD },
+       { 0x0008, KEY_STOP },
+       { 0x0009, KEY_TIME }, /* Timeshift */
+       { 0x000c, KEY_COFFEE }, /* Recall */
+       { 0x000e, KEY_CHANNELUP },
+       { 0x0012, KEY_POWER },
+       { 0x0015, KEY_MENU }, /* source */
+       { 0x0018, KEY_CYCLEWINDOWS }, /* TWIN PIP */
+       { 0x001a, KEY_CHANNELDOWN },
+       { 0x001b, KEY_VOLUMEDOWN },
+       { 0x001e, KEY_VOLUMEUP },
 };
 
 /* DVB USB Driver stuff */
index 07fb843c7c2b22d35b4a977dd405e2b6d5e97ab7..b41d66ef832556f3cad0ac93578e5494635a148f 100644 (file)
@@ -22,51 +22,51 @@ DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr);
 
 /* Hauppauge NOVA-T USB2 keys */
 static struct dvb_usb_rc_key haupp_rc_keys [] = {
-       { 0x1e, 0x00, KEY_0 },
-       { 0x1e, 0x01, KEY_1 },
-       { 0x1e, 0x02, KEY_2 },
-       { 0x1e, 0x03, KEY_3 },
-       { 0x1e, 0x04, KEY_4 },
-       { 0x1e, 0x05, KEY_5 },
-       { 0x1e, 0x06, KEY_6 },
-       { 0x1e, 0x07, KEY_7 },
-       { 0x1e, 0x08, KEY_8 },
-       { 0x1e, 0x09, KEY_9 },
-       { 0x1e, 0x0a, KEY_KPASTERISK },
-       { 0x1e, 0x0b, KEY_RED },
-       { 0x1e, 0x0c, KEY_RADIO },
-       { 0x1e, 0x0d, KEY_MENU },
-       { 0x1e, 0x0e, KEY_GRAVE }, /* # */
-       { 0x1e, 0x0f, KEY_MUTE },
-       { 0x1e, 0x10, KEY_VOLUMEUP },
-       { 0x1e, 0x11, KEY_VOLUMEDOWN },
-       { 0x1e, 0x12, KEY_CHANNEL },
-       { 0x1e, 0x14, KEY_UP },
-       { 0x1e, 0x15, KEY_DOWN },
-       { 0x1e, 0x16, KEY_LEFT },
-       { 0x1e, 0x17, KEY_RIGHT },
-       { 0x1e, 0x18, KEY_VIDEO },
-       { 0x1e, 0x19, KEY_AUDIO },
-       { 0x1e, 0x1a, KEY_MEDIA },
-       { 0x1e, 0x1b, KEY_EPG },
-       { 0x1e, 0x1c, KEY_TV },
-       { 0x1e, 0x1e, KEY_NEXT },
-       { 0x1e, 0x1f, KEY_BACK },
-       { 0x1e, 0x20, KEY_CHANNELUP },
-       { 0x1e, 0x21, KEY_CHANNELDOWN },
-       { 0x1e, 0x24, KEY_LAST }, /* Skip backwards */
-       { 0x1e, 0x25, KEY_OK },
-       { 0x1e, 0x29, KEY_BLUE},
-       { 0x1e, 0x2e, KEY_GREEN },
-       { 0x1e, 0x30, KEY_PAUSE },
-       { 0x1e, 0x32, KEY_REWIND },
-       { 0x1e, 0x34, KEY_FASTFORWARD },
-       { 0x1e, 0x35, KEY_PLAY },
-       { 0x1e, 0x36, KEY_STOP },
-       { 0x1e, 0x37, KEY_RECORD },
-       { 0x1e, 0x38, KEY_YELLOW },
-       { 0x1e, 0x3b, KEY_GOTO },
-       { 0x1e, 0x3d, KEY_POWER },
+       { 0x1e00, KEY_0 },
+       { 0x1e01, KEY_1 },
+       { 0x1e02, KEY_2 },
+       { 0x1e03, KEY_3 },
+       { 0x1e04, KEY_4 },
+       { 0x1e05, KEY_5 },
+       { 0x1e06, KEY_6 },
+       { 0x1e07, KEY_7 },
+       { 0x1e08, KEY_8 },
+       { 0x1e09, KEY_9 },
+       { 0x1e0a, KEY_KPASTERISK },
+       { 0x1e0b, KEY_RED },
+       { 0x1e0c, KEY_RADIO },
+       { 0x1e0d, KEY_MENU },
+       { 0x1e0e, KEY_GRAVE }, /* # */
+       { 0x1e0f, KEY_MUTE },
+       { 0x1e10, KEY_VOLUMEUP },
+       { 0x1e11, KEY_VOLUMEDOWN },
+       { 0x1e12, KEY_CHANNEL },
+       { 0x1e14, KEY_UP },
+       { 0x1e15, KEY_DOWN },
+       { 0x1e16, KEY_LEFT },
+       { 0x1e17, KEY_RIGHT },
+       { 0x1e18, KEY_VIDEO },
+       { 0x1e19, KEY_AUDIO },
+       { 0x1e1a, KEY_MEDIA },
+       { 0x1e1b, KEY_EPG },
+       { 0x1e1c, KEY_TV },
+       { 0x1e1e, KEY_NEXT },
+       { 0x1e1f, KEY_BACK },
+       { 0x1e20, KEY_CHANNELUP },
+       { 0x1e21, KEY_CHANNELDOWN },
+       { 0x1e24, KEY_LAST }, /* Skip backwards */
+       { 0x1e25, KEY_OK },
+       { 0x1e29, KEY_BLUE},
+       { 0x1e2e, KEY_GREEN },
+       { 0x1e30, KEY_PAUSE },
+       { 0x1e32, KEY_REWIND },
+       { 0x1e34, KEY_FASTFORWARD },
+       { 0x1e35, KEY_PLAY },
+       { 0x1e36, KEY_STOP },
+       { 0x1e37, KEY_RECORD },
+       { 0x1e38, KEY_YELLOW },
+       { 0x1e3b, KEY_GOTO },
+       { 0x1e3d, KEY_POWER },
 };
 
 /* Firmware bug? sometimes, when a new key is pressed, the previous pressed key
@@ -92,10 +92,11 @@ static int nova_t_rc_query(struct dvb_usb_device *d, u32 *event, int *state)
                        deb_rc("raw key code 0x%02x, 0x%02x, 0x%02x to c: %02x d: %02x toggle: %d\n",key[1],key[2],key[3],custom,data,toggle);
 
                        for (i = 0; i < ARRAY_SIZE(haupp_rc_keys); i++) {
-                               if (haupp_rc_keys[i].data == data &&
-                                       haupp_rc_keys[i].custom == custom) {
+                               if (rc5_data(&haupp_rc_keys[i]) == data &&
+                                       rc5_custom(&haupp_rc_keys[i]) == custom) {
 
-                                       deb_rc("c: %x, d: %x\n",haupp_rc_keys[i].data,haupp_rc_keys[i].custom);
+                                       deb_rc("c: %x, d: %x\n", rc5_data(&haupp_rc_keys[i]),
+                                                                rc5_custom(&haupp_rc_keys[i]));
 
                                        *event = haupp_rc_keys[i].event;
                                        *state = REMOTE_KEY_PRESSED;
index 7e32d11f32b0fd6e4ddc41714d7dd3242bacc819..d4e230941679a880ac154d21d5db31104c4f8275 100644 (file)
@@ -332,32 +332,32 @@ static int opera1_pid_filter_control(struct dvb_usb_adapter *adap, int onoff)
 }
 
 static struct dvb_usb_rc_key opera1_rc_keys[] = {
-       {0x5f, 0xa0, KEY_1},
-       {0x51, 0xaf, KEY_2},
-       {0x5d, 0xa2, KEY_3},
-       {0x41, 0xbe, KEY_4},
-       {0x0b, 0xf5, KEY_5},
-       {0x43, 0xbd, KEY_6},
-       {0x47, 0xb8, KEY_7},
-       {0x49, 0xb6, KEY_8},
-       {0x05, 0xfa, KEY_9},
-       {0x45, 0xba, KEY_0},
-       {0x09, 0xf6, KEY_UP},   /*chanup */
-       {0x1b, 0xe5, KEY_DOWN}, /*chandown */
-       {0x5d, 0xa3, KEY_LEFT}, /*voldown */
-       {0x5f, 0xa1, KEY_RIGHT},        /*volup */
-       {0x07, 0xf8, KEY_SPACE},        /*tab */
-       {0x1f, 0xe1, KEY_ENTER},        /*play ok */
-       {0x1b, 0xe4, KEY_Z},    /*zoom */
-       {0x59, 0xa6, KEY_M},    /*mute */
-       {0x5b, 0xa5, KEY_F},    /*tv/f */
-       {0x19, 0xe7, KEY_R},    /*rec */
-       {0x01, 0xfe, KEY_S},    /*Stop */
-       {0x03, 0xfd, KEY_P},    /*pause */
-       {0x03, 0xfc, KEY_W},    /*<- -> */
-       {0x07, 0xf9, KEY_C},    /*capture */
-       {0x47, 0xb9, KEY_Q},    /*exit */
-       {0x43, 0xbc, KEY_O},    /*power */
+       {0x5fa0, KEY_1},
+       {0x51af, KEY_2},
+       {0x5da2, KEY_3},
+       {0x41be, KEY_4},
+       {0x0bf5, KEY_5},
+       {0x43bd, KEY_6},
+       {0x47b8, KEY_7},
+       {0x49b6, KEY_8},
+       {0x05fa, KEY_9},
+       {0x45ba, KEY_0},
+       {0x09f6, KEY_UP},       /*chanup */
+       {0x1be5, KEY_DOWN},     /*chandown */
+       {0x5da3, KEY_LEFT},     /*voldown */
+       {0x5fa1, KEY_RIGHT},    /*volup */
+       {0x07f8, KEY_SPACE},    /*tab */
+       {0x1fe1, KEY_ENTER},    /*play ok */
+       {0x1be4, KEY_Z},        /*zoom */
+       {0x59a6, KEY_M},        /*mute */
+       {0x5ba5, KEY_F},        /*tv/f */
+       {0x19e7, KEY_R},        /*rec */
+       {0x01fe, KEY_S},        /*Stop */
+       {0x03fd, KEY_P},        /*pause */
+       {0x03fc, KEY_W},        /*<- -> */
+       {0x07f9, KEY_C},        /*capture */
+       {0x47b9, KEY_Q},        /*exit */
+       {0x43bc, KEY_O},        /*power */
 
 };
 
@@ -405,8 +405,7 @@ static int opera1_rc_query(struct dvb_usb_device *dev, u32 * event, int *state)
                send_key = (send_key & 0xffff) | 0x0100;
 
                for (i = 0; i < ARRAY_SIZE(opera1_rc_keys); i++) {
-                       if ((opera1_rc_keys[i].custom * 256 +
-                                       opera1_rc_keys[i].data) == (send_key & 0xffff)) {
+                       if (rc5_scan(&opera1_rc_keys[i]) == (send_key & 0xffff)) {
                                *state = REMOTE_KEY_PRESSED;
                                *event = opera1_rc_keys[i].event;
                                opst->last_key_pressed =
index 986fff9a5ba81580c6a40bcbfb2bd13100b0dddb..ef4e37d9c5ffa7a05b06f94269aced50f95a800e 100644 (file)
@@ -175,8 +175,8 @@ static int vp702x_streaming_ctrl(struct dvb_usb_adapter *adap, int onoff)
 
 /* keys for the enclosed remote control */
 static struct dvb_usb_rc_key vp702x_rc_keys[] = {
-       { 0x00, 0x01, KEY_1 },
-       { 0x00, 0x02, KEY_2 },
+       { 0x0001, KEY_1 },
+       { 0x0002, KEY_2 },
 };
 
 /* remote control stuff (does not work with my box) */
@@ -198,7 +198,7 @@ static int vp702x_rc_query(struct dvb_usb_device *d, u32 *event, int *state)
        }
 
        for (i = 0; i < ARRAY_SIZE(vp702x_rc_keys); i++)
-               if (vp702x_rc_keys[i].custom == key[1]) {
+               if (rc5_custom(&vp702x_rc_keys[i]) == key[1]) {
                        *state = REMOTE_KEY_PRESSED;
                        *event = vp702x_rc_keys[i].event;
                        break;
index acb345504e0da0cbd8d3c2d3541a1a5a092a6def..a59faa27912a6d478256f9b04ffcbec3aa587aa9 100644 (file)
@@ -100,56 +100,56 @@ static int vp7045_power_ctrl(struct dvb_usb_device *d, int onoff)
 /* The keymapping struct. Somehow this should be loaded to the driver, but
  * currently it is hardcoded. */
 static struct dvb_usb_rc_key vp7045_rc_keys[] = {
-       { 0x00, 0x16, KEY_POWER },
-       { 0x00, 0x10, KEY_MUTE },
-       { 0x00, 0x03, KEY_1 },
-       { 0x00, 0x01, KEY_2 },
-       { 0x00, 0x06, KEY_3 },
-       { 0x00, 0x09, KEY_4 },
-       { 0x00, 0x1d, KEY_5 },
-       { 0x00, 0x1f, KEY_6 },
-       { 0x00, 0x0d, KEY_7 },
-       { 0x00, 0x19, KEY_8 },
-       { 0x00, 0x1b, KEY_9 },
-       { 0x00, 0x15, KEY_0 },
-       { 0x00, 0x05, KEY_CHANNELUP },
-       { 0x00, 0x02, KEY_CHANNELDOWN },
-       { 0x00, 0x1e, KEY_VOLUMEUP },
-       { 0x00, 0x0a, KEY_VOLUMEDOWN },
-       { 0x00, 0x11, KEY_RECORD },
-       { 0x00, 0x17, KEY_FAVORITES }, /* Heart symbol - Channel list. */
-       { 0x00, 0x14, KEY_PLAY },
-       { 0x00, 0x1a, KEY_STOP },
-       { 0x00, 0x40, KEY_REWIND },
-       { 0x00, 0x12, KEY_FASTFORWARD },
-       { 0x00, 0x0e, KEY_PREVIOUS }, /* Recall - Previous channel. */
-       { 0x00, 0x4c, KEY_PAUSE },
-       { 0x00, 0x4d, KEY_SCREEN }, /* Full screen mode. */
-       { 0x00, 0x54, KEY_AUDIO }, /* MTS - Switch to secondary audio. */
-       { 0x00, 0x0c, KEY_CANCEL }, /* Cancel */
-       { 0x00, 0x1c, KEY_EPG }, /* EPG */
-       { 0x00, 0x00, KEY_TAB }, /* Tab */
-       { 0x00, 0x48, KEY_INFO }, /* Preview */
-       { 0x00, 0x04, KEY_LIST }, /* RecordList */
-       { 0x00, 0x0f, KEY_TEXT }, /* Teletext */
-       { 0x00, 0x41, KEY_PREVIOUSSONG },
-       { 0x00, 0x42, KEY_NEXTSONG },
-       { 0x00, 0x4b, KEY_UP },
-       { 0x00, 0x51, KEY_DOWN },
-       { 0x00, 0x4e, KEY_LEFT },
-       { 0x00, 0x52, KEY_RIGHT },
-       { 0x00, 0x4f, KEY_ENTER },
-       { 0x00, 0x13, KEY_CANCEL },
-       { 0x00, 0x4a, KEY_CLEAR },
-       { 0x00, 0x54, KEY_PRINT }, /* Capture */
-       { 0x00, 0x43, KEY_SUBTITLE }, /* Subtitle/CC */
-       { 0x00, 0x08, KEY_VIDEO }, /* A/V */
-       { 0x00, 0x07, KEY_SLEEP }, /* Hibernate */
-       { 0x00, 0x45, KEY_ZOOM }, /* Zoom+ */
-       { 0x00, 0x18, KEY_RED},
-       { 0x00, 0x53, KEY_GREEN},
-       { 0x00, 0x5e, KEY_YELLOW},
-       { 0x00, 0x5f, KEY_BLUE}
+       { 0x0016, KEY_POWER },
+       { 0x0010, KEY_MUTE },
+       { 0x0003, KEY_1 },
+       { 0x0001, KEY_2 },
+       { 0x0006, KEY_3 },
+       { 0x0009, KEY_4 },
+       { 0x001d, KEY_5 },
+       { 0x001f, KEY_6 },
+       { 0x000d, KEY_7 },
+       { 0x0019, KEY_8 },
+       { 0x001b, KEY_9 },
+       { 0x0015, KEY_0 },
+       { 0x0005, KEY_CHANNELUP },
+       { 0x0002, KEY_CHANNELDOWN },
+       { 0x001e, KEY_VOLUMEUP },
+       { 0x000a, KEY_VOLUMEDOWN },
+       { 0x0011, KEY_RECORD },
+       { 0x0017, KEY_FAVORITES }, /* Heart symbol - Channel list. */
+       { 0x0014, KEY_PLAY },
+       { 0x001a, KEY_STOP },
+       { 0x0040, KEY_REWIND },
+       { 0x0012, KEY_FASTFORWARD },
+       { 0x000e, KEY_PREVIOUS }, /* Recall - Previous channel. */
+       { 0x004c, KEY_PAUSE },
+       { 0x004d, KEY_SCREEN }, /* Full screen mode. */
+       { 0x0054, KEY_AUDIO }, /* MTS - Switch to secondary audio. */
+       { 0x000c, KEY_CANCEL }, /* Cancel */
+       { 0x001c, KEY_EPG }, /* EPG */
+       { 0x0000, KEY_TAB }, /* Tab */
+       { 0x0048, KEY_INFO }, /* Preview */
+       { 0x0004, KEY_LIST }, /* RecordList */
+       { 0x000f, KEY_TEXT }, /* Teletext */
+       { 0x0041, KEY_PREVIOUSSONG },
+       { 0x0042, KEY_NEXTSONG },
+       { 0x004b, KEY_UP },
+       { 0x0051, KEY_DOWN },
+       { 0x004e, KEY_LEFT },
+       { 0x0052, KEY_RIGHT },
+       { 0x004f, KEY_ENTER },
+       { 0x0013, KEY_CANCEL },
+       { 0x004a, KEY_CLEAR },
+       { 0x0054, KEY_PRINT }, /* Capture */
+       { 0x0043, KEY_SUBTITLE }, /* Subtitle/CC */
+       { 0x0008, KEY_VIDEO }, /* A/V */
+       { 0x0007, KEY_SLEEP }, /* Hibernate */
+       { 0x0045, KEY_ZOOM }, /* Zoom+ */
+       { 0x0018, KEY_RED},
+       { 0x0053, KEY_GREEN},
+       { 0x005e, KEY_YELLOW},
+       { 0x005f, KEY_BLUE}
 };
 
 static int vp7045_rc_query(struct dvb_usb_device *d, u32 *event, int *state)
@@ -166,7 +166,7 @@ static int vp7045_rc_query(struct dvb_usb_device *d, u32 *event, int *state)
        }
 
        for (i = 0; i < ARRAY_SIZE(vp7045_rc_keys); i++)
-               if (vp7045_rc_keys[i].data == key) {
+               if (rc5_data(&vp7045_rc_keys[i]) == key) {
                        *state = REMOTE_KEY_PRESSED;
                        *event = vp7045_rc_keys[i].event;
                        break;
index 32526f103b596290232de5ea652b363074935f21..d1b67fe0f011ba44cbd25f852e018ec16da4a772 100644 (file)
@@ -89,15 +89,33 @@ struct avc_response_frame {
        u8 operand[509];
 };
 
-#define AVC_DEBUG_FCP_SUBACTIONS       1
-#define AVC_DEBUG_FCP_PAYLOADS         2
+#define AVC_DEBUG_READ_DESCRIPTOR              0x0001
+#define AVC_DEBUG_DSIT                         0x0002
+#define AVC_DEBUG_DSD                          0x0004
+#define AVC_DEBUG_REGISTER_REMOTE_CONTROL      0x0008
+#define AVC_DEBUG_LNB_CONTROL                  0x0010
+#define AVC_DEBUG_TUNE_QPSK                    0x0020
+#define AVC_DEBUG_TUNE_QPSK2                   0x0040
+#define AVC_DEBUG_HOST2CA                      0x0080
+#define AVC_DEBUG_CA2HOST                      0x0100
+#define AVC_DEBUG_APPLICATION_PMT              0x4000
+#define AVC_DEBUG_FCP_PAYLOADS                 0x8000
 
 static int avc_debug;
 module_param_named(debug, avc_debug, int, 0644);
-MODULE_PARM_DESC(debug, "Verbose logging (default = 0"
-       ", FCP subactions = "   __stringify(AVC_DEBUG_FCP_SUBACTIONS)
-       ", FCP payloads = "     __stringify(AVC_DEBUG_FCP_PAYLOADS)
-       ", or all = -1)");
+MODULE_PARM_DESC(debug, "Verbose logging (none = 0"
+       ", FCP subactions"
+       ": READ DESCRIPTOR = "          __stringify(AVC_DEBUG_READ_DESCRIPTOR)
+       ", DSIT = "                     __stringify(AVC_DEBUG_DSIT)
+       ", REGISTER_REMOTE_CONTROL = "  __stringify(AVC_DEBUG_REGISTER_REMOTE_CONTROL)
+       ", LNB CONTROL = "              __stringify(AVC_DEBUG_LNB_CONTROL)
+       ", TUNE QPSK = "                __stringify(AVC_DEBUG_TUNE_QPSK)
+       ", TUNE QPSK2 = "               __stringify(AVC_DEBUG_TUNE_QPSK2)
+       ", HOST2CA = "                  __stringify(AVC_DEBUG_HOST2CA)
+       ", CA2HOST = "                  __stringify(AVC_DEBUG_CA2HOST)
+       "; Application sent PMT = "     __stringify(AVC_DEBUG_APPLICATION_PMT)
+       ", FCP payloads = "             __stringify(AVC_DEBUG_FCP_PAYLOADS)
+       ", or a combination, or all = -1)");
 
 static const char *debug_fcp_ctype(unsigned int ctype)
 {
@@ -118,48 +136,70 @@ static const char *debug_fcp_opcode(unsigned int opcode,
                                    const u8 *data, int length)
 {
        switch (opcode) {
-       case AVC_OPCODE_VENDOR:                 break;
-       case AVC_OPCODE_READ_DESCRIPTOR:        return "ReadDescriptor";
-       case AVC_OPCODE_DSIT:                   return "DirectSelectInfo.Type";
-       case AVC_OPCODE_DSD:                    return "DirectSelectData";
-       default:                                return "?";
+       case AVC_OPCODE_VENDOR:
+               break;
+       case AVC_OPCODE_READ_DESCRIPTOR:
+               return avc_debug & AVC_DEBUG_READ_DESCRIPTOR ?
+                               "ReadDescriptor" : NULL;
+       case AVC_OPCODE_DSIT:
+               return avc_debug & AVC_DEBUG_DSIT ?
+                               "DirectSelectInfo.Type" : NULL;
+       case AVC_OPCODE_DSD:
+               return avc_debug & AVC_DEBUG_DSD ? "DirectSelectData" : NULL;
+       default:
+               return "Unknown";
        }
 
        if (length < 7 ||
            data[3] != SFE_VENDOR_DE_COMPANYID_0 ||
            data[4] != SFE_VENDOR_DE_COMPANYID_1 ||
            data[5] != SFE_VENDOR_DE_COMPANYID_2)
-               return "Vendor";
+               return "Vendor/Unknown";
 
        switch (data[6]) {
-       case SFE_VENDOR_OPCODE_REGISTER_REMOTE_CONTROL: return "RegisterRC";
-       case SFE_VENDOR_OPCODE_LNB_CONTROL:             return "LNBControl";
-       case SFE_VENDOR_OPCODE_TUNE_QPSK:               return "TuneQPSK";
-       case SFE_VENDOR_OPCODE_TUNE_QPSK2:              return "TuneQPSK2";
-       case SFE_VENDOR_OPCODE_HOST2CA:                 return "Host2CA";
-       case SFE_VENDOR_OPCODE_CA2HOST:                 return "CA2Host";
+       case SFE_VENDOR_OPCODE_REGISTER_REMOTE_CONTROL:
+               return avc_debug & AVC_DEBUG_REGISTER_REMOTE_CONTROL ?
+                               "RegisterRC" : NULL;
+       case SFE_VENDOR_OPCODE_LNB_CONTROL:
+               return avc_debug & AVC_DEBUG_LNB_CONTROL ? "LNBControl" : NULL;
+       case SFE_VENDOR_OPCODE_TUNE_QPSK:
+               return avc_debug & AVC_DEBUG_TUNE_QPSK ? "TuneQPSK" : NULL;
+       case SFE_VENDOR_OPCODE_TUNE_QPSK2:
+               return avc_debug & AVC_DEBUG_TUNE_QPSK2 ? "TuneQPSK2" : NULL;
+       case SFE_VENDOR_OPCODE_HOST2CA:
+               return avc_debug & AVC_DEBUG_HOST2CA ? "Host2CA" : NULL;
+       case SFE_VENDOR_OPCODE_CA2HOST:
+               return avc_debug & AVC_DEBUG_CA2HOST ? "CA2Host" : NULL;
        }
-       return "Vendor";
+       return "Vendor/Unknown";
 }
 
 static void debug_fcp(const u8 *data, int length)
 {
-       unsigned int subunit_type, subunit_id, op;
-       const char *prefix = data[0] > 7 ? "FCP <- " : "FCP -> ";
+       unsigned int subunit_type, subunit_id, opcode;
+       const char *op, *prefix;
+
+       prefix       = data[0] > 7 ? "FCP <- " : "FCP -> ";
+       subunit_type = data[1] >> 3;
+       subunit_id   = data[1] & 7;
+       opcode       = subunit_type == 0x1e || subunit_id == 5 ? ~0 : data[2];
+       op           = debug_fcp_opcode(opcode, data, length);
 
-       if (avc_debug & AVC_DEBUG_FCP_SUBACTIONS) {
-               subunit_type = data[1] >> 3;
-               subunit_id = data[1] & 7;
-               op = subunit_type == 0x1e || subunit_id == 5 ? ~0 : data[2];
+       if (op) {
                printk(KERN_INFO "%ssu=%x.%x l=%d: %-8s - %s\n",
                       prefix, subunit_type, subunit_id, length,
-                      debug_fcp_ctype(data[0]),
-                      debug_fcp_opcode(op, data, length));
+                      debug_fcp_ctype(data[0]), op);
+               if (avc_debug & AVC_DEBUG_FCP_PAYLOADS)
+                       print_hex_dump(KERN_INFO, prefix, DUMP_PREFIX_NONE,
+                                      16, 1, data, length, false);
        }
+}
 
-       if (avc_debug & AVC_DEBUG_FCP_PAYLOADS)
-               print_hex_dump(KERN_INFO, prefix, DUMP_PREFIX_NONE, 16, 1,
-                              data, length, false);
+static void debug_pmt(char *msg, int length)
+{
+       printk(KERN_INFO "APP PMT -> l=%d\n", length);
+       print_hex_dump(KERN_INFO, "APP PMT -> ", DUMP_PREFIX_NONE,
+                      16, 1, msg, length, false);
 }
 
 static int __avc_write(struct firedtv *fdtv,
@@ -254,6 +294,26 @@ int avc_recv(struct firedtv *fdtv, void *data, size_t length)
        return 0;
 }
 
+static int add_pid_filter(struct firedtv *fdtv, u8 *operand)
+{
+       int i, n, pos = 1;
+
+       for (i = 0, n = 0; i < 16; i++) {
+               if (test_bit(i, &fdtv->channel_active)) {
+                       operand[pos++] = 0x13; /* flowfunction relay */
+                       operand[pos++] = 0x80; /* dsd_sel_spec_valid_flags -> PID */
+                       operand[pos++] = (fdtv->channel_pid[i] >> 8) & 0x1f;
+                       operand[pos++] = fdtv->channel_pid[i] & 0xff;
+                       operand[pos++] = 0x00; /* tableID */
+                       operand[pos++] = 0x00; /* filter_length */
+                       n++;
+               }
+       }
+       operand[0] = n;
+
+       return pos;
+}
+
 /*
  * tuning command for setting the relative LNB frequency
  * (not supported by the AVC standard)
@@ -316,7 +376,8 @@ static void avc_tuner_tuneqpsk(struct firedtv *fdtv,
        }
 }
 
-static void avc_tuner_dsd_dvb_c(struct dvb_frontend_parameters *params,
+static void avc_tuner_dsd_dvb_c(struct firedtv *fdtv,
+                               struct dvb_frontend_parameters *params,
                                struct avc_command_frame *c)
 {
        c->opcode = AVC_OPCODE_DSD;
@@ -378,13 +439,13 @@ static void avc_tuner_dsd_dvb_c(struct dvb_frontend_parameters *params,
 
        c->operand[20] = 0x00;
        c->operand[21] = 0x00;
-       /* Nr_of_dsd_sel_specs = 0 -> no PIDs are transmitted */
-       c->operand[22] = 0x00;
 
-       c->length = 28;
+       /* Add PIDs to filter */
+       c->length = ALIGN(22 + add_pid_filter(fdtv, &c->operand[22]) + 3, 4);
 }
 
-static void avc_tuner_dsd_dvb_t(struct dvb_frontend_parameters *params,
+static void avc_tuner_dsd_dvb_t(struct firedtv *fdtv,
+                               struct dvb_frontend_parameters *params,
                                struct avc_command_frame *c)
 {
        struct dvb_ofdm_parameters *ofdm = &params->u.ofdm;
@@ -481,10 +542,9 @@ static void avc_tuner_dsd_dvb_t(struct dvb_frontend_parameters *params,
 
        c->operand[15] = 0x00; /* network_ID[0] */
        c->operand[16] = 0x00; /* network_ID[1] */
-       /* Nr_of_dsd_sel_specs = 0 -> no PIDs are transmitted */
-       c->operand[17] = 0x00;
 
-       c->length = 24;
+       /* Add PIDs to filter */
+       c->length = ALIGN(17 + add_pid_filter(fdtv, &c->operand[17]) + 3, 4);
 }
 
 int avc_tuner_dsd(struct firedtv *fdtv,
@@ -502,8 +562,8 @@ int avc_tuner_dsd(struct firedtv *fdtv,
        switch (fdtv->type) {
        case FIREDTV_DVB_S:
        case FIREDTV_DVB_S2: avc_tuner_tuneqpsk(fdtv, params, c); break;
-       case FIREDTV_DVB_C: avc_tuner_dsd_dvb_c(params, c); break;
-       case FIREDTV_DVB_T: avc_tuner_dsd_dvb_t(params, c); break;
+       case FIREDTV_DVB_C: avc_tuner_dsd_dvb_c(fdtv, params, c); break;
+       case FIREDTV_DVB_T: avc_tuner_dsd_dvb_t(fdtv, params, c); break;
        default:
                BUG();
        }
@@ -963,6 +1023,9 @@ int avc_ca_pmt(struct firedtv *fdtv, char *msg, int length)
        int es_info_length;
        int crc32_csum;
 
+       if (unlikely(avc_debug & AVC_DEBUG_APPLICATION_PMT))
+               debug_pmt(msg, length);
+
        memset(c, 0, sizeof(*c));
 
        c->ctype   = AVC_CTYPE_CONTROL;
index be967ac09a3962e3f704a862998dfd43574d586d..b794e860b4e284c20756169fbdaa5dcc840ffe5f 100644 (file)
@@ -81,6 +81,13 @@ config DVB_ZL10036
        help
          A DVB-S tuner module. Say Y when you want to support this frontend.
 
+config DVB_ZL10039
+       tristate "Zarlink ZL10039 silicon tuner"
+       depends on DVB_CORE && I2C
+       default m if DVB_FE_CUSTOMISE
+       help
+         A DVB-S tuner module. Say Y when you want to support this frontend.
+
 config DVB_S5H1420
        tristate "Samsung S5H1420 based"
        depends on DVB_CORE && I2C
index 832473c1e512765feb454597c8fd55d19053b166..3b49d37ab5fa143a135f39f2d76d848ac44e670c 100644 (file)
@@ -31,6 +31,7 @@ obj-$(CONFIG_DVB_SP887X) += sp887x.o
 obj-$(CONFIG_DVB_NXT6000) += nxt6000.o
 obj-$(CONFIG_DVB_MT352) += mt352.o
 obj-$(CONFIG_DVB_ZL10036) += zl10036.o
+obj-$(CONFIG_DVB_ZL10039) += zl10039.o
 obj-$(CONFIG_DVB_ZL10353) += zl10353.o
 obj-$(CONFIG_DVB_CX22702) += cx22702.o
 obj-$(CONFIG_DVB_DRX397XD) += drx397xD.o
index fbd838eca268765e79268a3165f3fb34f9908a8d..5fbc0fc37ecd4785c41547216e9722ae8e69c5ab 100644 (file)
@@ -155,7 +155,7 @@ static int cx22700_set_tps (struct cx22700_state *state, struct dvb_ofdm_paramet
            p->hierarchy_information > HIERARCHY_4)
                return -EINVAL;
 
-       if (p->bandwidth < BANDWIDTH_8_MHZ && p->bandwidth > BANDWIDTH_6_MHZ)
+       if (p->bandwidth < BANDWIDTH_8_MHZ || p->bandwidth > BANDWIDTH_6_MHZ)
                return -EINVAL;
 
        if (p->bandwidth == BANDWIDTH_7_MHZ)
index e4fd533a427c43dd86c75b6acc667d10692204d4..075b2b57cf09f9a4fce00439ffa525b7d47a0124 100644 (file)
@@ -303,6 +303,7 @@ static void cx24113_calc_pll_nf(struct cx24113_state *state, u16 *n, s32 *f)
 {
        s32 N;
        s64 F;
+       u64 dividend;
        u8 R, r;
        u8 vcodiv;
        u8 factor;
@@ -346,7 +347,10 @@ static void cx24113_calc_pll_nf(struct cx24113_state *state, u16 *n, s32 *f)
        F = freq_hz;
        F *= (u64) (R * vcodiv * 262144);
        dprintk("1 N: %d, F: %lld, R: %d\n", N, (long long)F, R);
-       do_div(F, state->config->xtal_khz*1000 * factor * 2);
+       /* do_div needs an u64 as first argument */
+       dividend = F;
+       do_div(dividend, state->config->xtal_khz * 1000 * factor * 2);
+       F = dividend;
        dprintk("2 N: %d, F: %lld, R: %d\n", N, (long long)F, R);
        F -= (N + 32) * 262144;
 
index 0592f043ea64481228ffc9c26ae0c60929308ec3..d8f921b6fafdc330cbbc4e3e1486f04165858413 100644 (file)
@@ -458,7 +458,7 @@ static int cx24123_set_symbolrate(struct cx24123_state *state, u32 srate)
        /*  check if symbol rate is within limits */
        if ((srate > state->frontend.ops.info.symbol_rate_max) ||
            (srate < state->frontend.ops.info.symbol_rate_min))
-               return -EOPNOTSUPP;;
+               return -EOPNOTSUPP;
 
        /* choose the sampling rate high enough for the required operation,
           while optimizing the power consumed by the demodulator */
index fe895bf7b18fbc686a7d4114d2e506bbf3b9bbe6..da92cbe1b8ea4799c4ea56e876105b2027f361b4 100644 (file)
@@ -167,7 +167,7 @@ static int dib0070_tune_digital(struct dvb_frontend *fe, struct dvb_frontend_par
                                        break;
                                case BAND_SBAND:
                                        LO4_SET_VCO_HFDIV(lo4, 0, 0);
-                                       LO4_SET_CTRIM(lo4, 1);;
+                                       LO4_SET_CTRIM(lo4, 1);
                                        c = 1;
                                        break;
                                case BAND_UHF:
index 8217e5b38f47064e464942ff3b75fa3b8e8ce53c..fc96fbf03d6dc9d1bbf9cce827ac950184c6d1d5 100644 (file)
@@ -883,7 +883,7 @@ static void dib7000p_spur_protect(struct dib7000p_state *state, u32 rf_khz, u32
        255, 255, 255, 255, 255, 255};
 
        u32 xtal = state->cfg.bw->xtal_hz / 1000;
-       int f_rel = ( (rf_khz + xtal/2) / xtal) * xtal - rf_khz;
+       int f_rel = DIV_ROUND_CLOSEST(rf_khz, xtal) * xtal - rf_khz;
        int k;
        int coef_re[8],coef_im[8];
        int bw_khz = bw;
index 9f6349964cdafa53b49525b494e4c7066e4ed903..6d865d6161d78b33ffe05472de147bdf5360d06b 100644 (file)
@@ -389,6 +389,77 @@ static struct dvb_pll_desc dvb_pll_samsung_dtos403ih102a = {
        }
 };
 
+/* Samsung TDTC9251DH0 DVB-T NIM, as used on AirStar 2 */
+static struct dvb_pll_desc dvb_pll_samsung_tdtc9251dh0 = {
+       .name   = "Samsung TDTC9251DH0",
+       .min    =  48000000,
+       .max    = 863000000,
+       .iffreq =  36166667,
+       .count  = 3,
+       .entries = {
+               { 157500000, 166667, 0xcc, 0x09 },
+               { 443000000, 166667, 0xcc, 0x0a },
+               { 863000000, 166667, 0xcc, 0x08 },
+       }
+};
+
+/* Samsung TBDU18132 DVB-S NIM with TSA5059 PLL, used in SkyStar2 DVB-S 2.3 */
+static struct dvb_pll_desc dvb_pll_samsung_tbdu18132 = {
+       .name = "Samsung TBDU18132",
+       .min    =  950000,
+       .max    = 2150000, /* guesses */
+       .iffreq = 0,
+       .count = 2,
+       .entries = {
+               { 1550000, 125, 0x84, 0x82 },
+               { 4095937, 125, 0x84, 0x80 },
+       }
+       /* TSA5059 PLL has a 17 bit divisor rather than the 15 bits supported
+        * by this driver.  The two extra bits are 0x60 in the third byte.  15
+        * bits is enough for over 4 GHz, which is enough to cover the range
+        * of this tuner.  We could use the additional divisor bits by adding
+        * more entries, e.g.
+        { 0x0ffff * 125 + 125/2, 125, 0x84 | 0x20, },
+        { 0x17fff * 125 + 125/2, 125, 0x84 | 0x40, },
+        { 0x1ffff * 125 + 125/2, 125, 0x84 | 0x60, }, */
+};
+
+/* Samsung TBMU24112 DVB-S NIM with SL1935 zero-IF tuner */
+static struct dvb_pll_desc dvb_pll_samsung_tbmu24112 = {
+       .name = "Samsung TBMU24112",
+       .min    =  950000,
+       .max    = 2150000, /* guesses */
+       .iffreq = 0,
+       .count = 2,
+       .entries = {
+               { 1500000, 125, 0x84, 0x18 },
+               { 9999999, 125, 0x84, 0x08 },
+       }
+};
+
+/* Alps TDEE4 DVB-C NIM, used on Cablestar 2 */
+/* byte 4 : 1  *   *   AGD R3  R2  R1  R0
+ * byte 5 : C1 *   RE  RTS BS4 BS3 BS2 BS1
+ * AGD = 1, R3 R2 R1 R0 = 0 1 0 1 => byte 4 = 1**10101 = 0x95
+ * Range(MHz)  C1 *  RE RTS BS4 BS3 BS2 BS1  Byte 5
+ *  47 - 153   0  *  0   0   0   0   0   1   0x01
+ * 153 - 430   0  *  0   0   0   0   1   0   0x02
+ * 430 - 822   0  *  0   0   1   0   0   0   0x08
+ * 822 - 862   1  *  0   0   1   0   0   0   0x88 */
+static struct dvb_pll_desc dvb_pll_alps_tdee4 = {
+       .name = "ALPS TDEE4",
+       .min    =  47000000,
+       .max    = 862000000,
+       .iffreq =  36125000,
+       .count = 4,
+       .entries = {
+               { 153000000, 62500, 0x95, 0x01 },
+               { 430000000, 62500, 0x95, 0x02 },
+               { 822000000, 62500, 0x95, 0x08 },
+               { 999999999, 62500, 0x95, 0x88 },
+       }
+};
+
 /* ----------------------------------------------------------- */
 
 static struct dvb_pll_desc *pll_list[] = {
@@ -402,11 +473,15 @@ static struct dvb_pll_desc *pll_list[] = {
        [DVB_PLL_TUA6034]                = &dvb_pll_tua6034,
        [DVB_PLL_TDA665X]                = &dvb_pll_tda665x,
        [DVB_PLL_TDED4]                  = &dvb_pll_tded4,
+       [DVB_PLL_TDEE4]                  = &dvb_pll_alps_tdee4,
        [DVB_PLL_TDHU2]                  = &dvb_pll_tdhu2,
        [DVB_PLL_SAMSUNG_TBMV]           = &dvb_pll_samsung_tbmv,
        [DVB_PLL_PHILIPS_SD1878_TDA8261] = &dvb_pll_philips_sd1878_tda8261,
        [DVB_PLL_OPERA1]                 = &dvb_pll_opera1,
        [DVB_PLL_SAMSUNG_DTOS403IH102A]  = &dvb_pll_samsung_dtos403ih102a,
+       [DVB_PLL_SAMSUNG_TDTC9251DH0]    = &dvb_pll_samsung_tdtc9251dh0,
+       [DVB_PLL_SAMSUNG_TBDU18132]      = &dvb_pll_samsung_tbdu18132,
+       [DVB_PLL_SAMSUNG_TBMU24112]      = &dvb_pll_samsung_tbmu24112,
 };
 
 /* ----------------------------------------------------------- */
index 05239f579ccfc007e10ac95fdcf53203a61dc7bc..086964344c38bd180d0fe6f798d918f48d7edada 100644 (file)
 #define DVB_PLL_PHILIPS_SD1878_TDA8261 12
 #define DVB_PLL_OPERA1                 13
 #define DVB_PLL_SAMSUNG_DTOS403IH102A  14
+#define DVB_PLL_SAMSUNG_TDTC9251DH0    15
+#define DVB_PLL_SAMSUNG_TBDU18132      16
+#define DVB_PLL_SAMSUNG_TBMU24112      17
+#define DVB_PLL_TDEE4                 18
 
 /**
  * Attach a dvb-pll to the supplied frontend structure.
index fde27645bbed67918aca946c1f551dee7a961cea..eabcadc425d5297a772a772c5f19a6d9983d4dff 100644 (file)
@@ -1,9 +1,9 @@
 /*
- *    Support for Legend Silicon DMB-TH demodulator
- *    LGS8913, LGS8GL5
+ *    Support for Legend Silicon GB20600 (a.k.a DMB-TH) demodulator
+ *    LGS8913, LGS8GL5, LGS8G75
  *    experimental support LGS8G42, LGS8G52
  *
- *    Copyright (C) 2007,2008 David T.L. Wong <davidtlwong@gmail.com>
+ *    Copyright (C) 2007-2009 David T.L. Wong <davidtlwong@gmail.com>
  *    Copyright (C) 2008 Sirius International (Hong Kong) Limited
  *    Timothy Lee <timothy.lee@siriushk.com> (for initial work on LGS8GL5)
  *
@@ -46,6 +46,42 @@ module_param(fake_signal_str, int, 0644);
 MODULE_PARM_DESC(fake_signal_str, "fake signal strength for LGS8913."
 "Signal strength calculation is slow.(default:on).");
 
+static const u8 lgs8g75_initdat[] = {
+       0x01, 0x30, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+       0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+       0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+       0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+       0x00, 0x01, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+       0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+       0xE4, 0xF5, 0xA8, 0xF5, 0xB8, 0xF5, 0x88, 0xF5,
+       0x89, 0xF5, 0x87, 0x75, 0xD0, 0x00, 0x11, 0x50,
+       0x11, 0x50, 0xF4, 0xF5, 0x80, 0xF5, 0x90, 0xF5,
+       0xA0, 0xF5, 0xB0, 0x75, 0x81, 0x30, 0x80, 0x01,
+       0x32, 0x90, 0x80, 0x12, 0x74, 0xFF, 0xF0, 0x90,
+       0x80, 0x13, 0x74, 0x1F, 0xF0, 0x90, 0x80, 0x23,
+       0x74, 0x01, 0xF0, 0x90, 0x80, 0x22, 0xF0, 0x90,
+       0x00, 0x48, 0x74, 0x00, 0xF0, 0x90, 0x80, 0x4D,
+       0x74, 0x05, 0xF0, 0x90, 0x80, 0x09, 0xE0, 0x60,
+       0x21, 0x12, 0x00, 0xDD, 0x14, 0x60, 0x1B, 0x12,
+       0x00, 0xDD, 0x14, 0x60, 0x15, 0x12, 0x00, 0xDD,
+       0x14, 0x60, 0x0F, 0x12, 0x00, 0xDD, 0x14, 0x60,
+       0x09, 0x12, 0x00, 0xDD, 0x14, 0x60, 0x03, 0x12,
+       0x00, 0xDD, 0x90, 0x80, 0x42, 0xE0, 0x60, 0x0B,
+       0x14, 0x60, 0x0C, 0x14, 0x60, 0x0D, 0x14, 0x60,
+       0x0E, 0x01, 0xB3, 0x74, 0x04, 0x01, 0xB9, 0x74,
+       0x05, 0x01, 0xB9, 0x74, 0x07, 0x01, 0xB9, 0x74,
+       0x0A, 0xC0, 0xE0, 0x74, 0xC8, 0x12, 0x00, 0xE2,
+       0xD0, 0xE0, 0x14, 0x70, 0xF4, 0x90, 0x80, 0x09,
+       0xE0, 0x70, 0xAE, 0x12, 0x00, 0xF6, 0x12, 0x00,
+       0xFE, 0x90, 0x00, 0x48, 0xE0, 0x04, 0xF0, 0x90,
+       0x80, 0x4E, 0xF0, 0x01, 0x73, 0x90, 0x80, 0x08,
+       0xF0, 0x22, 0xF8, 0x7A, 0x0C, 0x79, 0xFD, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xD9,
+       0xF6, 0xDA, 0xF2, 0xD8, 0xEE, 0x22, 0x90, 0x80,
+       0x65, 0xE0, 0x54, 0xFD, 0xF0, 0x22, 0x90, 0x80,
+       0x65, 0xE0, 0x44, 0xC2, 0xF0, 0x22
+};
+
 /* LGS8GXX internal helper functions */
 
 static int lgs8gxx_write_reg(struct lgs8gxx_state *priv, u8 reg, u8 data)
@@ -55,7 +91,7 @@ static int lgs8gxx_write_reg(struct lgs8gxx_state *priv, u8 reg, u8 data)
        struct i2c_msg msg = { .flags = 0, .buf = buf, .len = 2 };
 
        msg.addr = priv->config->demod_address;
-       if (reg >= 0xC0)
+       if (priv->config->prod != LGS8GXX_PROD_LGS8G75 && reg >= 0xC0)
                msg.addr += 0x02;
 
        if (debug >= 2)
@@ -84,7 +120,7 @@ static int lgs8gxx_read_reg(struct lgs8gxx_state *priv, u8 reg, u8 *p_data)
        };
 
        dev_addr = priv->config->demod_address;
-       if (reg >= 0xC0)
+       if (priv->config->prod != LGS8GXX_PROD_LGS8G75 && reg >= 0xC0)
                dev_addr += 0x02;
        msg[1].addr =  msg[0].addr = dev_addr;
 
@@ -112,19 +148,36 @@ static int lgs8gxx_soft_reset(struct lgs8gxx_state *priv)
        return 0;
 }
 
+static int wait_reg_mask(struct lgs8gxx_state *priv, u8 reg, u8 mask,
+       u8 val, u8 delay, u8 tries)
+{
+       u8 t;
+       int i;
+
+       for (i = 0; i < tries; i++) {
+               lgs8gxx_read_reg(priv, reg, &t);
+
+               if ((t & mask) == val)
+                       return 0;
+               msleep(delay);
+       }
+
+       return 1;
+}
+
 static int lgs8gxx_set_ad_mode(struct lgs8gxx_state *priv)
 {
        const struct lgs8gxx_config *config = priv->config;
        u8 if_conf;
 
-       if_conf = 0x10; /* AGC output on; */
+       if_conf = 0x10; /* AGC output on, RF_AGC output off; */
 
        if_conf |=
                ((config->ext_adc) ? 0x80 : 0x00) |
                ((config->if_neg_center) ? 0x04 : 0x00) |
                ((config->if_freq == 0) ? 0x08 : 0x00) | /* Baseband */
-               ((config->ext_adc && config->adc_signed) ? 0x02 : 0x00) |
-               ((config->ext_adc && config->if_neg_edge) ? 0x01 : 0x00);
+               ((config->adc_signed) ? 0x02 : 0x00) |
+               ((config->if_neg_edge) ? 0x01 : 0x00);
 
        if (config->ext_adc &&
                (config->prod == LGS8GXX_PROD_LGS8G52)) {
@@ -157,39 +210,82 @@ static int lgs8gxx_set_if_freq(struct lgs8gxx_state *priv, u32 freq /*in kHz*/)
        }
        dprintk("AFC_INIT_FREQ = 0x%08X\n", v32);
 
-       lgs8gxx_write_reg(priv, 0x09, 0xFF & (v32));
-       lgs8gxx_write_reg(priv, 0x0A, 0xFF & (v32 >> 8));
-       lgs8gxx_write_reg(priv, 0x0B, 0xFF & (v32 >> 16));
-       lgs8gxx_write_reg(priv, 0x0C, 0xFF & (v32 >> 24));
+       if (priv->config->prod == LGS8GXX_PROD_LGS8G75) {
+               lgs8gxx_write_reg(priv, 0x08, 0xFF & (v32));
+               lgs8gxx_write_reg(priv, 0x09, 0xFF & (v32 >> 8));
+               lgs8gxx_write_reg(priv, 0x0A, 0xFF & (v32 >> 16));
+               lgs8gxx_write_reg(priv, 0x0B, 0xFF & (v32 >> 24));
+       } else {
+               lgs8gxx_write_reg(priv, 0x09, 0xFF & (v32));
+               lgs8gxx_write_reg(priv, 0x0A, 0xFF & (v32 >> 8));
+               lgs8gxx_write_reg(priv, 0x0B, 0xFF & (v32 >> 16));
+               lgs8gxx_write_reg(priv, 0x0C, 0xFF & (v32 >> 24));
+       }
+
+       return 0;
+}
+
+static int lgs8gxx_get_afc_phase(struct lgs8gxx_state *priv)
+{
+       u64 val;
+       u32 v32 = 0;
+       u8 reg_addr, t;
+       int i;
+
+       if (priv->config->prod == LGS8GXX_PROD_LGS8G75)
+               reg_addr = 0x23;
+       else
+               reg_addr = 0x48;
+
+       for (i = 0; i < 4; i++) {
+               lgs8gxx_read_reg(priv, reg_addr, &t);
+               v32 <<= 8;
+               v32 |= t;
+               reg_addr--;
+       }
 
+       val = v32;
+       val *= priv->config->if_clk_freq;
+       val /= (u64)1 << 32;
+       dprintk("AFC = %u kHz\n", (u32)val);
        return 0;
 }
 
 static int lgs8gxx_set_mode_auto(struct lgs8gxx_state *priv)
 {
        u8 t;
+       u8 prod = priv->config->prod;
 
-       if (priv->config->prod == LGS8GXX_PROD_LGS8913)
+       if (prod == LGS8GXX_PROD_LGS8913)
                lgs8gxx_write_reg(priv, 0xC6, 0x01);
 
-       lgs8gxx_read_reg(priv, 0x7E, &t);
-       lgs8gxx_write_reg(priv, 0x7E, t | 0x01);
-
-       /* clear FEC self reset */
-       lgs8gxx_read_reg(priv, 0xC5, &t);
-       lgs8gxx_write_reg(priv, 0xC5, t & 0xE0);
+       if (prod == LGS8GXX_PROD_LGS8G75) {
+               lgs8gxx_read_reg(priv, 0x0C, &t);
+               t &= (~0x04);
+               lgs8gxx_write_reg(priv, 0x0C, t | 0x80);
+               lgs8gxx_write_reg(priv, 0x39, 0x00);
+               lgs8gxx_write_reg(priv, 0x3D, 0x04);
+       } else if (prod == LGS8GXX_PROD_LGS8913 ||
+               prod == LGS8GXX_PROD_LGS8GL5 ||
+               prod == LGS8GXX_PROD_LGS8G42 ||
+               prod == LGS8GXX_PROD_LGS8G52 ||
+               prod == LGS8GXX_PROD_LGS8G54) {
+               lgs8gxx_read_reg(priv, 0x7E, &t);
+               lgs8gxx_write_reg(priv, 0x7E, t | 0x01);
+
+               /* clear FEC self reset */
+               lgs8gxx_read_reg(priv, 0xC5, &t);
+               lgs8gxx_write_reg(priv, 0xC5, t & 0xE0);
+       }
 
-       if (priv->config->prod == LGS8GXX_PROD_LGS8913) {
+       if (prod == LGS8GXX_PROD_LGS8913) {
                /* FEC auto detect */
                lgs8gxx_write_reg(priv, 0xC1, 0x03);
 
                lgs8gxx_read_reg(priv, 0x7C, &t);
                t = (t & 0x8C) | 0x03;
                lgs8gxx_write_reg(priv, 0x7C, t);
-       }
-
 
-       if (priv->config->prod == LGS8GXX_PROD_LGS8913) {
                /* BER test mode */
                lgs8gxx_read_reg(priv, 0xC3, &t);
                t = (t & 0xEF) |  0x10;
@@ -207,6 +303,32 @@ static int lgs8gxx_set_mode_manual(struct lgs8gxx_state *priv)
        int ret = 0;
        u8 t;
 
+       if (priv->config->prod == LGS8GXX_PROD_LGS8G75) {
+               u8 t2;
+               lgs8gxx_read_reg(priv, 0x0C, &t);
+               t &= (~0x80);
+               lgs8gxx_write_reg(priv, 0x0C, t);
+
+               lgs8gxx_read_reg(priv, 0x0C, &t);
+               lgs8gxx_read_reg(priv, 0x19, &t2);
+
+               if (((t&0x03) == 0x01) && (t2&0x01)) {
+                       lgs8gxx_write_reg(priv, 0x6E, 0x05);
+                       lgs8gxx_write_reg(priv, 0x39, 0x02);
+                       lgs8gxx_write_reg(priv, 0x39, 0x03);
+                       lgs8gxx_write_reg(priv, 0x3D, 0x05);
+                       lgs8gxx_write_reg(priv, 0x3E, 0x28);
+                       lgs8gxx_write_reg(priv, 0x53, 0x80);
+               } else {
+                       lgs8gxx_write_reg(priv, 0x6E, 0x3F);
+                       lgs8gxx_write_reg(priv, 0x39, 0x00);
+                       lgs8gxx_write_reg(priv, 0x3D, 0x04);
+               }
+
+               lgs8gxx_soft_reset(priv);
+               return 0;
+       }
+
        /* turn off auto-detect; manual settings */
        lgs8gxx_write_reg(priv, 0x7E, 0);
        if (priv->config->prod == LGS8GXX_PROD_LGS8913)
@@ -226,11 +348,39 @@ static int lgs8gxx_is_locked(struct lgs8gxx_state *priv, u8 *locked)
        int ret = 0;
        u8 t;
 
-       ret = lgs8gxx_read_reg(priv, 0x4B, &t);
+       if (priv->config->prod == LGS8GXX_PROD_LGS8G75)
+               ret = lgs8gxx_read_reg(priv, 0x13, &t);
+       else
+               ret = lgs8gxx_read_reg(priv, 0x4B, &t);
        if (ret != 0)
                return ret;
 
-       *locked = ((t & 0xC0) == 0xC0) ? 1 : 0;
+       if (priv->config->prod == LGS8GXX_PROD_LGS8G75)
+               *locked = ((t & 0x80) == 0x80) ? 1 : 0;
+       else
+               *locked = ((t & 0xC0) == 0xC0) ? 1 : 0;
+       return 0;
+}
+
+/* Wait for Code Acquisition Lock */
+static int lgs8gxx_wait_ca_lock(struct lgs8gxx_state *priv, u8 *locked)
+{
+       int ret = 0;
+       u8 reg, mask, val;
+
+       if (priv->config->prod == LGS8GXX_PROD_LGS8G75) {
+               reg = 0x13;
+               mask = 0x80;
+               val = 0x80;
+       } else {
+               reg = 0x4B;
+               mask = 0xC0;
+               val = 0xC0;
+       }
+
+       ret = wait_reg_mask(priv, reg, mask, val, 50, 40);
+       *locked = (ret == 0) ? 1 : 0;
+
        return 0;
 }
 
@@ -238,21 +388,30 @@ static int lgs8gxx_is_autodetect_finished(struct lgs8gxx_state *priv,
                                          u8 *finished)
 {
        int ret = 0;
-       u8 t;
+       u8 reg, mask, val;
 
-       ret = lgs8gxx_read_reg(priv, 0xA4, &t);
-       if (ret != 0)
-               return ret;
+       if (priv->config->prod == LGS8GXX_PROD_LGS8G75) {
+               reg = 0x1f;
+               mask = 0xC0;
+               val = 0x80;
+       } else {
+               reg = 0xA4;
+               mask = 0x03;
+               val = 0x01;
+       }
 
-       *finished = ((t & 0x3) == 0x1) ? 1 : 0;
+       ret = wait_reg_mask(priv, reg, mask, val, 10, 20);
+       *finished = (ret == 0) ? 1 : 0;
 
        return 0;
 }
 
-static int lgs8gxx_autolock_gi(struct lgs8gxx_state *priv, u8 gi, u8 *locked)
+static int lgs8gxx_autolock_gi(struct lgs8gxx_state *priv, u8 gi, u8 cpn,
+       u8 *locked)
 {
-       int err;
+       int err = 0;
        u8 ad_fini = 0;
+       u8 t1, t2;
 
        if (gi == GI_945)
                dprintk("try GI 945\n");
@@ -260,17 +419,29 @@ static int lgs8gxx_autolock_gi(struct lgs8gxx_state *priv, u8 gi, u8 *locked)
                dprintk("try GI 595\n");
        else if (gi == GI_420)
                dprintk("try GI 420\n");
-       lgs8gxx_write_reg(priv, 0x04, gi);
+       if (priv->config->prod == LGS8GXX_PROD_LGS8G75) {
+               lgs8gxx_read_reg(priv, 0x0C, &t1);
+               lgs8gxx_read_reg(priv, 0x18, &t2);
+               t1 &= ~(GI_MASK);
+               t1 |= gi;
+               t2 &= 0xFE;
+               t2 |= cpn ? 0x01 : 0x00;
+               lgs8gxx_write_reg(priv, 0x0C, t1);
+               lgs8gxx_write_reg(priv, 0x18, t2);
+       } else {
+               lgs8gxx_write_reg(priv, 0x04, gi);
+       }
        lgs8gxx_soft_reset(priv);
-       msleep(50);
+       err = lgs8gxx_wait_ca_lock(priv, locked);
+       if (err || !(*locked))
+               return err;
        err = lgs8gxx_is_autodetect_finished(priv, &ad_fini);
        if (err != 0)
                return err;
        if (ad_fini) {
-               err = lgs8gxx_is_locked(priv, locked);
-               if (err != 0)
-                       return err;
-       }
+               dprintk("auto detect finished\n");
+       } else
+               *locked = 0;
 
        return 0;
 }
@@ -285,13 +456,18 @@ static int lgs8gxx_auto_detect(struct lgs8gxx_state *priv,
        dprintk("%s\n", __func__);
 
        lgs8gxx_set_mode_auto(priv);
-       /* Guard Interval */
-       lgs8gxx_write_reg(priv, 0x03, 00);
+       if (priv->config->prod == LGS8GXX_PROD_LGS8G75) {
+               lgs8gxx_write_reg(priv, 0x67, 0xAA);
+               lgs8gxx_write_reg(priv, 0x6E, 0x3F);
+       } else {
+               /* Guard Interval */
+               lgs8gxx_write_reg(priv, 0x03, 00);
+       }
 
        for (i = 0; i < 2; i++) {
                for (j = 0; j < 2; j++) {
                        tmp_gi = GI_945;
-                       err = lgs8gxx_autolock_gi(priv, GI_945, &locked);
+                       err = lgs8gxx_autolock_gi(priv, GI_945, j, &locked);
                        if (err)
                                goto out;
                        if (locked)
@@ -299,14 +475,14 @@ static int lgs8gxx_auto_detect(struct lgs8gxx_state *priv,
                }
                for (j = 0; j < 2; j++) {
                        tmp_gi = GI_420;
-                       err = lgs8gxx_autolock_gi(priv, GI_420, &locked);
+                       err = lgs8gxx_autolock_gi(priv, GI_420, j, &locked);
                        if (err)
                                goto out;
                        if (locked)
                                goto locked;
                }
                tmp_gi = GI_595;
-               err = lgs8gxx_autolock_gi(priv, GI_595, &locked);
+               err = lgs8gxx_autolock_gi(priv, GI_595, 1, &locked);
                if (err)
                        goto out;
                if (locked)
@@ -317,8 +493,13 @@ locked:
        if ((err == 0) && (locked == 1)) {
                u8 t;
 
-               lgs8gxx_read_reg(priv, 0xA2, &t);
-               *detected_param = t;
+               if (priv->config->prod != LGS8GXX_PROD_LGS8G75) {
+                       lgs8gxx_read_reg(priv, 0xA2, &t);
+                       *detected_param = t;
+               } else {
+                       lgs8gxx_read_reg(priv, 0x1F, &t);
+                       *detected_param = t & 0x3F;
+               }
 
                if (tmp_gi == GI_945)
                        dprintk("GI 945 locked\n");
@@ -345,18 +526,28 @@ static void lgs8gxx_auto_lock(struct lgs8gxx_state *priv)
 
        if (err != 0) {
                dprintk("lgs8gxx_auto_detect failed\n");
-       }
+       } else
+               dprintk("detected param = 0x%02X\n", detected_param);
 
        /* Apply detected parameters */
        if (priv->config->prod == LGS8GXX_PROD_LGS8913) {
                u8 inter_leave_len = detected_param & TIM_MASK ;
-               inter_leave_len = (inter_leave_len == TIM_LONG) ? 0x60 : 0x40;
+               /* Fix 8913 time interleaver detection bug */
+               inter_leave_len = (inter_leave_len == TIM_MIDDLE) ? 0x60 : 0x40;
                detected_param &= CF_MASK | SC_MASK  | LGS_FEC_MASK;
                detected_param |= inter_leave_len;
        }
-       lgs8gxx_write_reg(priv, 0x7D, detected_param);
-       if (priv->config->prod == LGS8GXX_PROD_LGS8913)
-               lgs8gxx_write_reg(priv, 0xC0, detected_param);
+       if (priv->config->prod == LGS8GXX_PROD_LGS8G75) {
+               u8 t;
+               lgs8gxx_read_reg(priv, 0x19, &t);
+               t &= 0x81;
+               t |= detected_param << 1;
+               lgs8gxx_write_reg(priv, 0x19, t);
+       } else {
+               lgs8gxx_write_reg(priv, 0x7D, detected_param);
+               if (priv->config->prod == LGS8GXX_PROD_LGS8913)
+                       lgs8gxx_write_reg(priv, 0xC0, detected_param);
+       }
        /* lgs8gxx_soft_reset(priv); */
 
        /* Enter manual mode */
@@ -378,9 +569,10 @@ static int lgs8gxx_set_mpeg_mode(struct lgs8gxx_state *priv,
        u8 serial, u8 clk_pol, u8 clk_gated)
 {
        int ret = 0;
-       u8 t;
+       u8 t, reg_addr;
 
-       ret = lgs8gxx_read_reg(priv, 0xC2, &t);
+       reg_addr = (priv->config->prod == LGS8GXX_PROD_LGS8G75) ? 0x30 : 0xC2;
+       ret = lgs8gxx_read_reg(priv, reg_addr, &t);
        if (ret != 0)
                return ret;
 
@@ -389,13 +581,29 @@ static int lgs8gxx_set_mpeg_mode(struct lgs8gxx_state *priv,
        t |= clk_pol ? TS_CLK_INVERTED : TS_CLK_NORMAL;
        t |= clk_gated ? TS_CLK_GATED : TS_CLK_FREERUN;
 
-       ret = lgs8gxx_write_reg(priv, 0xC2, t);
+       ret = lgs8gxx_write_reg(priv, reg_addr, t);
        if (ret != 0)
                return ret;
 
        return 0;
 }
 
+/* A/D input peak-to-peak voltage range */
+static int lgs8g75_set_adc_vpp(struct lgs8gxx_state *priv,
+       u8 sel)
+{
+       u8 r26 = 0x73, r27 = 0x90;
+
+       if (priv->config->prod != LGS8GXX_PROD_LGS8G75)
+               return 0;
+
+       r26 |= (sel & 0x01) << 7;
+       r27 |= (sel & 0x02) >> 1;
+       lgs8gxx_write_reg(priv, 0x26, r26);
+       lgs8gxx_write_reg(priv, 0x27, r27);
+
+       return 0;
+}
 
 /* LGS8913 demod frontend functions */
 
@@ -417,6 +625,34 @@ static int lgs8913_init(struct lgs8gxx_state *priv)
        return 0;
 }
 
+static int lgs8g75_init_data(struct lgs8gxx_state *priv)
+{
+       const u8 *p = lgs8g75_initdat;
+       int i;
+
+       lgs8gxx_write_reg(priv, 0xC6, 0x40);
+
+       lgs8gxx_write_reg(priv, 0x3D, 0x04);
+       lgs8gxx_write_reg(priv, 0x39, 0x00);
+
+       lgs8gxx_write_reg(priv, 0x3A, 0x00);
+       lgs8gxx_write_reg(priv, 0x38, 0x00);
+       lgs8gxx_write_reg(priv, 0x3B, 0x00);
+       lgs8gxx_write_reg(priv, 0x38, 0x00);
+
+       for (i = 0; i < sizeof(lgs8g75_initdat); i++) {
+               lgs8gxx_write_reg(priv, 0x38, 0x00);
+               lgs8gxx_write_reg(priv, 0x3A, (u8)(i&0xff));
+               lgs8gxx_write_reg(priv, 0x3B, (u8)(i>>8));
+               lgs8gxx_write_reg(priv, 0x3C, *p);
+               p++;
+       }
+
+       lgs8gxx_write_reg(priv, 0x38, 0x00);
+
+       return 0;
+}
+
 static int lgs8gxx_init(struct dvb_frontend *fe)
 {
        struct lgs8gxx_state *priv =
@@ -429,6 +665,9 @@ static int lgs8gxx_init(struct dvb_frontend *fe)
        lgs8gxx_read_reg(priv, 0, &data);
        dprintk("reg 0 = 0x%02X\n", data);
 
+       if (config->prod == LGS8GXX_PROD_LGS8G75)
+               lgs8g75_set_adc_vpp(priv, config->adc_vpp);
+
        /* Setup MPEG output format */
        err = lgs8gxx_set_mpeg_mode(priv, config->serial_ts,
                                    config->ts_clk_pol,
@@ -439,8 +678,7 @@ static int lgs8gxx_init(struct dvb_frontend *fe)
        if (config->prod == LGS8GXX_PROD_LGS8913)
                lgs8913_init(priv);
        lgs8gxx_set_if_freq(priv, priv->config->if_freq);
-       if (config->prod != LGS8GXX_PROD_LGS8913)
-               lgs8gxx_set_ad_mode(priv);
+       lgs8gxx_set_ad_mode(priv);
 
        return 0;
 }
@@ -489,9 +727,6 @@ static int lgs8gxx_set_fe(struct dvb_frontend *fe,
 static int lgs8gxx_get_fe(struct dvb_frontend *fe,
                          struct dvb_frontend_parameters *fe_params)
 {
-       struct lgs8gxx_state *priv = fe->demodulator_priv;
-       u8 t;
-
        dprintk("%s\n", __func__);
 
        /* TODO: get real readings from device */
@@ -501,29 +736,10 @@ static int lgs8gxx_get_fe(struct dvb_frontend *fe,
        /* bandwidth */
        fe_params->u.ofdm.bandwidth = BANDWIDTH_8_MHZ;
 
-
-       lgs8gxx_read_reg(priv, 0x7D, &t);
        fe_params->u.ofdm.code_rate_HP = FEC_AUTO;
        fe_params->u.ofdm.code_rate_LP = FEC_AUTO;
 
-       /* constellation */
-       switch (t & SC_MASK) {
-       case SC_QAM64:
-               fe_params->u.ofdm.constellation = QAM_64;
-               break;
-       case SC_QAM32:
-               fe_params->u.ofdm.constellation = QAM_32;
-               break;
-       case SC_QAM16:
-               fe_params->u.ofdm.constellation = QAM_16;
-               break;
-       case SC_QAM4:
-       case SC_QAM4NR:
-               fe_params->u.ofdm.constellation = QPSK;
-               break;
-       default:
-               fe_params->u.ofdm.constellation = QAM_64;
-       }
+       fe_params->u.ofdm.constellation = QAM_AUTO;
 
        /* transmission mode */
        fe_params->u.ofdm.transmission_mode = TRANSMISSION_MODE_AUTO;
@@ -552,9 +768,19 @@ static int lgs8gxx_read_status(struct dvb_frontend *fe, fe_status_t *fe_status)
 {
        struct lgs8gxx_state *priv = fe->demodulator_priv;
        s8 ret;
-       u8 t;
+       u8 t, locked = 0;
 
        dprintk("%s\n", __func__);
+       *fe_status = 0;
+
+       lgs8gxx_get_afc_phase(priv);
+       lgs8gxx_is_locked(priv, &locked);
+       if (priv->config->prod == LGS8GXX_PROD_LGS8G75) {
+               if (locked)
+                       *fe_status |= FE_HAS_SIGNAL | FE_HAS_CARRIER |
+                               FE_HAS_VITERBI | FE_HAS_SYNC | FE_HAS_LOCK;
+               return 0;
+       }
 
        ret = lgs8gxx_read_reg(priv, 0x4B, &t);
        if (ret != 0)
@@ -658,12 +884,33 @@ static int lgs8913_read_signal_strength(struct lgs8gxx_state *priv, u16 *signal)
        return 0;
 }
 
+static int lgs8g75_read_signal_strength(struct lgs8gxx_state *priv, u16 *signal)
+{
+       u8 t;
+       s16 v = 0;
+
+       dprintk("%s\n", __func__);
+
+       lgs8gxx_read_reg(priv, 0xB1, &t);
+       v |= t;
+       v <<= 8;
+       lgs8gxx_read_reg(priv, 0xB0, &t);
+       v |= t;
+
+       *signal = v;
+       dprintk("%s: signal=0x%02X\n", __func__, *signal);
+
+       return 0;
+}
+
 static int lgs8gxx_read_signal_strength(struct dvb_frontend *fe, u16 *signal)
 {
        struct lgs8gxx_state *priv = fe->demodulator_priv;
 
        if (priv->config->prod == LGS8GXX_PROD_LGS8913)
                return lgs8913_read_signal_strength(priv, signal);
+       else if (priv->config->prod == LGS8GXX_PROD_LGS8G75)
+               return lgs8g75_read_signal_strength(priv, signal);
        else
                return lgs8gxx_read_signal_agc(priv, signal);
 }
@@ -674,7 +921,10 @@ static int lgs8gxx_read_snr(struct dvb_frontend *fe, u16 *snr)
        u8 t;
        *snr = 0;
 
-       lgs8gxx_read_reg(priv, 0x95, &t);
+       if (priv->config->prod == LGS8GXX_PROD_LGS8G75)
+               lgs8gxx_read_reg(priv, 0x34, &t);
+       else
+               lgs8gxx_read_reg(priv, 0x95, &t);
        dprintk("AVG Noise=0x%02X\n", t);
        *snr = 256 - t;
        *snr <<= 8;
@@ -690,31 +940,68 @@ static int lgs8gxx_read_ucblocks(struct dvb_frontend *fe, u32 *ucblocks)
        return 0;
 }
 
+static void packet_counter_start(struct lgs8gxx_state *priv)
+{
+       u8 orig, t;
+
+       if (priv->config->prod == LGS8GXX_PROD_LGS8G75) {
+               lgs8gxx_read_reg(priv, 0x30, &orig);
+               orig &= 0xE7;
+               t = orig | 0x10;
+               lgs8gxx_write_reg(priv, 0x30, t);
+               t = orig | 0x18;
+               lgs8gxx_write_reg(priv, 0x30, t);
+               t = orig | 0x10;
+               lgs8gxx_write_reg(priv, 0x30, t);
+       } else {
+               lgs8gxx_write_reg(priv, 0xC6, 0x01);
+               lgs8gxx_write_reg(priv, 0xC6, 0x41);
+               lgs8gxx_write_reg(priv, 0xC6, 0x01);
+       }
+}
+
+static void packet_counter_stop(struct lgs8gxx_state *priv)
+{
+       u8 t;
+
+       if (priv->config->prod == LGS8GXX_PROD_LGS8G75) {
+               lgs8gxx_read_reg(priv, 0x30, &t);
+               t &= 0xE7;
+               lgs8gxx_write_reg(priv, 0x30, t);
+       } else {
+               lgs8gxx_write_reg(priv, 0xC6, 0x81);
+       }
+}
+
 static int lgs8gxx_read_ber(struct dvb_frontend *fe, u32 *ber)
 {
        struct lgs8gxx_state *priv = fe->demodulator_priv;
-       u8 r0, r1, r2, r3;
-       u32 total_cnt, err_cnt;
+       u8 reg_err, reg_total, t;
+       u32 total_cnt = 0, err_cnt = 0;
+       int i;
 
        dprintk("%s\n", __func__);
 
-       lgs8gxx_write_reg(priv, 0xc6, 0x01);
-       lgs8gxx_write_reg(priv, 0xc6, 0x41);
-       lgs8gxx_write_reg(priv, 0xc6, 0x01);
-
+       packet_counter_start(priv);
        msleep(200);
+       packet_counter_stop(priv);
+
+       if (priv->config->prod == LGS8GXX_PROD_LGS8G75) {
+               reg_total = 0x28; reg_err = 0x2C;
+       } else {
+               reg_total = 0xD0; reg_err = 0xD4;
+       }
 
-       lgs8gxx_write_reg(priv, 0xc6, 0x81);
-       lgs8gxx_read_reg(priv, 0xd0, &r0);
-       lgs8gxx_read_reg(priv, 0xd1, &r1);
-       lgs8gxx_read_reg(priv, 0xd2, &r2);
-       lgs8gxx_read_reg(priv, 0xd3, &r3);
-       total_cnt = (r3 << 24) | (r2 << 16) | (r1 << 8) | (r0);
-       lgs8gxx_read_reg(priv, 0xd4, &r0);
-       lgs8gxx_read_reg(priv, 0xd5, &r1);
-       lgs8gxx_read_reg(priv, 0xd6, &r2);
-       lgs8gxx_read_reg(priv, 0xd7, &r3);
-       err_cnt = (r3 << 24) | (r2 << 16) | (r1 << 8) | (r0);
+       for (i = 0; i < 4; i++) {
+               total_cnt <<= 8;
+               lgs8gxx_read_reg(priv, reg_total+3-i, &t);
+               total_cnt |= t;
+       }
+       for (i = 0; i < 4; i++) {
+               err_cnt <<= 8;
+               lgs8gxx_read_reg(priv, reg_err+3-i, &t);
+               err_cnt |= t;
+       }
        dprintk("error=%d total=%d\n", err_cnt, total_cnt);
 
        if (total_cnt == 0)
@@ -801,6 +1088,9 @@ struct dvb_frontend *lgs8gxx_attach(const struct lgs8gxx_config *config,
               sizeof(struct dvb_frontend_ops));
        priv->frontend.demodulator_priv = priv;
 
+       if (config->prod == LGS8GXX_PROD_LGS8G75)
+               lgs8g75_init_data(priv);
+
        return &priv->frontend;
 
 error_out:
index 321d366a830766fae3e37c7cf4861b1dc820bb68..33c3c5e162fa6b4e2b79fbc87406293b61e38f1e 100644 (file)
@@ -1,9 +1,9 @@
 /*
- *    Support for Legend Silicon DMB-TH demodulator
- *    LGS8913, LGS8GL5
+ *    Support for Legend Silicon GB20600 (a.k.a DMB-TH) demodulator
+ *    LGS8913, LGS8GL5, LGS8G75
  *    experimental support LGS8G42, LGS8G52
  *
- *    Copyright (C) 2007,2008 David T.L. Wong <davidtlwong@gmail.com>
+ *    Copyright (C) 2007-2009 David T.L. Wong <davidtlwong@gmail.com>
  *    Copyright (C) 2008 Sirius International (Hong Kong) Limited
  *    Timothy Lee <timothy.lee@siriushk.com> (for initial work on LGS8GL5)
  *
@@ -34,6 +34,7 @@
 #define LGS8GXX_PROD_LGS8G42 3
 #define LGS8GXX_PROD_LGS8G52 4
 #define LGS8GXX_PROD_LGS8G54 5
+#define LGS8GXX_PROD_LGS8G75 6
 
 struct lgs8gxx_config {
 
@@ -70,6 +71,10 @@ struct lgs8gxx_config {
        /*IF use Negative center frequency*/
        u8 if_neg_center;
 
+       /*8G75 internal ADC input range selection*/
+       /*0: 0.8Vpp, 1: 1.0Vpp, 2: 1.6Vpp, 3: 2.0Vpp*/
+       u8 adc_vpp;
+
        /* slave address and configuration of the tuner */
        u8 tuner_address;
 };
index 9776d30686dcdab482f0509d3d106d418acf89ea..8ef376f1414de30c6d078a47e36d05717767b9ec 100644 (file)
@@ -1,9 +1,9 @@
 /*
- *    Support for Legend Silicon DMB-TH demodulator
- *    LGS8913, LGS8GL5
+ *    Support for Legend Silicon GB20600 (a.k.a DMB-TH) demodulator
+ *    LGS8913, LGS8GL5, LGS8G75
  *    experimental support LGS8G42, LGS8G52
  *
- *    Copyright (C) 2007,2008 David T.L. Wong <davidtlwong@gmail.com>
+ *    Copyright (C) 2007-2009 David T.L. Wong <davidtlwong@gmail.com>
  *    Copyright (C) 2008 Sirius International (Hong Kong) Limited
  *    Timothy Lee <timothy.lee@siriushk.com> (for initial work on LGS8GL5)
  *
@@ -38,7 +38,7 @@ struct lgs8gxx_state {
 #define SC_QAM64       0x10    /* 64QAM modulation */
 #define SC_QAM32       0x0C    /* 32QAM modulation */
 #define SC_QAM16       0x08    /* 16QAM modulation */
-#define SC_QAM4NR      0x04    /* 4QAM modulation */
+#define SC_QAM4NR      0x04    /* 4QAM-NR modulation */
 #define SC_QAM4                0x00    /* 4QAM modulation */
 
 #define LGS_FEC_MASK   0x03    /* FEC Rate Mask */
@@ -47,8 +47,8 @@ struct lgs8gxx_state {
 #define LGS_FEC_0_8    0x02    /* FEC Rate 0.8 */
 
 #define TIM_MASK         0x20  /* Time Interleave Length Mask */
-#define TIM_LONG         0x00  /* Time Interleave Length = 720 */
-#define TIM_MIDDLE     0x20   /* Time Interleave Length = 240 */
+#define TIM_LONG         0x20  /* Time Interleave Length = 720 */
+#define TIM_MIDDLE     0x00   /* Time Interleave Length = 240 */
 
 #define CF_MASK        0x80    /* Control Frame Mask */
 #define CF_EN  0x80    /* Control Frame On */
index f69daaac78c9bf431d1371914d208ad5a9f9811e..472907d43460f8c6536d83d0152ee269de0ad635 100644 (file)
@@ -85,7 +85,7 @@ static int mt312_read(struct mt312_state *state, const enum mt312_reg_addr reg,
                int i;
                dprintk("R(%d):", reg & 0x7f);
                for (i = 0; i < count; i++)
-                       printk(" %02x", buf[i]);
+                       printk(KERN_CONT " %02x", buf[i]);
                printk("\n");
        }
 
@@ -103,7 +103,7 @@ static int mt312_write(struct mt312_state *state, const enum mt312_reg_addr reg,
                int i;
                dprintk("W(%d):", reg & 0x7f);
                for (i = 0; i < count; i++)
-                       printk(" %02x", src[i]);
+                       printk(KERN_CONT " %02x", src[i]);
                printk("\n");
        }
 
@@ -744,7 +744,8 @@ static struct dvb_frontend_ops mt312_ops = {
                .type = FE_QPSK,
                .frequency_min = 950000,
                .frequency_max = 2150000,
-               .frequency_stepsize = (MT312_PLL_CLK / 1000) / 128, /* FIXME: adjust freq to real used xtal */
+               /* FIXME: adjust freq to real used xtal */
+               .frequency_stepsize = (MT312_PLL_CLK / 1000) / 128,
                .symbol_rate_min = MT312_SYS_CLK / 128, /* FIXME as above */
                .symbol_rate_max = MT312_SYS_CLK / 2,
                .caps =
index 1ed5a7db4c5eec887eaceb749ee6b454d79856c3..60ee18a94f43228b74a944cadad7c5ed430301d2 100644 (file)
@@ -367,7 +367,9 @@ static int stb6100_set_frequency(struct dvb_frontend *fe, u32 frequency)
        /* N(I) = floor(f(VCO) / (f(XTAL) * (PSD2 ? 2 : 1)))    */
        nint = fvco / (state->reference << psd2);
        /* N(F) = round(f(VCO) / f(XTAL) * (PSD2 ? 2 : 1) - N(I)) * 2 ^ 9       */
-       nfrac = (((fvco - (nint * state->reference << psd2)) << (9 - psd2)) + state->reference / 2) / state->reference;
+       nfrac = DIV_ROUND_CLOSEST((fvco - (nint * state->reference << psd2))
+                                        << (9 - psd2),
+                                 state->reference);
        dprintk(verbose, FE_DEBUG, 1,
                "frequency = %u, srate = %u, g = %u, odiv = %u, psd2 = %u, fxtal = %u, osm = %u, fvco = %u, N(I) = %u, N(F) = %u",
                frequency, srate, (unsigned int)g, (unsigned int)odiv,
index 1da045fbb4ef225def8c67afac3b6d528db668e6..3bde3324a032b4fb0711465d3d0bd41303d567f8 100644 (file)
@@ -230,8 +230,8 @@ enum fe_stv0900_error stv0900_initialize(struct stv0900_internal *i_params)
                        stv0900_write_reg(i_params, R0900_P2_DMDISTATE, 0x5c);
                        stv0900_write_reg(i_params, R0900_P1_TNRCFG, 0x6c);
                        stv0900_write_reg(i_params, R0900_P2_TNRCFG, 0x6f);
-                       stv0900_write_reg(i_params, R0900_P1_I2CRPT, 0x24);
-                       stv0900_write_reg(i_params, R0900_P2_I2CRPT, 0x24);
+                       stv0900_write_reg(i_params, R0900_P1_I2CRPT, 0x20);
+                       stv0900_write_reg(i_params, R0900_P2_I2CRPT, 0x20);
                        stv0900_write_reg(i_params, R0900_NCOARSE, 0x13);
                        msleep(3);
                        stv0900_write_reg(i_params, R0900_I2CCFG, 0x08);
@@ -370,8 +370,8 @@ static int stv0900_i2c_gate_ctrl(struct dvb_frontend *fe, int enable)
        u32 fi2c;
 
        dmd_reg(fi2c, F0900_P1_I2CT_ON, F0900_P2_I2CT_ON);
-       if (enable)
-               stv0900_write_bits(i_params, fi2c, 1);
+
+       stv0900_write_bits(i_params, fi2c, enable);
 
        return 0;
 }
index a5a31536cbcb113fbcd5690b24c98395cb4a69d0..962fde1437cea24b1d5ae8c52dba8cfdebf8c0d6 100644 (file)
@@ -1721,7 +1721,7 @@ static enum fe_stv0900_signal_type stv0900_dvbs1_acq_workaround(struct dvb_front
 
        s32 srate, demod_timeout,
                fec_timeout, freq1, freq0;
-       enum fe_stv0900_signal_type signal_type = STV0900_NODATA;;
+       enum fe_stv0900_signal_type signal_type = STV0900_NODATA;
 
        switch (demod) {
        case STV0900_DEMOD_1:
index 70efac869d28e9cbb6945c6610736a76009fa516..dcf1b21ea9741971e15ad314dd59ecfcf7743cf8 100644 (file)
@@ -36,6 +36,7 @@ struct stv6110_priv {
        struct i2c_adapter *i2c;
 
        u32 mclk;
+       u8 clk_div;
        u8 regs[8];
 };
 
@@ -100,35 +101,25 @@ static int stv6110_read_regs(struct dvb_frontend *fe, u8 regs[],
        struct stv6110_priv *priv = fe->tuner_priv;
        int rc;
        u8 reg[] = { start };
-       struct i2c_msg msg_wr = {
-               .addr   = priv->i2c_address,
-               .flags  = 0,
-               .buf    = reg,
-               .len    = 1,
+       struct i2c_msg msg[] = {
+               {
+                       .addr   = priv->i2c_address,
+                       .flags  = 0,
+                       .buf    = reg,
+                       .len    = 1,
+               }, {
+                       .addr   = priv->i2c_address,
+                       .flags  = I2C_M_RD,
+                       .buf    = regs,
+                       .len    = len,
+               },
        };
 
-       struct i2c_msg msg_rd = {
-               .addr   = priv->i2c_address,
-               .flags  = I2C_M_RD,
-               .buf    = regs,
-               .len    = len,
-       };
-       /* write subaddr */
        if (fe->ops.i2c_gate_ctrl)
                fe->ops.i2c_gate_ctrl(fe, 1);
 
-       rc = i2c_transfer(priv->i2c, &msg_wr, 1);
-       if (rc != 1)
-               dprintk("%s: i2c error\n", __func__);
-
-       if (fe->ops.i2c_gate_ctrl)
-               fe->ops.i2c_gate_ctrl(fe, 0);
-       /* read registers */
-       if (fe->ops.i2c_gate_ctrl)
-               fe->ops.i2c_gate_ctrl(fe, 1);
-
-       rc = i2c_transfer(priv->i2c, &msg_rd, 1);
-       if (rc != 1)
+       rc = i2c_transfer(priv->i2c, msg, 2);
+       if (rc != 2)
                dprintk("%s: i2c error\n", __func__);
 
        if (fe->ops.i2c_gate_ctrl)
@@ -221,6 +212,10 @@ static int stv6110_init(struct dvb_frontend *fe)
        priv->regs[RSTV6110_CTRL1] |=
                                ((((priv->mclk / 1000000) - 16) & 0x1f) << 3);
 
+       /* divisor value for the output clock */
+       priv->regs[RSTV6110_CTRL2] &= ~0xc0;
+       priv->regs[RSTV6110_CTRL2] |= (priv->clk_div << 6);
+
        stv6110_write_regs(fe, &priv->regs[RSTV6110_CTRL1], RSTV6110_CTRL1, 8);
        msleep(1);
        stv6110_set_bandwidth(fe, 72000000);
@@ -418,6 +413,10 @@ struct dvb_frontend *stv6110_attach(struct dvb_frontend *fe,
        };
        int ret;
 
+       /* divisor value for the output clock */
+       reg0[2] &= ~0xc0;
+       reg0[2] |= (config->clk_div << 6);
+
        if (fe->ops.i2c_gate_ctrl)
                fe->ops.i2c_gate_ctrl(fe, 1);
 
@@ -436,6 +435,7 @@ struct dvb_frontend *stv6110_attach(struct dvb_frontend *fe,
        priv->i2c_address = config->i2c_address;
        priv->i2c = i2c;
        priv->mclk = config->mclk;
+       priv->clk_div = config->clk_div;
 
        memcpy(&priv->regs, &reg0[1], 8);
 
index 1c0314d6aa558b053783ebe0a323935e34a7407a..9db2402410f63b0b740697d8e39915102392ce7c 100644 (file)
@@ -41,7 +41,7 @@
 struct stv6110_config {
        u8 i2c_address;
        u32 mclk;
-       int iq_wiring;
+       u8 clk_div;     /* divisor value for the output clock */
 };
 
 #if defined(CONFIG_DVB_STV6110) || (defined(CONFIG_DVB_STV6110_MODULE) \
index f5d7b3277a2fa585360aaafda331669a11ecd95a..6c1dbf9288d8b34d652bdf4b3465f3d46d0d4b1e 100644 (file)
@@ -176,7 +176,7 @@ static int tda10021_set_symbolrate (struct tda10021_state* state, u32 symbolrate
        tmp =  ((symbolrate << 4) % FIN) << 8;
        ratio = (ratio << 8) + tmp / FIN;
        tmp = (tmp % FIN) << 8;
-       ratio = (ratio << 8) + (tmp + FIN/2) / FIN;
+       ratio = (ratio << 8) + DIV_ROUND_CLOSEST(tmp, FIN);
 
        BDR = ratio;
        BDRI = (((XIN << 5) / symbolrate) + 1) / 2;
index b6d177799104d6b6e555b0fb7acc714ff51a4b33..320c3c36d8b2495663a233d0c167fa9c5dee51a0 100644 (file)
@@ -136,9 +136,9 @@ static int tda8261_set_state(struct dvb_frontend *fe,
 
                if (frequency < 1450000)
                        buf[3] = 0x00;
-               if (frequency < 2000000)
+               else if (frequency < 2000000)
                        buf[3] = 0x40;
-               if (frequency < 2150000)
+               else if (frequency < 2150000)
                        buf[3] = 0x80;
 
                /* Set params */
index 6e78e486551599bc47d76addb4e0af3e284175b6..550a07a8a9975d253b9e39482d5e4cc0b040adb8 100644 (file)
@@ -165,7 +165,7 @@ static int ves1820_set_symbolrate(struct ves1820_state *state, u32 symbolrate)
        tmp = ((symbolrate << 4) % fin) << 8;
        ratio = (ratio << 8) + tmp / fin;
        tmp = (tmp % fin) << 8;
-       ratio = (ratio << 8) + (tmp + fin / 2) / fin;
+       ratio = (ratio << 8) + DIV_ROUND_CLOSEST(tmp, fin);
 
        BDR = ratio;
        BDRI = (((state->config->xin << 5) / symbolrate) + 1) / 2;
index e22a0b381dc4f402bddf043a0d91580a34fc50f6..4e814ff22b23c5f5847b949b8918579bce61bdf0 100644 (file)
@@ -29,7 +29,7 @@
 
 #include <linux/module.h>
 #include <linux/dvb/frontend.h>
-#include <asm/types.h>
+#include <linux/types.h>
 
 #include "zl10036.h"
 
diff --git a/drivers/media/dvb/frontends/zl10039.c b/drivers/media/dvb/frontends/zl10039.c
new file mode 100644 (file)
index 0000000..11b29cb
--- /dev/null
@@ -0,0 +1,308 @@
+/*
+ *  Driver for Zarlink ZL10039 DVB-S tuner
+ *
+ *  Copyright 2007 Jan D. Louw <jd.louw@mweb.co.za>
+ *
+ *  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/string.h>
+#include <linux/slab.h>
+#include <linux/dvb/frontend.h>
+
+#include "dvb_frontend.h"
+#include "zl10039.h"
+
+static int debug;
+
+#define dprintk(args...) \
+       do { \
+               if (debug) \
+                       printk(KERN_DEBUG args); \
+       } while (0)
+
+enum zl10039_model_id {
+       ID_ZL10039 = 1
+};
+
+struct zl10039_state {
+       struct i2c_adapter *i2c;
+       u8 i2c_addr;
+       u8 id;
+};
+
+enum zl10039_reg_addr {
+       PLL0 = 0,
+       PLL1,
+       PLL2,
+       PLL3,
+       RFFE,
+       BASE0,
+       BASE1,
+       BASE2,
+       LO0,
+       LO1,
+       LO2,
+       LO3,
+       LO4,
+       LO5,
+       LO6,
+       GENERAL
+};
+
+static int zl10039_read(const struct zl10039_state *state,
+                       const enum zl10039_reg_addr reg, u8 *buf,
+                       const size_t count)
+{
+       u8 regbuf[] = { reg };
+       struct i2c_msg msg[] = {
+               {/* Write register address */
+                       .addr = state->i2c_addr,
+                       .flags = 0,
+                       .buf = regbuf,
+                       .len = 1,
+               }, {/* Read count bytes */
+                       .addr = state->i2c_addr,
+                       .flags = I2C_M_RD,
+                       .buf = buf,
+                       .len = count,
+               },
+       };
+
+       dprintk("%s\n", __func__);
+
+       if (i2c_transfer(state->i2c, msg, 2) != 2) {
+               dprintk("%s: i2c read error\n", __func__);
+               return -EREMOTEIO;
+       }
+
+       return 0; /* Success */
+}
+
+static int zl10039_write(struct zl10039_state *state,
+                       const enum zl10039_reg_addr reg, const u8 *src,
+                       const size_t count)
+{
+       u8 buf[count + 1];
+       struct i2c_msg msg = {
+               .addr = state->i2c_addr,
+               .flags = 0,
+               .buf = buf,
+               .len = count + 1,
+       };
+
+       dprintk("%s\n", __func__);
+       /* Write register address and data in one go */
+       buf[0] = reg;
+       memcpy(&buf[1], src, count);
+       if (i2c_transfer(state->i2c, &msg, 1) != 1) {
+               dprintk("%s: i2c write error\n", __func__);
+               return -EREMOTEIO;
+       }
+
+       return 0; /* Success */
+}
+
+static inline int zl10039_readreg(struct zl10039_state *state,
+                               const enum zl10039_reg_addr reg, u8 *val)
+{
+       return zl10039_read(state, reg, val, 1);
+}
+
+static inline int zl10039_writereg(struct zl10039_state *state,
+                               const enum zl10039_reg_addr reg,
+                               const u8 val)
+{
+       return zl10039_write(state, reg, &val, 1);
+}
+
+static int zl10039_init(struct dvb_frontend *fe)
+{
+       struct zl10039_state *state = fe->tuner_priv;
+       int ret;
+
+       dprintk("%s\n", __func__);
+       if (fe->ops.i2c_gate_ctrl)
+               fe->ops.i2c_gate_ctrl(fe, 1);
+       /* Reset logic */
+       ret = zl10039_writereg(state, GENERAL, 0x40);
+       if (ret < 0) {
+               dprintk("Note: i2c write error normal when resetting the "
+                       "tuner\n");
+       }
+       /* Wake up */
+       ret = zl10039_writereg(state, GENERAL, 0x01);
+       if (ret < 0) {
+               dprintk("Tuner power up failed\n");
+               return ret;
+       }
+       if (fe->ops.i2c_gate_ctrl)
+               fe->ops.i2c_gate_ctrl(fe, 0);
+
+       return 0;
+}
+
+static int zl10039_sleep(struct dvb_frontend *fe)
+{
+       struct zl10039_state *state = fe->tuner_priv;
+       int ret;
+
+       dprintk("%s\n", __func__);
+       if (fe->ops.i2c_gate_ctrl)
+               fe->ops.i2c_gate_ctrl(fe, 1);
+       ret = zl10039_writereg(state, GENERAL, 0x80);
+       if (ret < 0) {
+               dprintk("Tuner sleep failed\n");
+               return ret;
+       }
+       if (fe->ops.i2c_gate_ctrl)
+               fe->ops.i2c_gate_ctrl(fe, 0);
+
+       return 0;
+}
+
+static int zl10039_set_params(struct dvb_frontend *fe,
+                       struct dvb_frontend_parameters *params)
+{
+       struct zl10039_state *state = fe->tuner_priv;
+       u8 buf[6];
+       u8 bf;
+       u32 fbw;
+       u32 div;
+       int ret;
+
+       dprintk("%s\n", __func__);
+       dprintk("Set frequency = %d, symbol rate = %d\n",
+                       params->frequency, params->u.qpsk.symbol_rate);
+
+       /* Assumed 10.111 MHz crystal oscillator */
+       /* Cancelled num/den 80 to prevent overflow */
+       div = (params->frequency * 1000) / 126387;
+       fbw = (params->u.qpsk.symbol_rate * 27) / 32000;
+       /* Cancelled num/den 10 to prevent overflow */
+       bf = ((fbw * 5088) / 1011100) - 1;
+
+       /*PLL divider*/
+       buf[0] = (div >> 8) & 0x7f;
+       buf[1] = (div >> 0) & 0xff;
+       /*Reference divider*/
+       /* Select reference ratio of 80 */
+       buf[2] = 0x1D;
+       /*PLL test modes*/
+       buf[3] = 0x40;
+       /*RF Control register*/
+       buf[4] = 0x6E; /* Bypass enable */
+       /*Baseband filter cutoff */
+       buf[5] = bf;
+
+       /* Open i2c gate */
+       if (fe->ops.i2c_gate_ctrl)
+               fe->ops.i2c_gate_ctrl(fe, 1);
+       /* BR = 10, Enable filter adjustment */
+       ret = zl10039_writereg(state, BASE1, 0x0A);
+       if (ret < 0)
+               goto error;
+       /* Write new config values */
+       ret = zl10039_write(state, PLL0, buf, sizeof(buf));
+       if (ret < 0)
+               goto error;
+       /* BR = 10, Disable filter adjustment */
+       ret = zl10039_writereg(state, BASE1, 0x6A);
+       if (ret < 0)
+               goto error;
+
+       /* Close i2c gate */
+       if (fe->ops.i2c_gate_ctrl)
+               fe->ops.i2c_gate_ctrl(fe, 0);
+       return 0;
+error:
+       dprintk("Error setting tuner\n");
+       return ret;
+}
+
+static int zl10039_release(struct dvb_frontend *fe)
+{
+       struct zl10039_state *state = fe->tuner_priv;
+
+       dprintk("%s\n", __func__);
+       kfree(state);
+       fe->tuner_priv = NULL;
+       return 0;
+}
+
+static struct dvb_tuner_ops zl10039_ops = {
+       .release = zl10039_release,
+       .init = zl10039_init,
+       .sleep = zl10039_sleep,
+       .set_params = zl10039_set_params,
+};
+
+struct dvb_frontend *zl10039_attach(struct dvb_frontend *fe,
+               u8 i2c_addr, struct i2c_adapter *i2c)
+{
+       struct zl10039_state *state = NULL;
+
+       dprintk("%s\n", __func__);
+       state = kmalloc(sizeof(struct zl10039_state), GFP_KERNEL);
+       if (state == NULL)
+               goto error;
+
+       state->i2c = i2c;
+       state->i2c_addr = i2c_addr;
+
+       /* Open i2c gate */
+       if (fe->ops.i2c_gate_ctrl)
+               fe->ops.i2c_gate_ctrl(fe, 1);
+       /* check if this is a valid tuner */
+       if (zl10039_readreg(state, GENERAL, &state->id) < 0) {
+               /* Close i2c gate */
+               if (fe->ops.i2c_gate_ctrl)
+                       fe->ops.i2c_gate_ctrl(fe, 0);
+               goto error;
+       }
+       /* Close i2c gate */
+       if (fe->ops.i2c_gate_ctrl)
+               fe->ops.i2c_gate_ctrl(fe, 0);
+
+       state->id = state->id & 0x0f;
+       switch (state->id) {
+       case ID_ZL10039:
+               strcpy(fe->ops.tuner_ops.info.name,
+                       "Zarlink ZL10039 DVB-S tuner");
+               break;
+       default:
+               dprintk("Chip ID=%x does not match a known type\n", state->id);
+               break;
+               goto error;
+       }
+
+       memcpy(&fe->ops.tuner_ops, &zl10039_ops, sizeof(struct dvb_tuner_ops));
+       fe->tuner_priv = state;
+       dprintk("Tuner attached @ i2c address 0x%02x\n", i2c_addr);
+       return fe;
+error:
+       kfree(state);
+       return NULL;
+}
+EXPORT_SYMBOL(zl10039_attach);
+
+module_param(debug, int, 0644);
+MODULE_PARM_DESC(debug, "Turn on/off frontend debugging (default:off).");
+MODULE_DESCRIPTION("Zarlink ZL10039 DVB-S tuner driver");
+MODULE_AUTHOR("Jan D. Louw <jd.louw@mweb.co.za>");
+MODULE_LICENSE("GPL");
diff --git a/drivers/media/dvb/frontends/zl10039.h b/drivers/media/dvb/frontends/zl10039.h
new file mode 100644 (file)
index 0000000..5eee7ea
--- /dev/null
@@ -0,0 +1,40 @@
+/*
+    Driver for Zarlink ZL10039 DVB-S tuner
+
+    Copyright (C) 2007 Jan D. Louw <jd.louw@mweb.co.za>
+
+    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 ZL10039_H
+#define ZL10039_H
+
+#if defined(CONFIG_DVB_ZL10039) || (defined(CONFIG_DVB_ZL10039_MODULE) \
+           && defined(MODULE))
+struct dvb_frontend *zl10039_attach(struct dvb_frontend *fe,
+                                       u8 i2c_addr,
+                                       struct i2c_adapter *i2c);
+#else
+static inline struct dvb_frontend *zl10039_attach(struct dvb_frontend *fe,
+                                       u8 i2c_addr,
+                                       struct i2c_adapter *i2c)
+{
+       printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
+       return NULL;
+}
+#endif /* CONFIG_DVB_ZL10039 */
+
+#endif /* ZL10039_H */
index 66f5c1fb3074e60e13d481b558d2403803e9d5eb..8c612719adfca35c81d01cfb78223559137d30b6 100644 (file)
@@ -38,6 +38,8 @@ struct zl10353_state {
        struct zl10353_config config;
 
        enum fe_bandwidth bandwidth;
+       u32 ucblocks;
+       u32 frequency;
 };
 
 static int debug;
@@ -199,6 +201,8 @@ static int zl10353_set_parameters(struct dvb_frontend *fe,
        u16 tps = 0;
        struct dvb_ofdm_parameters *op = &param->u.ofdm;
 
+       state->frequency = param->frequency;
+
        zl10353_single_write(fe, RESET, 0x80);
        udelay(200);
        zl10353_single_write(fe, 0xEA, 0x01);
@@ -464,7 +468,7 @@ static int zl10353_get_parameters(struct dvb_frontend *fe,
                break;
        }
 
-       param->frequency = 0;
+       param->frequency = state->frequency;
        op->bandwidth = state->bandwidth;
        param->inversion = INVERSION_AUTO;
 
@@ -542,9 +546,13 @@ static int zl10353_read_snr(struct dvb_frontend *fe, u16 *snr)
 static int zl10353_read_ucblocks(struct dvb_frontend *fe, u32 *ucblocks)
 {
        struct zl10353_state *state = fe->demodulator_priv;
+       u32 ubl = 0;
+
+       ubl = zl10353_read_register(state, RS_UBC_1) << 8 |
+            zl10353_read_register(state, RS_UBC_0);
 
-       *ucblocks = zl10353_read_register(state, RS_UBC_1) << 8 |
-                   zl10353_read_register(state, RS_UBC_0);
+       state->ucblocks += ubl;
+       *ucblocks = state->ucblocks;
 
        return 0;
 }
index 598eaf8acc6e4ef4881fe1a862716142698b5c97..80d14a065bad0755fda4af3f27edb0b9fbe18308 100644 (file)
@@ -439,7 +439,7 @@ static inline u32 divide(u32 numerator, u32 denominator)
        if (denominator == 0)
                return ~0;
 
-       return (numerator + denominator / 2) / denominator;
+       return DIV_ROUND_CLOSEST(numerator, denominator);
 }
 
 /* LG Innotek TDTE-E001P (Infineon TUA6034) */
index ce64c6214cc410d473e61eac226ffa3514acea19..8986d967d2f4bb03c0e67dae2458a686e718ad3e 100644 (file)
@@ -490,7 +490,7 @@ static int vidioc_s_input(struct file *file, void *fh, unsigned int input)
        if (!av7110->analog_tuner_flags)
                return 0;
 
-       if (input < 0 || input >= 4)
+       if (input >= 4)
                return -EINVAL;
 
        av7110->current_input = input;
index 371a716168106e0698e299504594fe62c242198a..b5c681372b6ca254ea39e5669c40101c81df2bff 100644 (file)
@@ -225,7 +225,7 @@ static int msp430_ir_init(struct budget_ci *budget_ci)
        case 0x1012:
                /* The hauppauge keymap is a superset of these remotes */
                ir_input_init(input_dev, &budget_ci->ir.state,
-                             IR_TYPE_RC5, ir_codes_hauppauge_new);
+                             IR_TYPE_RC5, &ir_codes_hauppauge_new_table);
 
                if (rc5_device < 0)
                        budget_ci->ir.rc5_device = 0x1f;
@@ -237,7 +237,7 @@ static int msp430_ir_init(struct budget_ci *budget_ci)
        case 0x101a:
                /* for the Technotrend 1500 bundled remote */
                ir_input_init(input_dev, &budget_ci->ir.state,
-                             IR_TYPE_RC5, ir_codes_tt_1500);
+                             IR_TYPE_RC5, &ir_codes_tt_1500_table);
 
                if (rc5_device < 0)
                        budget_ci->ir.rc5_device = IR_DEVICE_ANY;
@@ -247,7 +247,7 @@ static int msp430_ir_init(struct budget_ci *budget_ci)
        default:
                /* unknown remote */
                ir_input_init(input_dev, &budget_ci->ir.state,
-                             IR_TYPE_RC5, ir_codes_budget_ci_old);
+                             IR_TYPE_RC5, &ir_codes_budget_ci_old_table);
 
                if (rc5_device < 0)
                        budget_ci->ir.rc5_device = IR_DEVICE_ANY;
index 3315cac875e518996b4f02a1a2cd791fc5e45f6a..25a36ad60c5e92192d10269c9e2d96efa224c715 100644 (file)
@@ -288,16 +288,6 @@ config RADIO_TYPHOON
          To compile this driver as a module, choose M here: the
          module will be called radio-typhoon.
 
-config RADIO_TYPHOON_PROC_FS
-       bool "Support for /proc/radio-typhoon"
-       depends on PROC_FS && RADIO_TYPHOON
-       help
-         Say Y here if you want the typhoon radio card driver to write
-         status information (frequency, volume, muted, mute frequency,
-         base address) to /proc/radio-typhoon. The file can be viewed with
-         your favorite pager (i.e. use "more /proc/radio-typhoon" or "less
-         /proc/radio-typhoon" or simply "cat /proc/radio-typhoon").
-
 config RADIO_TYPHOON_PORT
        hex "Typhoon I/O port (0x316 or 0x336)"
        depends on RADIO_TYPHOON=y
@@ -339,6 +329,29 @@ config RADIO_ZOLTRIX_PORT
        help
          Enter the I/O port of your Zoltrix radio card.
 
+config I2C_SI4713
+       tristate "I2C driver for Silicon Labs Si4713 device"
+       depends on I2C && VIDEO_V4L2
+       ---help---
+         Say Y here if you want support to Si4713 I2C device.
+         This device driver supports only i2c bus.
+
+         To compile this driver as a module, choose M here: the
+         module will be called si4713.
+
+config RADIO_SI4713
+       tristate "Silicon Labs Si4713 FM Radio Transmitter support"
+       depends on I2C && VIDEO_V4L2
+       select I2C_SI4713
+       ---help---
+         Say Y here if you want support to Si4713 FM Radio Transmitter.
+         This device can transmit audio through FM. It can transmit
+         EDS and EBDS signals as well. This module is the v4l2 radio
+         interface for the i2c driver of this device.
+
+         To compile this driver as a module, choose M here: the
+         module will be called radio-si4713.
+
 config USB_DSBR
        tristate "D-Link/GemTek USB FM radio support"
        depends on USB && VIDEO_V4L2
@@ -351,29 +364,11 @@ config USB_DSBR
          To compile this driver as a module, choose M here: the
          module will be called dsbr100.
 
-config USB_SI470X
-       tristate "Silicon Labs Si470x FM Radio Receiver support"
-       depends on USB && VIDEO_V4L2
-       ---help---
-         This is a driver for USB devices with the Silicon Labs SI470x
-         chip. Currently these devices are known to work:
-         - 10c4:818a: Silicon Labs USB FM Radio Reference Design
-         - 06e1:a155: ADS/Tech FM Radio Receiver (formerly Instant FM Music)
-         - 1b80:d700: KWorld USB FM Radio SnapMusic Mobile 700 (FM700)
-
-         Sound is provided by the ALSA USB Audio/MIDI driver. Therefore
-         if you don't want to use the device solely for RDS receiving,
-         it is recommended to also select SND_USB_AUDIO.
-
-         Please have a look at the documentation, especially on how
-         to redirect the audio stream from the radio to your sound device:
-         Documentation/video4linux/si470x.txt
-
-         Say Y here if you want to connect this type of radio to your
-         computer's USB port.
+config RADIO_SI470X
+       bool "Silicon Labs Si470x FM Radio Receiver support"
+       depends on VIDEO_V4L2
 
-         To compile this driver as a module, choose M here: the
-         module will be called radio-si470x.
+source "drivers/media/radio/si470x/Kconfig"
 
 config USB_MR800
        tristate "AverMedia MR 800 USB FM radio support"
index 0f2b35b3e5608a2fdb5a19d6ea78f12f5b3f5791..2a1be3bf4f7c92470db75c3acac1fcff6c246ad8 100644 (file)
@@ -15,9 +15,11 @@ obj-$(CONFIG_RADIO_ZOLTRIX) += radio-zoltrix.o
 obj-$(CONFIG_RADIO_GEMTEK) += radio-gemtek.o
 obj-$(CONFIG_RADIO_GEMTEK_PCI) += radio-gemtek-pci.o
 obj-$(CONFIG_RADIO_TRUST) += radio-trust.o
+obj-$(CONFIG_I2C_SI4713) += si4713-i2c.o
+obj-$(CONFIG_RADIO_SI4713) += radio-si4713.o
 obj-$(CONFIG_RADIO_MAESTRO) += radio-maestro.o
 obj-$(CONFIG_USB_DSBR) += dsbr100.o
-obj-$(CONFIG_USB_SI470X) += radio-si470x.o
+obj-$(CONFIG_RADIO_SI470X) += si470x/
 obj-$(CONFIG_USB_MR800) += radio-mr800.o
 obj-$(CONFIG_RADIO_TEA5764) += radio-tea5764.o
 
index d30fc0ce82c08f093dc48d13052994eaedafbc87..8b1440136c45b10710079bdbf2e80fba7f166978 100644 (file)
@@ -359,7 +359,8 @@ static int vidioc_querycap(struct file *file, void *priv,
        strlcpy(v->card, "ADS Cadet", sizeof(v->card));
        strlcpy(v->bus_info, "ISA", sizeof(v->bus_info));
        v->version = CADET_VERSION;
-       v->capabilities = V4L2_CAP_TUNER | V4L2_CAP_RADIO | V4L2_CAP_READWRITE;
+       v->capabilities = V4L2_CAP_TUNER | V4L2_CAP_RADIO |
+                         V4L2_CAP_READWRITE | V4L2_CAP_RDS_CAPTURE;
        return 0;
 }
 
@@ -372,7 +373,7 @@ static int vidioc_g_tuner(struct file *file, void *priv,
        switch (v->index) {
        case 0:
                strlcpy(v->name, "FM", sizeof(v->name));
-               v->capability = V4L2_TUNER_CAP_STEREO;
+               v->capability = V4L2_TUNER_CAP_STEREO | V4L2_TUNER_CAP_RDS;
                v->rangelow = 1400;     /* 87.5 MHz */
                v->rangehigh = 1728;    /* 108.0 MHz */
                v->rxsubchans = cadet_getstereo(dev);
@@ -386,6 +387,7 @@ static int vidioc_g_tuner(struct file *file, void *priv,
                default:
                        break;
                }
+               v->rxsubchans |= V4L2_TUNER_SUB_RDS;
                break;
        case 1:
                strlcpy(v->name, "AM", sizeof(v->name));
diff --git a/drivers/media/radio/radio-si470x.c b/drivers/media/radio/radio-si470x.c
deleted file mode 100644 (file)
index e85f318..0000000
+++ /dev/null
@@ -1,1863 +0,0 @@
-/*
- *  drivers/media/radio/radio-si470x.c
- *
- *  Driver for USB radios for the Silicon Labs Si470x FM Radio Receivers:
- *   - Silicon Labs USB FM Radio Reference Design
- *   - ADS/Tech FM Radio Receiver (formerly Instant FM Music) (RDX-155-EF)
- *   - KWorld USB FM Radio SnapMusic Mobile 700 (FM700)
- *   - Sanei Electric, Inc. FM USB Radio (sold as DealExtreme.com PCear)
- *
- *  Copyright (c) 2009 Tobias Lorenz <tobias.lorenz@gmx.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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- */
-
-
-/*
- * History:
- * 2008-01-12  Tobias Lorenz <tobias.lorenz@gmx.net>
- *             Version 1.0.0
- *             - First working version
- * 2008-01-13  Tobias Lorenz <tobias.lorenz@gmx.net>
- *             Version 1.0.1
- *             - Improved error handling, every function now returns errno
- *             - Improved multi user access (start/mute/stop)
- *             - Channel doesn't get lost anymore after start/mute/stop
- *             - RDS support added (polling mode via interrupt EP 1)
- *             - marked default module parameters with *value*
- *             - switched from bit structs to bit masks
- *             - header file cleaned and integrated
- * 2008-01-14  Tobias Lorenz <tobias.lorenz@gmx.net>
- *             Version 1.0.2
- *             - hex values are now lower case
- *             - commented USB ID for ADS/Tech moved on todo list
- *             - blacklisted si470x in hid-quirks.c
- *             - rds buffer handling functions integrated into *_work, *_read
- *             - rds_command in si470x_poll exchanged against simple retval
- *             - check for firmware version 15
- *             - code order and prototypes still remain the same
- *             - spacing and bottom of band codes remain the same
- * 2008-01-16  Tobias Lorenz <tobias.lorenz@gmx.net>
- *             Version 1.0.3
- *             - code reordered to avoid function prototypes
- *             - switch/case defaults are now more user-friendly
- *             - unified comment style
- *             - applied all checkpatch.pl v1.12 suggestions
- *               except the warning about the too long lines with bit comments
- *             - renamed FMRADIO to RADIO to cut line length (checkpatch.pl)
- * 2008-01-22  Tobias Lorenz <tobias.lorenz@gmx.net>
- *             Version 1.0.4
- *             - avoid poss. locking when doing copy_to_user which may sleep
- *             - RDS is automatically activated on read now
- *             - code cleaned of unnecessary rds_commands
- *             - USB Vendor/Product ID for ADS/Tech FM Radio Receiver verified
- *               (thanks to Guillaume RAMOUSSE)
- * 2008-01-27  Tobias Lorenz <tobias.lorenz@gmx.net>
- *             Version 1.0.5
- *             - number of seek_retries changed to tune_timeout
- *             - fixed problem with incomplete tune operations by own buffers
- *             - optimization of variables and printf types
- *             - improved error logging
- * 2008-01-31  Tobias Lorenz <tobias.lorenz@gmx.net>
- *             Oliver Neukum <oliver@neukum.org>
- *             Version 1.0.6
- *             - fixed coverity checker warnings in *_usb_driver_disconnect
- *             - probe()/open() race by correct ordering in probe()
- *             - DMA coherency rules by separate allocation of all buffers
- *             - use of endianness macros
- *             - abuse of spinlock, replaced by mutex
- *             - racy handling of timer in disconnect,
- *               replaced by delayed_work
- *             - racy interruptible_sleep_on(),
- *               replaced with wait_event_interruptible()
- *             - handle signals in read()
- * 2008-02-08  Tobias Lorenz <tobias.lorenz@gmx.net>
- *             Oliver Neukum <oliver@neukum.org>
- *             Version 1.0.7
- *             - usb autosuspend support
- *             - unplugging fixed
- * 2008-05-07  Tobias Lorenz <tobias.lorenz@gmx.net>
- *             Version 1.0.8
- *             - hardware frequency seek support
- *             - afc indication
- *             - more safety checks, let si470x_get_freq return errno
- *             - vidioc behavior corrected according to v4l2 spec
- * 2008-10-20  Alexey Klimov <klimov.linux@gmail.com>
- *             - add support for KWorld USB FM Radio FM700
- *             - blacklisted KWorld radio in hid-core.c and hid-ids.h
- * 2008-12-03  Mark Lord <mlord@pobox.com>
- *             - add support for DealExtreme USB Radio
- * 2009-01-31  Bob Ross <pigiron@gmx.com>
- *             - correction of stereo detection/setting
- *             - correction of signal strength indicator scaling
- * 2009-01-31  Rick Bronson <rick@efn.org>
- *             Tobias Lorenz <tobias.lorenz@gmx.net>
- *             - add LED status output
- *             - get HW/SW version from scratchpad
- *
- * ToDo:
- * - add firmware download/update support
- * - RDS support: interrupt mode, instead of polling
- */
-
-
-/* driver definitions */
-#define DRIVER_AUTHOR "Tobias Lorenz <tobias.lorenz@gmx.net>"
-#define DRIVER_NAME "radio-si470x"
-#define DRIVER_KERNEL_VERSION KERNEL_VERSION(1, 0, 9)
-#define DRIVER_CARD "Silicon Labs Si470x FM Radio Receiver"
-#define DRIVER_DESC "USB radio driver for Si470x FM Radio Receivers"
-#define DRIVER_VERSION "1.0.9"
-
-
-/* kernel includes */
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/init.h>
-#include <linux/slab.h>
-#include <linux/smp_lock.h>
-#include <linux/input.h>
-#include <linux/usb.h>
-#include <linux/hid.h>
-#include <linux/version.h>
-#include <linux/videodev2.h>
-#include <linux/mutex.h>
-#include <media/v4l2-common.h>
-#include <media/v4l2-ioctl.h>
-#include <media/rds.h>
-#include <asm/unaligned.h>
-
-
-/* USB Device ID List */
-static struct usb_device_id si470x_usb_driver_id_table[] = {
-       /* Silicon Labs USB FM Radio Reference Design */
-       { USB_DEVICE_AND_INTERFACE_INFO(0x10c4, 0x818a, USB_CLASS_HID, 0, 0) },
-       /* ADS/Tech FM Radio Receiver (formerly Instant FM Music) */
-       { USB_DEVICE_AND_INTERFACE_INFO(0x06e1, 0xa155, USB_CLASS_HID, 0, 0) },
-       /* KWorld USB FM Radio SnapMusic Mobile 700 (FM700) */
-       { USB_DEVICE_AND_INTERFACE_INFO(0x1b80, 0xd700, USB_CLASS_HID, 0, 0) },
-       /* Sanei Electric, Inc. FM USB Radio (sold as DealExtreme.com PCear) */
-       { USB_DEVICE_AND_INTERFACE_INFO(0x10c5, 0x819a, USB_CLASS_HID, 0, 0) },
-       /* Terminating entry */
-       { }
-};
-MODULE_DEVICE_TABLE(usb, si470x_usb_driver_id_table);
-
-
-
-/**************************************************************************
- * Module Parameters
- **************************************************************************/
-
-/* Radio Nr */
-static int radio_nr = -1;
-module_param(radio_nr, int, 0444);
-MODULE_PARM_DESC(radio_nr, "Radio Nr");
-
-/* Spacing (kHz) */
-/* 0: 200 kHz (USA, Australia) */
-/* 1: 100 kHz (Europe, Japan) */
-/* 2:  50 kHz */
-static unsigned short space = 2;
-module_param(space, ushort, 0444);
-MODULE_PARM_DESC(space, "Spacing: 0=200kHz 1=100kHz *2=50kHz*");
-
-/* Bottom of Band (MHz) */
-/* 0: 87.5 - 108 MHz (USA, Europe)*/
-/* 1: 76   - 108 MHz (Japan wide band) */
-/* 2: 76   -  90 MHz (Japan) */
-static unsigned short band = 1;
-module_param(band, ushort, 0444);
-MODULE_PARM_DESC(band, "Band: 0=87.5..108MHz *1=76..108MHz* 2=76..90MHz");
-
-/* De-emphasis */
-/* 0: 75 us (USA) */
-/* 1: 50 us (Europe, Australia, Japan) */
-static unsigned short de = 1;
-module_param(de, ushort, 0444);
-MODULE_PARM_DESC(de, "De-emphasis: 0=75us *1=50us*");
-
-/* USB timeout */
-static unsigned int usb_timeout = 500;
-module_param(usb_timeout, uint, 0644);
-MODULE_PARM_DESC(usb_timeout, "USB timeout (ms): *500*");
-
-/* Tune timeout */
-static unsigned int tune_timeout = 3000;
-module_param(tune_timeout, uint, 0644);
-MODULE_PARM_DESC(tune_timeout, "Tune timeout: *3000*");
-
-/* Seek timeout */
-static unsigned int seek_timeout = 5000;
-module_param(seek_timeout, uint, 0644);
-MODULE_PARM_DESC(seek_timeout, "Seek timeout: *5000*");
-
-/* RDS buffer blocks */
-static unsigned int rds_buf = 100;
-module_param(rds_buf, uint, 0444);
-MODULE_PARM_DESC(rds_buf, "RDS buffer entries: *100*");
-
-/* RDS maximum block errors */
-static unsigned short max_rds_errors = 1;
-/* 0 means   0  errors requiring correction */
-/* 1 means 1-2  errors requiring correction (used by original USBRadio.exe) */
-/* 2 means 3-5  errors requiring correction */
-/* 3 means   6+ errors or errors in checkword, correction not possible */
-module_param(max_rds_errors, ushort, 0644);
-MODULE_PARM_DESC(max_rds_errors, "RDS maximum block errors: *1*");
-
-/* RDS poll frequency */
-static unsigned int rds_poll_time = 40;
-/* 40 is used by the original USBRadio.exe */
-/* 50 is used by radio-cadet */
-/* 75 should be okay */
-/* 80 is the usual RDS receive interval */
-module_param(rds_poll_time, uint, 0644);
-MODULE_PARM_DESC(rds_poll_time, "RDS poll time (ms): *40*");
-
-
-
-/**************************************************************************
- * Register Definitions
- **************************************************************************/
-#define RADIO_REGISTER_SIZE    2       /* 16 register bit width */
-#define RADIO_REGISTER_NUM     16      /* DEVICEID   ... RDSD */
-#define RDS_REGISTER_NUM       6       /* STATUSRSSI ... RDSD */
-
-#define DEVICEID               0       /* Device ID */
-#define DEVICEID_PN            0xf000  /* bits 15..12: Part Number */
-#define DEVICEID_MFGID         0x0fff  /* bits 11..00: Manufacturer ID */
-
-#define CHIPID                 1       /* Chip ID */
-#define CHIPID_REV             0xfc00  /* bits 15..10: Chip Version */
-#define CHIPID_DEV             0x0200  /* bits 09..09: Device */
-#define CHIPID_FIRMWARE                0x01ff  /* bits 08..00: Firmware Version */
-
-#define POWERCFG               2       /* Power Configuration */
-#define POWERCFG_DSMUTE                0x8000  /* bits 15..15: Softmute Disable */
-#define POWERCFG_DMUTE         0x4000  /* bits 14..14: Mute Disable */
-#define POWERCFG_MONO          0x2000  /* bits 13..13: Mono Select */
-#define POWERCFG_RDSM          0x0800  /* bits 11..11: RDS Mode (Si4701 only) */
-#define POWERCFG_SKMODE                0x0400  /* bits 10..10: Seek Mode */
-#define POWERCFG_SEEKUP                0x0200  /* bits 09..09: Seek Direction */
-#define POWERCFG_SEEK          0x0100  /* bits 08..08: Seek */
-#define POWERCFG_DISABLE       0x0040  /* bits 06..06: Powerup Disable */
-#define POWERCFG_ENABLE                0x0001  /* bits 00..00: Powerup Enable */
-
-#define CHANNEL                        3       /* Channel */
-#define CHANNEL_TUNE           0x8000  /* bits 15..15: Tune */
-#define CHANNEL_CHAN           0x03ff  /* bits 09..00: Channel Select */
-
-#define SYSCONFIG1             4       /* System Configuration 1 */
-#define SYSCONFIG1_RDSIEN      0x8000  /* bits 15..15: RDS Interrupt Enable (Si4701 only) */
-#define SYSCONFIG1_STCIEN      0x4000  /* bits 14..14: Seek/Tune Complete Interrupt Enable */
-#define SYSCONFIG1_RDS         0x1000  /* bits 12..12: RDS Enable (Si4701 only) */
-#define SYSCONFIG1_DE          0x0800  /* bits 11..11: De-emphasis (0=75us 1=50us) */
-#define SYSCONFIG1_AGCD                0x0400  /* bits 10..10: AGC Disable */
-#define SYSCONFIG1_BLNDADJ     0x00c0  /* bits 07..06: Stereo/Mono Blend Level Adjustment */
-#define SYSCONFIG1_GPIO3       0x0030  /* bits 05..04: General Purpose I/O 3 */
-#define SYSCONFIG1_GPIO2       0x000c  /* bits 03..02: General Purpose I/O 2 */
-#define SYSCONFIG1_GPIO1       0x0003  /* bits 01..00: General Purpose I/O 1 */
-
-#define SYSCONFIG2             5       /* System Configuration 2 */
-#define SYSCONFIG2_SEEKTH      0xff00  /* bits 15..08: RSSI Seek Threshold */
-#define SYSCONFIG2_BAND                0x0080  /* bits 07..06: Band Select */
-#define SYSCONFIG2_SPACE       0x0030  /* bits 05..04: Channel Spacing */
-#define SYSCONFIG2_VOLUME      0x000f  /* bits 03..00: Volume */
-
-#define SYSCONFIG3             6       /* System Configuration 3 */
-#define SYSCONFIG3_SMUTER      0xc000  /* bits 15..14: Softmute Attack/Recover Rate */
-#define SYSCONFIG3_SMUTEA      0x3000  /* bits 13..12: Softmute Attenuation */
-#define SYSCONFIG3_SKSNR       0x00f0  /* bits 07..04: Seek SNR Threshold */
-#define SYSCONFIG3_SKCNT       0x000f  /* bits 03..00: Seek FM Impulse Detection Threshold */
-
-#define TEST1                  7       /* Test 1 */
-#define TEST1_AHIZEN           0x4000  /* bits 14..14: Audio High-Z Enable */
-
-#define TEST2                  8       /* Test 2 */
-/* TEST2 only contains reserved bits */
-
-#define BOOTCONFIG             9       /* Boot Configuration */
-/* BOOTCONFIG only contains reserved bits */
-
-#define STATUSRSSI             10      /* Status RSSI */
-#define STATUSRSSI_RDSR                0x8000  /* bits 15..15: RDS Ready (Si4701 only) */
-#define STATUSRSSI_STC         0x4000  /* bits 14..14: Seek/Tune Complete */
-#define STATUSRSSI_SF          0x2000  /* bits 13..13: Seek Fail/Band Limit */
-#define STATUSRSSI_AFCRL       0x1000  /* bits 12..12: AFC Rail */
-#define STATUSRSSI_RDSS                0x0800  /* bits 11..11: RDS Synchronized (Si4701 only) */
-#define STATUSRSSI_BLERA       0x0600  /* bits 10..09: RDS Block A Errors (Si4701 only) */
-#define STATUSRSSI_ST          0x0100  /* bits 08..08: Stereo Indicator */
-#define STATUSRSSI_RSSI                0x00ff  /* bits 07..00: RSSI (Received Signal Strength Indicator) */
-
-#define READCHAN               11      /* Read Channel */
-#define READCHAN_BLERB         0xc000  /* bits 15..14: RDS Block D Errors (Si4701 only) */
-#define READCHAN_BLERC         0x3000  /* bits 13..12: RDS Block C Errors (Si4701 only) */
-#define READCHAN_BLERD         0x0c00  /* bits 11..10: RDS Block B Errors (Si4701 only) */
-#define READCHAN_READCHAN      0x03ff  /* bits 09..00: Read Channel */
-
-#define RDSA                   12      /* RDSA */
-#define RDSA_RDSA              0xffff  /* bits 15..00: RDS Block A Data (Si4701 only) */
-
-#define RDSB                   13      /* RDSB */
-#define RDSB_RDSB              0xffff  /* bits 15..00: RDS Block B Data (Si4701 only) */
-
-#define RDSC                   14      /* RDSC */
-#define RDSC_RDSC              0xffff  /* bits 15..00: RDS Block C Data (Si4701 only) */
-
-#define RDSD                   15      /* RDSD */
-#define RDSD_RDSD              0xffff  /* bits 15..00: RDS Block D Data (Si4701 only) */
-
-
-
-/**************************************************************************
- * USB HID Reports
- **************************************************************************/
-
-/* Reports 1-16 give direct read/write access to the 16 Si470x registers */
-/* with the (REPORT_ID - 1) corresponding to the register address across USB */
-/* endpoint 0 using GET_REPORT and SET_REPORT */
-#define REGISTER_REPORT_SIZE   (RADIO_REGISTER_SIZE + 1)
-#define REGISTER_REPORT(reg)   ((reg) + 1)
-
-/* Report 17 gives direct read/write access to the entire Si470x register */
-/* map across endpoint 0 using GET_REPORT and SET_REPORT */
-#define ENTIRE_REPORT_SIZE     (RADIO_REGISTER_NUM * RADIO_REGISTER_SIZE + 1)
-#define ENTIRE_REPORT          17
-
-/* Report 18 is used to send the lowest 6 Si470x registers up the HID */
-/* interrupt endpoint 1 to Windows every 20 milliseconds for status */
-#define RDS_REPORT_SIZE                (RDS_REGISTER_NUM * RADIO_REGISTER_SIZE + 1)
-#define RDS_REPORT             18
-
-/* Report 19: LED state */
-#define LED_REPORT_SIZE                3
-#define LED_REPORT             19
-
-/* Report 19: stream */
-#define STREAM_REPORT_SIZE     3
-#define STREAM_REPORT          19
-
-/* Report 20: scratch */
-#define SCRATCH_PAGE_SIZE      63
-#define SCRATCH_REPORT_SIZE    (SCRATCH_PAGE_SIZE + 1)
-#define SCRATCH_REPORT         20
-
-/* Reports 19-22: flash upgrade of the C8051F321 */
-#define WRITE_REPORT_SIZE      4
-#define WRITE_REPORT           19
-#define FLASH_REPORT_SIZE      64
-#define FLASH_REPORT           20
-#define CRC_REPORT_SIZE                3
-#define CRC_REPORT             21
-#define RESPONSE_REPORT_SIZE   2
-#define RESPONSE_REPORT                22
-
-/* Report 23: currently unused, but can accept 60 byte reports on the HID */
-/* interrupt out endpoint 2 every 1 millisecond */
-#define UNUSED_REPORT          23
-
-
-
-/**************************************************************************
- * Software/Hardware Versions
- **************************************************************************/
-#define RADIO_SW_VERSION_NOT_BOOTLOADABLE      6
-#define RADIO_SW_VERSION                       7
-#define RADIO_SW_VERSION_CURRENT               15
-#define RADIO_HW_VERSION                       1
-
-#define SCRATCH_PAGE_SW_VERSION        1
-#define SCRATCH_PAGE_HW_VERSION        2
-
-
-
-/**************************************************************************
- * LED State Definitions
- **************************************************************************/
-#define LED_COMMAND            0x35
-
-#define NO_CHANGE_LED          0x00
-#define ALL_COLOR_LED          0x01    /* streaming state */
-#define BLINK_GREEN_LED                0x02    /* connect state */
-#define BLINK_RED_LED          0x04
-#define BLINK_ORANGE_LED       0x10    /* disconnect state */
-#define SOLID_GREEN_LED                0x20    /* tuning/seeking state */
-#define SOLID_RED_LED          0x40    /* bootload state */
-#define SOLID_ORANGE_LED       0x80
-
-
-
-/**************************************************************************
- * Stream State Definitions
- **************************************************************************/
-#define STREAM_COMMAND 0x36
-#define STREAM_VIDPID  0x00
-#define STREAM_AUDIO   0xff
-
-
-
-/**************************************************************************
- * Bootloader / Flash Commands
- **************************************************************************/
-
-/* unique id sent to bootloader and required to put into a bootload state */
-#define UNIQUE_BL_ID           0x34
-
-/* mask for the flash data */
-#define FLASH_DATA_MASK                0x55
-
-/* bootloader commands */
-#define GET_SW_VERSION_COMMAND 0x00
-#define SET_PAGE_COMMAND       0x01
-#define ERASE_PAGE_COMMAND     0x02
-#define WRITE_PAGE_COMMAND     0x03
-#define CRC_ON_PAGE_COMMAND    0x04
-#define READ_FLASH_BYTE_COMMAND        0x05
-#define RESET_DEVICE_COMMAND   0x06
-#define GET_HW_VERSION_COMMAND 0x07
-#define BLANK                  0xff
-
-/* bootloader command responses */
-#define COMMAND_OK             0x01
-#define COMMAND_FAILED         0x02
-#define COMMAND_PENDING                0x03
-
-
-
-/**************************************************************************
- * General Driver Definitions
- **************************************************************************/
-
-/*
- * si470x_device - private data
- */
-struct si470x_device {
-       /* reference to USB and video device */
-       struct usb_device *usbdev;
-       struct usb_interface *intf;
-       struct video_device *videodev;
-
-       /* driver management */
-       unsigned int users;
-       unsigned char disconnected;
-       struct mutex disconnect_lock;
-
-       /* Silabs internal registers (0..15) */
-       unsigned short registers[RADIO_REGISTER_NUM];
-
-       /* RDS receive buffer */
-       struct delayed_work work;
-       wait_queue_head_t read_queue;
-       struct mutex lock;              /* buffer locking */
-       unsigned char *buffer;          /* size is always multiple of three */
-       unsigned int buf_size;
-       unsigned int rd_index;
-       unsigned int wr_index;
-
-       /* scratch page */
-       unsigned char software_version;
-       unsigned char hardware_version;
-};
-
-
-/*
- * The frequency is set in units of 62.5 Hz when using V4L2_TUNER_CAP_LOW,
- * 62.5 kHz otherwise.
- * The tuner is able to have a channel spacing of 50, 100 or 200 kHz.
- * tuner->capability is therefore set to V4L2_TUNER_CAP_LOW
- * The FREQ_MUL is then: 1 MHz / 62.5 Hz = 16000
- */
-#define FREQ_MUL (1000000 / 62.5)
-
-
-
-/**************************************************************************
- * General Driver Functions - REGISTER_REPORTs
- **************************************************************************/
-
-/*
- * si470x_get_report - receive a HID report
- */
-static int si470x_get_report(struct si470x_device *radio, void *buf, int size)
-{
-       unsigned char *report = (unsigned char *) buf;
-       int retval;
-
-       retval = usb_control_msg(radio->usbdev,
-               usb_rcvctrlpipe(radio->usbdev, 0),
-               HID_REQ_GET_REPORT,
-               USB_TYPE_CLASS | USB_RECIP_INTERFACE | USB_DIR_IN,
-               report[0], 2,
-               buf, size, usb_timeout);
-
-       if (retval < 0)
-               printk(KERN_WARNING DRIVER_NAME
-                       ": si470x_get_report: usb_control_msg returned %d\n",
-                       retval);
-       return retval;
-}
-
-
-/*
- * si470x_set_report - send a HID report
- */
-static int si470x_set_report(struct si470x_device *radio, void *buf, int size)
-{
-       unsigned char *report = (unsigned char *) buf;
-       int retval;
-
-       retval = usb_control_msg(radio->usbdev,
-               usb_sndctrlpipe(radio->usbdev, 0),
-               HID_REQ_SET_REPORT,
-               USB_TYPE_CLASS | USB_RECIP_INTERFACE | USB_DIR_OUT,
-               report[0], 2,
-               buf, size, usb_timeout);
-
-       if (retval < 0)
-               printk(KERN_WARNING DRIVER_NAME
-                       ": si470x_set_report: usb_control_msg returned %d\n",
-                       retval);
-       return retval;
-}
-
-
-/*
- * si470x_get_register - read register
- */
-static int si470x_get_register(struct si470x_device *radio, int regnr)
-{
-       unsigned char buf[REGISTER_REPORT_SIZE];
-       int retval;
-
-       buf[0] = REGISTER_REPORT(regnr);
-
-       retval = si470x_get_report(radio, (void *) &buf, sizeof(buf));
-
-       if (retval >= 0)
-               radio->registers[regnr] = get_unaligned_be16(&buf[1]);
-
-       return (retval < 0) ? -EINVAL : 0;
-}
-
-
-/*
- * si470x_set_register - write register
- */
-static int si470x_set_register(struct si470x_device *radio, int regnr)
-{
-       unsigned char buf[REGISTER_REPORT_SIZE];
-       int retval;
-
-       buf[0] = REGISTER_REPORT(regnr);
-       put_unaligned_be16(radio->registers[regnr], &buf[1]);
-
-       retval = si470x_set_report(radio, (void *) &buf, sizeof(buf));
-
-       return (retval < 0) ? -EINVAL : 0;
-}
-
-
-/*
- * si470x_set_chan - set the channel
- */
-static int si470x_set_chan(struct si470x_device *radio, unsigned short chan)
-{
-       int retval;
-       unsigned long timeout;
-       bool timed_out = 0;
-
-       /* start tuning */
-       radio->registers[CHANNEL] &= ~CHANNEL_CHAN;
-       radio->registers[CHANNEL] |= CHANNEL_TUNE | chan;
-       retval = si470x_set_register(radio, CHANNEL);
-       if (retval < 0)
-               goto done;
-
-       /* wait till tune operation has completed */
-       timeout = jiffies + msecs_to_jiffies(tune_timeout);
-       do {
-               retval = si470x_get_register(radio, STATUSRSSI);
-               if (retval < 0)
-                       goto stop;
-               timed_out = time_after(jiffies, timeout);
-       } while (((radio->registers[STATUSRSSI] & STATUSRSSI_STC) == 0) &&
-               (!timed_out));
-       if ((radio->registers[STATUSRSSI] & STATUSRSSI_STC) == 0)
-               printk(KERN_WARNING DRIVER_NAME ": tune does not complete\n");
-       if (timed_out)
-               printk(KERN_WARNING DRIVER_NAME
-                       ": tune timed out after %u ms\n", tune_timeout);
-
-stop:
-       /* stop tuning */
-       radio->registers[CHANNEL] &= ~CHANNEL_TUNE;
-       retval = si470x_set_register(radio, CHANNEL);
-
-done:
-       return retval;
-}
-
-
-/*
- * si470x_get_freq - get the frequency
- */
-static int si470x_get_freq(struct si470x_device *radio, unsigned int *freq)
-{
-       unsigned int spacing, band_bottom;
-       unsigned short chan;
-       int retval;
-
-       /* Spacing (kHz) */
-       switch ((radio->registers[SYSCONFIG2] & SYSCONFIG2_SPACE) >> 4) {
-       /* 0: 200 kHz (USA, Australia) */
-       case 0:
-               spacing = 0.200 * FREQ_MUL; break;
-       /* 1: 100 kHz (Europe, Japan) */
-       case 1:
-               spacing = 0.100 * FREQ_MUL; break;
-       /* 2:  50 kHz */
-       default:
-               spacing = 0.050 * FREQ_MUL; break;
-       };
-
-       /* Bottom of Band (MHz) */
-       switch ((radio->registers[SYSCONFIG2] & SYSCONFIG2_BAND) >> 6) {
-       /* 0: 87.5 - 108 MHz (USA, Europe) */
-       case 0:
-               band_bottom = 87.5 * FREQ_MUL; break;
-       /* 1: 76   - 108 MHz (Japan wide band) */
-       default:
-               band_bottom = 76   * FREQ_MUL; break;
-       /* 2: 76   -  90 MHz (Japan) */
-       case 2:
-               band_bottom = 76   * FREQ_MUL; break;
-       };
-
-       /* read channel */
-       retval = si470x_get_register(radio, READCHAN);
-       chan = radio->registers[READCHAN] & READCHAN_READCHAN;
-
-       /* Frequency (MHz) = Spacing (kHz) x Channel + Bottom of Band (MHz) */
-       *freq = chan * spacing + band_bottom;
-
-       return retval;
-}
-
-
-/*
- * si470x_set_freq - set the frequency
- */
-static int si470x_set_freq(struct si470x_device *radio, unsigned int freq)
-{
-       unsigned int spacing, band_bottom;
-       unsigned short chan;
-
-       /* Spacing (kHz) */
-       switch ((radio->registers[SYSCONFIG2] & SYSCONFIG2_SPACE) >> 4) {
-       /* 0: 200 kHz (USA, Australia) */
-       case 0:
-               spacing = 0.200 * FREQ_MUL; break;
-       /* 1: 100 kHz (Europe, Japan) */
-       case 1:
-               spacing = 0.100 * FREQ_MUL; break;
-       /* 2:  50 kHz */
-       default:
-               spacing = 0.050 * FREQ_MUL; break;
-       };
-
-       /* Bottom of Band (MHz) */
-       switch ((radio->registers[SYSCONFIG2] & SYSCONFIG2_BAND) >> 6) {
-       /* 0: 87.5 - 108 MHz (USA, Europe) */
-       case 0:
-               band_bottom = 87.5 * FREQ_MUL; break;
-       /* 1: 76   - 108 MHz (Japan wide band) */
-       default:
-               band_bottom = 76   * FREQ_MUL; break;
-       /* 2: 76   -  90 MHz (Japan) */
-       case 2:
-               band_bottom = 76   * FREQ_MUL; break;
-       };
-
-       /* Chan = [ Freq (Mhz) - Bottom of Band (MHz) ] / Spacing (kHz) */
-       chan = (freq - band_bottom) / spacing;
-
-       return si470x_set_chan(radio, chan);
-}
-
-
-/*
- * si470x_set_seek - set seek
- */
-static int si470x_set_seek(struct si470x_device *radio,
-               unsigned int wrap_around, unsigned int seek_upward)
-{
-       int retval = 0;
-       unsigned long timeout;
-       bool timed_out = 0;
-
-       /* start seeking */
-       radio->registers[POWERCFG] |= POWERCFG_SEEK;
-       if (wrap_around == 1)
-               radio->registers[POWERCFG] &= ~POWERCFG_SKMODE;
-       else
-               radio->registers[POWERCFG] |= POWERCFG_SKMODE;
-       if (seek_upward == 1)
-               radio->registers[POWERCFG] |= POWERCFG_SEEKUP;
-       else
-               radio->registers[POWERCFG] &= ~POWERCFG_SEEKUP;
-       retval = si470x_set_register(radio, POWERCFG);
-       if (retval < 0)
-               goto done;
-
-       /* wait till seek operation has completed */
-       timeout = jiffies + msecs_to_jiffies(seek_timeout);
-       do {
-               retval = si470x_get_register(radio, STATUSRSSI);
-               if (retval < 0)
-                       goto stop;
-               timed_out = time_after(jiffies, timeout);
-       } while (((radio->registers[STATUSRSSI] & STATUSRSSI_STC) == 0) &&
-               (!timed_out));
-       if ((radio->registers[STATUSRSSI] & STATUSRSSI_STC) == 0)
-               printk(KERN_WARNING DRIVER_NAME ": seek does not complete\n");
-       if (radio->registers[STATUSRSSI] & STATUSRSSI_SF)
-               printk(KERN_WARNING DRIVER_NAME
-                       ": seek failed / band limit reached\n");
-       if (timed_out)
-               printk(KERN_WARNING DRIVER_NAME
-                       ": seek timed out after %u ms\n", seek_timeout);
-
-stop:
-       /* stop seeking */
-       radio->registers[POWERCFG] &= ~POWERCFG_SEEK;
-       retval = si470x_set_register(radio, POWERCFG);
-
-done:
-       /* try again, if timed out */
-       if ((retval == 0) && timed_out)
-               retval = -EAGAIN;
-
-       return retval;
-}
-
-
-/*
- * si470x_start - switch on radio
- */
-static int si470x_start(struct si470x_device *radio)
-{
-       int retval;
-
-       /* powercfg */
-       radio->registers[POWERCFG] =
-               POWERCFG_DMUTE | POWERCFG_ENABLE | POWERCFG_RDSM;
-       retval = si470x_set_register(radio, POWERCFG);
-       if (retval < 0)
-               goto done;
-
-       /* sysconfig 1 */
-       radio->registers[SYSCONFIG1] = SYSCONFIG1_DE;
-       retval = si470x_set_register(radio, SYSCONFIG1);
-       if (retval < 0)
-               goto done;
-
-       /* sysconfig 2 */
-       radio->registers[SYSCONFIG2] =
-               (0x3f  << 8) |                          /* SEEKTH */
-               ((band  << 6) & SYSCONFIG2_BAND)  |     /* BAND */
-               ((space << 4) & SYSCONFIG2_SPACE) |     /* SPACE */
-               15;                                     /* VOLUME (max) */
-       retval = si470x_set_register(radio, SYSCONFIG2);
-       if (retval < 0)
-               goto done;
-
-       /* reset last channel */
-       retval = si470x_set_chan(radio,
-               radio->registers[CHANNEL] & CHANNEL_CHAN);
-
-done:
-       return retval;
-}
-
-
-/*
- * si470x_stop - switch off radio
- */
-static int si470x_stop(struct si470x_device *radio)
-{
-       int retval;
-
-       /* sysconfig 1 */
-       radio->registers[SYSCONFIG1] &= ~SYSCONFIG1_RDS;
-       retval = si470x_set_register(radio, SYSCONFIG1);
-       if (retval < 0)
-               goto done;
-
-       /* powercfg */
-       radio->registers[POWERCFG] &= ~POWERCFG_DMUTE;
-       /* POWERCFG_ENABLE has to automatically go low */
-       radio->registers[POWERCFG] |= POWERCFG_ENABLE | POWERCFG_DISABLE;
-       retval = si470x_set_register(radio, POWERCFG);
-
-done:
-       return retval;
-}
-
-
-/*
- * si470x_rds_on - switch on rds reception
- */
-static int si470x_rds_on(struct si470x_device *radio)
-{
-       int retval;
-
-       /* sysconfig 1 */
-       mutex_lock(&radio->lock);
-       radio->registers[SYSCONFIG1] |= SYSCONFIG1_RDS;
-       retval = si470x_set_register(radio, SYSCONFIG1);
-       if (retval < 0)
-               radio->registers[SYSCONFIG1] &= ~SYSCONFIG1_RDS;
-       mutex_unlock(&radio->lock);
-
-       return retval;
-}
-
-
-
-/**************************************************************************
- * General Driver Functions - ENTIRE_REPORT
- **************************************************************************/
-
-/*
- * si470x_get_all_registers - read entire registers
- */
-static int si470x_get_all_registers(struct si470x_device *radio)
-{
-       unsigned char buf[ENTIRE_REPORT_SIZE];
-       int retval;
-       unsigned char regnr;
-
-       buf[0] = ENTIRE_REPORT;
-
-       retval = si470x_get_report(radio, (void *) &buf, sizeof(buf));
-
-       if (retval >= 0)
-               for (regnr = 0; regnr < RADIO_REGISTER_NUM; regnr++)
-                       radio->registers[regnr] = get_unaligned_be16(
-                               &buf[regnr * RADIO_REGISTER_SIZE + 1]);
-
-       return (retval < 0) ? -EINVAL : 0;
-}
-
-
-
-/**************************************************************************
- * General Driver Functions - RDS_REPORT
- **************************************************************************/
-
-/*
- * si470x_get_rds_registers - read rds registers
- */
-static int si470x_get_rds_registers(struct si470x_device *radio)
-{
-       unsigned char buf[RDS_REPORT_SIZE];
-       int retval;
-       int size;
-       unsigned char regnr;
-
-       buf[0] = RDS_REPORT;
-
-       retval = usb_interrupt_msg(radio->usbdev,
-               usb_rcvintpipe(radio->usbdev, 1),
-               (void *) &buf, sizeof(buf), &size, usb_timeout);
-       if (size != sizeof(buf))
-               printk(KERN_WARNING DRIVER_NAME ": si470x_get_rds_registers: "
-                       "return size differs: %d != %zu\n", size, sizeof(buf));
-       if (retval < 0)
-               printk(KERN_WARNING DRIVER_NAME ": si470x_get_rds_registers: "
-                       "usb_interrupt_msg returned %d\n", retval);
-
-       if (retval >= 0)
-               for (regnr = 0; regnr < RDS_REGISTER_NUM; regnr++)
-                       radio->registers[STATUSRSSI + regnr] =
-                               get_unaligned_be16(
-                               &buf[regnr * RADIO_REGISTER_SIZE + 1]);
-
-       return (retval < 0) ? -EINVAL : 0;
-}
-
-
-
-/**************************************************************************
- * General Driver Functions - LED_REPORT
- **************************************************************************/
-
-/*
- * si470x_set_led_state - sets the led state
- */
-static int si470x_set_led_state(struct si470x_device *radio,
-               unsigned char led_state)
-{
-       unsigned char buf[LED_REPORT_SIZE];
-       int retval;
-
-       buf[0] = LED_REPORT;
-       buf[1] = LED_COMMAND;
-       buf[2] = led_state;
-
-       retval = si470x_set_report(radio, (void *) &buf, sizeof(buf));
-
-       return (retval < 0) ? -EINVAL : 0;
-}
-
-
-
-/**************************************************************************
- * General Driver Functions - SCRATCH_REPORT
- **************************************************************************/
-
-/*
- * si470x_get_scratch_versions - gets the scratch page and version infos
- */
-static int si470x_get_scratch_page_versions(struct si470x_device *radio)
-{
-       unsigned char buf[SCRATCH_REPORT_SIZE];
-       int retval;
-
-       buf[0] = SCRATCH_REPORT;
-
-       retval = si470x_get_report(radio, (void *) &buf, sizeof(buf));
-
-       if (retval < 0)
-               printk(KERN_WARNING DRIVER_NAME ": si470x_get_scratch: "
-                       "si470x_get_report returned %d\n", retval);
-       else {
-               radio->software_version = buf[1];
-               radio->hardware_version = buf[2];
-       }
-
-       return (retval < 0) ? -EINVAL : 0;
-}
-
-
-
-/**************************************************************************
- * RDS Driver Functions
- **************************************************************************/
-
-/*
- * si470x_rds - rds processing function
- */
-static void si470x_rds(struct si470x_device *radio)
-{
-       unsigned char blocknum;
-       unsigned short bler; /* rds block errors */
-       unsigned short rds;
-       unsigned char tmpbuf[3];
-
-       /* get rds blocks */
-       if (si470x_get_rds_registers(radio) < 0)
-               return;
-       if ((radio->registers[STATUSRSSI] & STATUSRSSI_RDSR) == 0) {
-               /* No RDS group ready */
-               return;
-       }
-       if ((radio->registers[STATUSRSSI] & STATUSRSSI_RDSS) == 0) {
-               /* RDS decoder not synchronized */
-               return;
-       }
-
-       /* copy all four RDS blocks to internal buffer */
-       mutex_lock(&radio->lock);
-       for (blocknum = 0; blocknum < 4; blocknum++) {
-               switch (blocknum) {
-               default:
-                       bler = (radio->registers[STATUSRSSI] &
-                                       STATUSRSSI_BLERA) >> 9;
-                       rds = radio->registers[RDSA];
-                       break;
-               case 1:
-                       bler = (radio->registers[READCHAN] &
-                                       READCHAN_BLERB) >> 14;
-                       rds = radio->registers[RDSB];
-                       break;
-               case 2:
-                       bler = (radio->registers[READCHAN] &
-                                       READCHAN_BLERC) >> 12;
-                       rds = radio->registers[RDSC];
-                       break;
-               case 3:
-                       bler = (radio->registers[READCHAN] &
-                                       READCHAN_BLERD) >> 10;
-                       rds = radio->registers[RDSD];
-                       break;
-               };
-
-               /* Fill the V4L2 RDS buffer */
-               put_unaligned_le16(rds, &tmpbuf);
-               tmpbuf[2] = blocknum;           /* offset name */
-               tmpbuf[2] |= blocknum << 3;     /* received offset */
-               if (bler > max_rds_errors)
-                       tmpbuf[2] |= 0x80; /* uncorrectable errors */
-               else if (bler > 0)
-                       tmpbuf[2] |= 0x40; /* corrected error(s) */
-
-               /* copy RDS block to internal buffer */
-               memcpy(&radio->buffer[radio->wr_index], &tmpbuf, 3);
-               radio->wr_index += 3;
-
-               /* wrap write pointer */
-               if (radio->wr_index >= radio->buf_size)
-                       radio->wr_index = 0;
-
-               /* check for overflow */
-               if (radio->wr_index == radio->rd_index) {
-                       /* increment and wrap read pointer */
-                       radio->rd_index += 3;
-                       if (radio->rd_index >= radio->buf_size)
-                               radio->rd_index = 0;
-               }
-       }
-       mutex_unlock(&radio->lock);
-
-       /* wake up read queue */
-       if (radio->wr_index != radio->rd_index)
-               wake_up_interruptible(&radio->read_queue);
-}
-
-
-/*
- * si470x_work - rds work function
- */
-static void si470x_work(struct work_struct *work)
-{
-       struct si470x_device *radio = container_of(work, struct si470x_device,
-               work.work);
-
-       /* safety checks */
-       if (radio->disconnected)
-               return;
-       if ((radio->registers[SYSCONFIG1] & SYSCONFIG1_RDS) == 0)
-               return;
-
-       si470x_rds(radio);
-       schedule_delayed_work(&radio->work, msecs_to_jiffies(rds_poll_time));
-}
-
-
-
-/**************************************************************************
- * File Operations Interface
- **************************************************************************/
-
-/*
- * si470x_fops_read - read RDS data
- */
-static ssize_t si470x_fops_read(struct file *file, char __user *buf,
-               size_t count, loff_t *ppos)
-{
-       struct si470x_device *radio = video_drvdata(file);
-       int retval = 0;
-       unsigned int block_count = 0;
-
-       /* switch on rds reception */
-       if ((radio->registers[SYSCONFIG1] & SYSCONFIG1_RDS) == 0) {
-               si470x_rds_on(radio);
-               schedule_delayed_work(&radio->work,
-                       msecs_to_jiffies(rds_poll_time));
-       }
-
-       /* block if no new data available */
-       while (radio->wr_index == radio->rd_index) {
-               if (file->f_flags & O_NONBLOCK) {
-                       retval = -EWOULDBLOCK;
-                       goto done;
-               }
-               if (wait_event_interruptible(radio->read_queue,
-                       radio->wr_index != radio->rd_index) < 0) {
-                       retval = -EINTR;
-                       goto done;
-               }
-       }
-
-       /* calculate block count from byte count */
-       count /= 3;
-
-       /* copy RDS block out of internal buffer and to user buffer */
-       mutex_lock(&radio->lock);
-       while (block_count < count) {
-               if (radio->rd_index == radio->wr_index)
-                       break;
-
-               /* always transfer rds complete blocks */
-               if (copy_to_user(buf, &radio->buffer[radio->rd_index], 3))
-                       /* retval = -EFAULT; */
-                       break;
-
-               /* increment and wrap read pointer */
-               radio->rd_index += 3;
-               if (radio->rd_index >= radio->buf_size)
-                       radio->rd_index = 0;
-
-               /* increment counters */
-               block_count++;
-               buf += 3;
-               retval += 3;
-       }
-       mutex_unlock(&radio->lock);
-
-done:
-       return retval;
-}
-
-
-/*
- * si470x_fops_poll - poll RDS data
- */
-static unsigned int si470x_fops_poll(struct file *file,
-               struct poll_table_struct *pts)
-{
-       struct si470x_device *radio = video_drvdata(file);
-       int retval = 0;
-
-       /* switch on rds reception */
-       if ((radio->registers[SYSCONFIG1] & SYSCONFIG1_RDS) == 0) {
-               si470x_rds_on(radio);
-               schedule_delayed_work(&radio->work,
-                       msecs_to_jiffies(rds_poll_time));
-       }
-
-       poll_wait(file, &radio->read_queue, pts);
-
-       if (radio->rd_index != radio->wr_index)
-               retval = POLLIN | POLLRDNORM;
-
-       return retval;
-}
-
-
-/*
- * si470x_fops_open - file open
- */
-static int si470x_fops_open(struct file *file)
-{
-       struct si470x_device *radio = video_drvdata(file);
-       int retval;
-
-       lock_kernel();
-       radio->users++;
-
-       retval = usb_autopm_get_interface(radio->intf);
-       if (retval < 0) {
-               radio->users--;
-               retval = -EIO;
-               goto done;
-       }
-
-       if (radio->users == 1) {
-               /* start radio */
-               retval = si470x_start(radio);
-               if (retval < 0)
-                       usb_autopm_put_interface(radio->intf);
-       }
-
-done:
-       unlock_kernel();
-       return retval;
-}
-
-
-/*
- * si470x_fops_release - file release
- */
-static int si470x_fops_release(struct file *file)
-{
-       struct si470x_device *radio = video_drvdata(file);
-       int retval = 0;
-
-       /* safety check */
-       if (!radio) {
-               retval = -ENODEV;
-               goto done;
-       }
-
-       mutex_lock(&radio->disconnect_lock);
-       radio->users--;
-       if (radio->users == 0) {
-               if (radio->disconnected) {
-                       video_unregister_device(radio->videodev);
-                       kfree(radio->buffer);
-                       kfree(radio);
-                       goto unlock;
-               }
-
-               /* stop rds reception */
-               cancel_delayed_work_sync(&radio->work);
-
-               /* cancel read processes */
-               wake_up_interruptible(&radio->read_queue);
-
-               /* stop radio */
-               retval = si470x_stop(radio);
-               usb_autopm_put_interface(radio->intf);
-       }
-unlock:
-       mutex_unlock(&radio->disconnect_lock);
-done:
-       return retval;
-}
-
-
-/*
- * si470x_fops - file operations interface
- */
-static const struct v4l2_file_operations si470x_fops = {
-       .owner          = THIS_MODULE,
-       .read           = si470x_fops_read,
-       .poll           = si470x_fops_poll,
-       .ioctl          = video_ioctl2,
-       .open           = si470x_fops_open,
-       .release        = si470x_fops_release,
-};
-
-
-
-/**************************************************************************
- * Video4Linux Interface
- **************************************************************************/
-
-/*
- * si470x_v4l2_queryctrl - query control
- */
-static struct v4l2_queryctrl si470x_v4l2_queryctrl[] = {
-       {
-               .id             = V4L2_CID_AUDIO_VOLUME,
-               .type           = V4L2_CTRL_TYPE_INTEGER,
-               .name           = "Volume",
-               .minimum        = 0,
-               .maximum        = 15,
-               .step           = 1,
-               .default_value  = 15,
-       },
-       {
-               .id             = V4L2_CID_AUDIO_MUTE,
-               .type           = V4L2_CTRL_TYPE_BOOLEAN,
-               .name           = "Mute",
-               .minimum        = 0,
-               .maximum        = 1,
-               .step           = 1,
-               .default_value  = 1,
-       },
-};
-
-
-/*
- * si470x_vidioc_querycap - query device capabilities
- */
-static int si470x_vidioc_querycap(struct file *file, void *priv,
-               struct v4l2_capability *capability)
-{
-       struct si470x_device *radio = video_drvdata(file);
-
-       strlcpy(capability->driver, DRIVER_NAME, sizeof(capability->driver));
-       strlcpy(capability->card, DRIVER_CARD, sizeof(capability->card));
-       usb_make_path(radio->usbdev, capability->bus_info, sizeof(capability->bus_info));
-       capability->version = DRIVER_KERNEL_VERSION;
-       capability->capabilities = V4L2_CAP_HW_FREQ_SEEK |
-               V4L2_CAP_TUNER | V4L2_CAP_RADIO;
-
-       return 0;
-}
-
-
-/*
- * si470x_vidioc_queryctrl - enumerate control items
- */
-static int si470x_vidioc_queryctrl(struct file *file, void *priv,
-               struct v4l2_queryctrl *qc)
-{
-       unsigned char i = 0;
-       int retval = -EINVAL;
-
-       /* abort if qc->id is below V4L2_CID_BASE */
-       if (qc->id < V4L2_CID_BASE)
-               goto done;
-
-       /* search video control */
-       for (i = 0; i < ARRAY_SIZE(si470x_v4l2_queryctrl); i++) {
-               if (qc->id == si470x_v4l2_queryctrl[i].id) {
-                       memcpy(qc, &(si470x_v4l2_queryctrl[i]), sizeof(*qc));
-                       retval = 0; /* found */
-                       break;
-               }
-       }
-
-       /* disable unsupported base controls */
-       /* to satisfy kradio and such apps */
-       if ((retval == -EINVAL) && (qc->id < V4L2_CID_LASTP1)) {
-               qc->flags = V4L2_CTRL_FLAG_DISABLED;
-               retval = 0;
-       }
-
-done:
-       if (retval < 0)
-               printk(KERN_WARNING DRIVER_NAME
-                       ": query controls failed with %d\n", retval);
-       return retval;
-}
-
-
-/*
- * si470x_vidioc_g_ctrl - get the value of a control
- */
-static int si470x_vidioc_g_ctrl(struct file *file, void *priv,
-               struct v4l2_control *ctrl)
-{
-       struct si470x_device *radio = video_drvdata(file);
-       int retval = 0;
-
-       /* safety checks */
-       if (radio->disconnected) {
-               retval = -EIO;
-               goto done;
-       }
-
-       switch (ctrl->id) {
-       case V4L2_CID_AUDIO_VOLUME:
-               ctrl->value = radio->registers[SYSCONFIG2] &
-                               SYSCONFIG2_VOLUME;
-               break;
-       case V4L2_CID_AUDIO_MUTE:
-               ctrl->value = ((radio->registers[POWERCFG] &
-                               POWERCFG_DMUTE) == 0) ? 1 : 0;
-               break;
-       default:
-               retval = -EINVAL;
-       }
-
-done:
-       if (retval < 0)
-               printk(KERN_WARNING DRIVER_NAME
-                       ": get control failed with %d\n", retval);
-       return retval;
-}
-
-
-/*
- * si470x_vidioc_s_ctrl - set the value of a control
- */
-static int si470x_vidioc_s_ctrl(struct file *file, void *priv,
-               struct v4l2_control *ctrl)
-{
-       struct si470x_device *radio = video_drvdata(file);
-       int retval = 0;
-
-       /* safety checks */
-       if (radio->disconnected) {
-               retval = -EIO;
-               goto done;
-       }
-
-       switch (ctrl->id) {
-       case V4L2_CID_AUDIO_VOLUME:
-               radio->registers[SYSCONFIG2] &= ~SYSCONFIG2_VOLUME;
-               radio->registers[SYSCONFIG2] |= ctrl->value;
-               retval = si470x_set_register(radio, SYSCONFIG2);
-               break;
-       case V4L2_CID_AUDIO_MUTE:
-               if (ctrl->value == 1)
-                       radio->registers[POWERCFG] &= ~POWERCFG_DMUTE;
-               else
-                       radio->registers[POWERCFG] |= POWERCFG_DMUTE;
-               retval = si470x_set_register(radio, POWERCFG);
-               break;
-       default:
-               retval = -EINVAL;
-       }
-
-done:
-       if (retval < 0)
-               printk(KERN_WARNING DRIVER_NAME
-                       ": set control failed with %d\n", retval);
-       return retval;
-}
-
-
-/*
- * si470x_vidioc_g_audio - get audio attributes
- */
-static int si470x_vidioc_g_audio(struct file *file, void *priv,
-               struct v4l2_audio *audio)
-{
-       /* driver constants */
-       audio->index = 0;
-       strcpy(audio->name, "Radio");
-       audio->capability = V4L2_AUDCAP_STEREO;
-       audio->mode = 0;
-
-       return 0;
-}
-
-
-/*
- * si470x_vidioc_g_tuner - get tuner attributes
- */
-static int si470x_vidioc_g_tuner(struct file *file, void *priv,
-               struct v4l2_tuner *tuner)
-{
-       struct si470x_device *radio = video_drvdata(file);
-       int retval = 0;
-
-       /* safety checks */
-       if (radio->disconnected) {
-               retval = -EIO;
-               goto done;
-       }
-       if (tuner->index != 0) {
-               retval = -EINVAL;
-               goto done;
-       }
-
-       retval = si470x_get_register(radio, STATUSRSSI);
-       if (retval < 0)
-               goto done;
-
-       /* driver constants */
-       strcpy(tuner->name, "FM");
-       tuner->type = V4L2_TUNER_RADIO;
-       tuner->capability = V4L2_TUNER_CAP_LOW | V4L2_TUNER_CAP_STEREO;
-
-       /* range limits */
-       switch ((radio->registers[SYSCONFIG2] & SYSCONFIG2_BAND) >> 6) {
-       /* 0: 87.5 - 108 MHz (USA, Europe, default) */
-       default:
-               tuner->rangelow  =  87.5 * FREQ_MUL;
-               tuner->rangehigh = 108   * FREQ_MUL;
-               break;
-       /* 1: 76   - 108 MHz (Japan wide band) */
-       case 1 :
-               tuner->rangelow  =  76   * FREQ_MUL;
-               tuner->rangehigh = 108   * FREQ_MUL;
-               break;
-       /* 2: 76   -  90 MHz (Japan) */
-       case 2 :
-               tuner->rangelow  =  76   * FREQ_MUL;
-               tuner->rangehigh =  90   * FREQ_MUL;
-               break;
-       };
-
-       /* stereo indicator == stereo (instead of mono) */
-       if ((radio->registers[STATUSRSSI] & STATUSRSSI_ST) == 0)
-               tuner->rxsubchans = V4L2_TUNER_SUB_MONO;
-       else
-               tuner->rxsubchans = V4L2_TUNER_SUB_MONO | V4L2_TUNER_SUB_STEREO;
-
-       /* mono/stereo selector */
-       if ((radio->registers[POWERCFG] & POWERCFG_MONO) == 0)
-               tuner->audmode = V4L2_TUNER_MODE_STEREO;
-       else
-               tuner->audmode = V4L2_TUNER_MODE_MONO;
-
-       /* min is worst, max is best; signal:0..0xffff; rssi: 0..0xff */
-       /* measured in units of dbµV in 1 db increments (max at ~75 dbµV) */
-       tuner->signal = (radio->registers[STATUSRSSI] & STATUSRSSI_RSSI);
-       /* the ideal factor is 0xffff/75 = 873,8 */
-       tuner->signal = (tuner->signal * 873) + (8 * tuner->signal / 10);
-
-       /* automatic frequency control: -1: freq to low, 1 freq to high */
-       /* AFCRL does only indicate that freq. differs, not if too low/high */
-       tuner->afc = (radio->registers[STATUSRSSI] & STATUSRSSI_AFCRL) ? 1 : 0;
-
-done:
-       if (retval < 0)
-               printk(KERN_WARNING DRIVER_NAME
-                       ": get tuner failed with %d\n", retval);
-       return retval;
-}
-
-
-/*
- * si470x_vidioc_s_tuner - set tuner attributes
- */
-static int si470x_vidioc_s_tuner(struct file *file, void *priv,
-               struct v4l2_tuner *tuner)
-{
-       struct si470x_device *radio = video_drvdata(file);
-       int retval = -EINVAL;
-
-       /* safety checks */
-       if (radio->disconnected) {
-               retval = -EIO;
-               goto done;
-       }
-       if (tuner->index != 0)
-               goto done;
-
-       /* mono/stereo selector */
-       switch (tuner->audmode) {
-       case V4L2_TUNER_MODE_MONO:
-               radio->registers[POWERCFG] |= POWERCFG_MONO;  /* force mono */
-               break;
-       case V4L2_TUNER_MODE_STEREO:
-               radio->registers[POWERCFG] &= ~POWERCFG_MONO; /* try stereo */
-               break;
-       default:
-               goto done;
-       }
-
-       retval = si470x_set_register(radio, POWERCFG);
-
-done:
-       if (retval < 0)
-               printk(KERN_WARNING DRIVER_NAME
-                       ": set tuner failed with %d\n", retval);
-       return retval;
-}
-
-
-/*
- * si470x_vidioc_g_frequency - get tuner or modulator radio frequency
- */
-static int si470x_vidioc_g_frequency(struct file *file, void *priv,
-               struct v4l2_frequency *freq)
-{
-       struct si470x_device *radio = video_drvdata(file);
-       int retval = 0;
-
-       /* safety checks */
-       if (radio->disconnected) {
-               retval = -EIO;
-               goto done;
-       }
-       if (freq->tuner != 0) {
-               retval = -EINVAL;
-               goto done;
-       }
-
-       freq->type = V4L2_TUNER_RADIO;
-       retval = si470x_get_freq(radio, &freq->frequency);
-
-done:
-       if (retval < 0)
-               printk(KERN_WARNING DRIVER_NAME
-                       ": get frequency failed with %d\n", retval);
-       return retval;
-}
-
-
-/*
- * si470x_vidioc_s_frequency - set tuner or modulator radio frequency
- */
-static int si470x_vidioc_s_frequency(struct file *file, void *priv,
-               struct v4l2_frequency *freq)
-{
-       struct si470x_device *radio = video_drvdata(file);
-       int retval = 0;
-
-       /* safety checks */
-       if (radio->disconnected) {
-               retval = -EIO;
-               goto done;
-       }
-       if (freq->tuner != 0) {
-               retval = -EINVAL;
-               goto done;
-       }
-
-       retval = si470x_set_freq(radio, freq->frequency);
-
-done:
-       if (retval < 0)
-               printk(KERN_WARNING DRIVER_NAME
-                       ": set frequency failed with %d\n", retval);
-       return retval;
-}
-
-
-/*
- * si470x_vidioc_s_hw_freq_seek - set hardware frequency seek
- */
-static int si470x_vidioc_s_hw_freq_seek(struct file *file, void *priv,
-               struct v4l2_hw_freq_seek *seek)
-{
-       struct si470x_device *radio = video_drvdata(file);
-       int retval = 0;
-
-       /* safety checks */
-       if (radio->disconnected) {
-               retval = -EIO;
-               goto done;
-       }
-       if (seek->tuner != 0) {
-               retval = -EINVAL;
-               goto done;
-       }
-
-       retval = si470x_set_seek(radio, seek->wrap_around, seek->seek_upward);
-
-done:
-       if (retval < 0)
-               printk(KERN_WARNING DRIVER_NAME
-                       ": set hardware frequency seek failed with %d\n",
-                       retval);
-       return retval;
-}
-
-
-/*
- * si470x_ioctl_ops - video device ioctl operations
- */
-static const struct v4l2_ioctl_ops si470x_ioctl_ops = {
-       .vidioc_querycap        = si470x_vidioc_querycap,
-       .vidioc_queryctrl       = si470x_vidioc_queryctrl,
-       .vidioc_g_ctrl          = si470x_vidioc_g_ctrl,
-       .vidioc_s_ctrl          = si470x_vidioc_s_ctrl,
-       .vidioc_g_audio         = si470x_vidioc_g_audio,
-       .vidioc_g_tuner         = si470x_vidioc_g_tuner,
-       .vidioc_s_tuner         = si470x_vidioc_s_tuner,
-       .vidioc_g_frequency     = si470x_vidioc_g_frequency,
-       .vidioc_s_frequency     = si470x_vidioc_s_frequency,
-       .vidioc_s_hw_freq_seek  = si470x_vidioc_s_hw_freq_seek,
-};
-
-
-/*
- * si470x_viddev_template - video device interface
- */
-static struct video_device si470x_viddev_template = {
-       .fops                   = &si470x_fops,
-       .name                   = DRIVER_NAME,
-       .release                = video_device_release,
-       .ioctl_ops              = &si470x_ioctl_ops,
-};
-
-
-
-/**************************************************************************
- * USB Interface
- **************************************************************************/
-
-/*
- * si470x_usb_driver_probe - probe for the device
- */
-static int si470x_usb_driver_probe(struct usb_interface *intf,
-               const struct usb_device_id *id)
-{
-       struct si470x_device *radio;
-       int retval = 0;
-
-       /* private data allocation and initialization */
-       radio = kzalloc(sizeof(struct si470x_device), GFP_KERNEL);
-       if (!radio) {
-               retval = -ENOMEM;
-               goto err_initial;
-       }
-       radio->users = 0;
-       radio->disconnected = 0;
-       radio->usbdev = interface_to_usbdev(intf);
-       radio->intf = intf;
-       mutex_init(&radio->disconnect_lock);
-       mutex_init(&radio->lock);
-
-       /* video device allocation and initialization */
-       radio->videodev = video_device_alloc();
-       if (!radio->videodev) {
-               retval = -ENOMEM;
-               goto err_radio;
-       }
-       memcpy(radio->videodev, &si470x_viddev_template,
-                       sizeof(si470x_viddev_template));
-       video_set_drvdata(radio->videodev, radio);
-
-       /* show some infos about the specific si470x device */
-       if (si470x_get_all_registers(radio) < 0) {
-               retval = -EIO;
-               goto err_video;
-       }
-       printk(KERN_INFO DRIVER_NAME ": DeviceID=0x%4.4hx ChipID=0x%4.4hx\n",
-                       radio->registers[DEVICEID], radio->registers[CHIPID]);
-
-       /* get software and hardware versions */
-       if (si470x_get_scratch_page_versions(radio) < 0) {
-               retval = -EIO;
-               goto err_video;
-       }
-       printk(KERN_INFO DRIVER_NAME
-                       ": software version %d, hardware version %d\n",
-                       radio->software_version, radio->hardware_version);
-
-       /* check if device and firmware is current */
-       if ((radio->registers[CHIPID] & CHIPID_FIRMWARE)
-                       < RADIO_SW_VERSION_CURRENT) {
-               printk(KERN_WARNING DRIVER_NAME
-                       ": This driver is known to work with "
-                       "firmware version %hu,\n", RADIO_SW_VERSION_CURRENT);
-               printk(KERN_WARNING DRIVER_NAME
-                       ": but the device has firmware version %hu.\n",
-                       radio->registers[CHIPID] & CHIPID_FIRMWARE);
-               printk(KERN_WARNING DRIVER_NAME
-                       ": If you have some trouble using this driver,\n");
-               printk(KERN_WARNING DRIVER_NAME
-                       ": please report to V4L ML at "
-                       "linux-media@vger.kernel.org\n");
-       }
-
-       /* set initial frequency */
-       si470x_set_freq(radio, 87.5 * FREQ_MUL); /* available in all regions */
-
-       /* set led to connect state */
-       si470x_set_led_state(radio, BLINK_GREEN_LED);
-
-       /* rds buffer allocation */
-       radio->buf_size = rds_buf * 3;
-       radio->buffer = kmalloc(radio->buf_size, GFP_KERNEL);
-       if (!radio->buffer) {
-               retval = -EIO;
-               goto err_video;
-       }
-
-       /* rds buffer configuration */
-       radio->wr_index = 0;
-       radio->rd_index = 0;
-       init_waitqueue_head(&radio->read_queue);
-
-       /* prepare rds work function */
-       INIT_DELAYED_WORK(&radio->work, si470x_work);
-
-       /* register video device */
-       retval = video_register_device(radio->videodev, VFL_TYPE_RADIO, radio_nr);
-       if (retval) {
-               printk(KERN_WARNING DRIVER_NAME
-                               ": Could not register video device\n");
-               goto err_all;
-       }
-       usb_set_intfdata(intf, radio);
-
-       return 0;
-err_all:
-       kfree(radio->buffer);
-err_video:
-       video_device_release(radio->videodev);
-err_radio:
-       kfree(radio);
-err_initial:
-       return retval;
-}
-
-
-/*
- * si470x_usb_driver_suspend - suspend the device
- */
-static int si470x_usb_driver_suspend(struct usb_interface *intf,
-               pm_message_t message)
-{
-       struct si470x_device *radio = usb_get_intfdata(intf);
-
-       printk(KERN_INFO DRIVER_NAME ": suspending now...\n");
-
-       cancel_delayed_work_sync(&radio->work);
-
-       return 0;
-}
-
-
-/*
- * si470x_usb_driver_resume - resume the device
- */
-static int si470x_usb_driver_resume(struct usb_interface *intf)
-{
-       struct si470x_device *radio = usb_get_intfdata(intf);
-
-       printk(KERN_INFO DRIVER_NAME ": resuming now...\n");
-
-       mutex_lock(&radio->lock);
-       if (radio->users && radio->registers[SYSCONFIG1] & SYSCONFIG1_RDS)
-               schedule_delayed_work(&radio->work,
-                       msecs_to_jiffies(rds_poll_time));
-       mutex_unlock(&radio->lock);
-
-       return 0;
-}
-
-
-/*
- * si470x_usb_driver_disconnect - disconnect the device
- */
-static void si470x_usb_driver_disconnect(struct usb_interface *intf)
-{
-       struct si470x_device *radio = usb_get_intfdata(intf);
-
-       mutex_lock(&radio->disconnect_lock);
-       radio->disconnected = 1;
-       cancel_delayed_work_sync(&radio->work);
-       usb_set_intfdata(intf, NULL);
-       if (radio->users == 0) {
-               /* set led to disconnect state */
-               si470x_set_led_state(radio, BLINK_ORANGE_LED);
-
-               video_unregister_device(radio->videodev);
-               kfree(radio->buffer);
-               kfree(radio);
-       }
-       mutex_unlock(&radio->disconnect_lock);
-}
-
-
-/*
- * si470x_usb_driver - usb driver interface
- */
-static struct usb_driver si470x_usb_driver = {
-       .name                   = DRIVER_NAME,
-       .probe                  = si470x_usb_driver_probe,
-       .disconnect             = si470x_usb_driver_disconnect,
-       .suspend                = si470x_usb_driver_suspend,
-       .resume                 = si470x_usb_driver_resume,
-       .id_table               = si470x_usb_driver_id_table,
-       .supports_autosuspend   = 1,
-};
-
-
-
-/**************************************************************************
- * Module Interface
- **************************************************************************/
-
-/*
- * si470x_module_init - module init
- */
-static int __init si470x_module_init(void)
-{
-       printk(KERN_INFO DRIVER_DESC ", Version " DRIVER_VERSION "\n");
-       return usb_register(&si470x_usb_driver);
-}
-
-
-/*
- * si470x_module_exit - module exit
- */
-static void __exit si470x_module_exit(void)
-{
-       usb_deregister(&si470x_usb_driver);
-}
-
-
-module_init(si470x_module_init);
-module_exit(si470x_module_exit);
-
-MODULE_LICENSE("GPL");
-MODULE_AUTHOR(DRIVER_AUTHOR);
-MODULE_DESCRIPTION(DRIVER_DESC);
-MODULE_VERSION(DRIVER_VERSION);
diff --git a/drivers/media/radio/radio-si4713.c b/drivers/media/radio/radio-si4713.c
new file mode 100644 (file)
index 0000000..65c14b7
--- /dev/null
@@ -0,0 +1,367 @@
+/*
+ * drivers/media/radio/radio-si4713.c
+ *
+ * Platform Driver for Silicon Labs Si4713 FM Radio Transmitter:
+ *
+ * Copyright (c) 2008 Instituto Nokia de Tecnologia - INdT
+ * Contact: Eduardo Valentin <eduardo.valentin@nokia.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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/version.h>
+#include <linux/platform_device.h>
+#include <linux/i2c.h>
+#include <linux/videodev2.h>
+#include <media/v4l2-device.h>
+#include <media/v4l2-common.h>
+#include <media/v4l2-ioctl.h>
+#include <media/radio-si4713.h>
+
+/* module parameters */
+static int radio_nr = -1;      /* radio device minor (-1 ==> auto assign) */
+module_param(radio_nr, int, 0);
+MODULE_PARM_DESC(radio_nr,
+                "Minor number for radio device (-1 ==> auto assign)");
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Eduardo Valentin <eduardo.valentin@nokia.com>");
+MODULE_DESCRIPTION("Platform driver for Si4713 FM Radio Transmitter");
+MODULE_VERSION("0.0.1");
+
+/* Driver state struct */
+struct radio_si4713_device {
+       struct v4l2_device              v4l2_dev;
+       struct video_device             *radio_dev;
+};
+
+/* radio_si4713_fops - file operations interface */
+static const struct v4l2_file_operations radio_si4713_fops = {
+       .owner          = THIS_MODULE,
+       .ioctl          = video_ioctl2,
+};
+
+/* Video4Linux Interface */
+static int radio_si4713_fill_audout(struct v4l2_audioout *vao)
+{
+       /* TODO: check presence of audio output */
+       strlcpy(vao->name, "FM Modulator Audio Out", 32);
+
+       return 0;
+}
+
+static int radio_si4713_enumaudout(struct file *file, void *priv,
+                                               struct v4l2_audioout *vao)
+{
+       return radio_si4713_fill_audout(vao);
+}
+
+static int radio_si4713_g_audout(struct file *file, void *priv,
+                                       struct v4l2_audioout *vao)
+{
+       int rval = radio_si4713_fill_audout(vao);
+
+       vao->index = 0;
+
+       return rval;
+}
+
+static int radio_si4713_s_audout(struct file *file, void *priv,
+                                       struct v4l2_audioout *vao)
+{
+       return vao->index ? -EINVAL : 0;
+}
+
+/* radio_si4713_querycap - query device capabilities */
+static int radio_si4713_querycap(struct file *file, void *priv,
+                                       struct v4l2_capability *capability)
+{
+       struct radio_si4713_device *rsdev;
+
+       rsdev = video_get_drvdata(video_devdata(file));
+
+       strlcpy(capability->driver, "radio-si4713", sizeof(capability->driver));
+       strlcpy(capability->card, "Silicon Labs Si4713 Modulator",
+                               sizeof(capability->card));
+       capability->capabilities = V4L2_CAP_MODULATOR | V4L2_CAP_RDS_OUTPUT;
+
+       return 0;
+}
+
+/* radio_si4713_queryctrl - enumerate control items */
+static int radio_si4713_queryctrl(struct file *file, void *priv,
+                                               struct v4l2_queryctrl *qc)
+{
+       /* Must be sorted from low to high control ID! */
+       static const u32 user_ctrls[] = {
+               V4L2_CID_USER_CLASS,
+               V4L2_CID_AUDIO_MUTE,
+               0
+       };
+
+       /* Must be sorted from low to high control ID! */
+       static const u32 fmtx_ctrls[] = {
+               V4L2_CID_FM_TX_CLASS,
+               V4L2_CID_RDS_TX_DEVIATION,
+               V4L2_CID_RDS_TX_PI,
+               V4L2_CID_RDS_TX_PTY,
+               V4L2_CID_RDS_TX_PS_NAME,
+               V4L2_CID_RDS_TX_RADIO_TEXT,
+               V4L2_CID_AUDIO_LIMITER_ENABLED,
+               V4L2_CID_AUDIO_LIMITER_RELEASE_TIME,
+               V4L2_CID_AUDIO_LIMITER_DEVIATION,
+               V4L2_CID_AUDIO_COMPRESSION_ENABLED,
+               V4L2_CID_AUDIO_COMPRESSION_GAIN,
+               V4L2_CID_AUDIO_COMPRESSION_THRESHOLD,
+               V4L2_CID_AUDIO_COMPRESSION_ATTACK_TIME,
+               V4L2_CID_AUDIO_COMPRESSION_RELEASE_TIME,
+               V4L2_CID_PILOT_TONE_ENABLED,
+               V4L2_CID_PILOT_TONE_DEVIATION,
+               V4L2_CID_PILOT_TONE_FREQUENCY,
+               V4L2_CID_TUNE_PREEMPHASIS,
+               V4L2_CID_TUNE_POWER_LEVEL,
+               V4L2_CID_TUNE_ANTENNA_CAPACITOR,
+               0
+       };
+       static const u32 *ctrl_classes[] = {
+               user_ctrls,
+               fmtx_ctrls,
+               NULL
+       };
+       struct radio_si4713_device *rsdev;
+
+       rsdev = video_get_drvdata(video_devdata(file));
+
+       qc->id = v4l2_ctrl_next(ctrl_classes, qc->id);
+       if (qc->id == 0)
+               return -EINVAL;
+
+       if (qc->id == V4L2_CID_USER_CLASS || qc->id == V4L2_CID_FM_TX_CLASS)
+               return v4l2_ctrl_query_fill(qc, 0, 0, 0, 0);
+
+       return v4l2_device_call_until_err(&rsdev->v4l2_dev, 0, core,
+                                               queryctrl, qc);
+}
+
+/*
+ * v4l2 ioctl call backs.
+ * we are just a wrapper for v4l2_sub_devs.
+ */
+static inline struct v4l2_device *get_v4l2_dev(struct file *file)
+{
+       return &((struct radio_si4713_device *)video_drvdata(file))->v4l2_dev;
+}
+
+static int radio_si4713_g_ext_ctrls(struct file *file, void *p,
+                                               struct v4l2_ext_controls *vecs)
+{
+       return v4l2_device_call_until_err(get_v4l2_dev(file), 0, core,
+                                                       g_ext_ctrls, vecs);
+}
+
+static int radio_si4713_s_ext_ctrls(struct file *file, void *p,
+                                               struct v4l2_ext_controls *vecs)
+{
+       return v4l2_device_call_until_err(get_v4l2_dev(file), 0, core,
+                                                       s_ext_ctrls, vecs);
+}
+
+static int radio_si4713_g_ctrl(struct file *file, void *p,
+                                               struct v4l2_control *vc)
+{
+       return v4l2_device_call_until_err(get_v4l2_dev(file), 0, core,
+                                                       g_ctrl, vc);
+}
+
+static int radio_si4713_s_ctrl(struct file *file, void *p,
+                                               struct v4l2_control *vc)
+{
+       return v4l2_device_call_until_err(get_v4l2_dev(file), 0, core,
+                                                       s_ctrl, vc);
+}
+
+static int radio_si4713_g_modulator(struct file *file, void *p,
+                                               struct v4l2_modulator *vm)
+{
+       return v4l2_device_call_until_err(get_v4l2_dev(file), 0, tuner,
+                                                       g_modulator, vm);
+}
+
+static int radio_si4713_s_modulator(struct file *file, void *p,
+                                               struct v4l2_modulator *vm)
+{
+       return v4l2_device_call_until_err(get_v4l2_dev(file), 0, tuner,
+                                                       s_modulator, vm);
+}
+
+static int radio_si4713_g_frequency(struct file *file, void *p,
+                                               struct v4l2_frequency *vf)
+{
+       return v4l2_device_call_until_err(get_v4l2_dev(file), 0, tuner,
+                                                       g_frequency, vf);
+}
+
+static int radio_si4713_s_frequency(struct file *file, void *p,
+                                               struct v4l2_frequency *vf)
+{
+       return v4l2_device_call_until_err(get_v4l2_dev(file), 0, tuner,
+                                                       s_frequency, vf);
+}
+
+static long radio_si4713_default(struct file *file, void *p, int cmd, void *arg)
+{
+       return v4l2_device_call_until_err(get_v4l2_dev(file), 0, core,
+                                                       ioctl, cmd, arg);
+}
+
+static struct v4l2_ioctl_ops radio_si4713_ioctl_ops = {
+       .vidioc_enumaudout      = radio_si4713_enumaudout,
+       .vidioc_g_audout        = radio_si4713_g_audout,
+       .vidioc_s_audout        = radio_si4713_s_audout,
+       .vidioc_querycap        = radio_si4713_querycap,
+       .vidioc_queryctrl       = radio_si4713_queryctrl,
+       .vidioc_g_ext_ctrls     = radio_si4713_g_ext_ctrls,
+       .vidioc_s_ext_ctrls     = radio_si4713_s_ext_ctrls,
+       .vidioc_g_ctrl          = radio_si4713_g_ctrl,
+       .vidioc_s_ctrl          = radio_si4713_s_ctrl,
+       .vidioc_g_modulator     = radio_si4713_g_modulator,
+       .vidioc_s_modulator     = radio_si4713_s_modulator,
+       .vidioc_g_frequency     = radio_si4713_g_frequency,
+       .vidioc_s_frequency     = radio_si4713_s_frequency,
+       .vidioc_default         = radio_si4713_default,
+};
+
+/* radio_si4713_vdev_template - video device interface */
+static struct video_device radio_si4713_vdev_template = {
+       .fops                   = &radio_si4713_fops,
+       .name                   = "radio-si4713",
+       .release                = video_device_release,
+       .ioctl_ops              = &radio_si4713_ioctl_ops,
+};
+
+/* Platform driver interface */
+/* radio_si4713_pdriver_probe - probe for the device */
+static int radio_si4713_pdriver_probe(struct platform_device *pdev)
+{
+       struct radio_si4713_platform_data *pdata = pdev->dev.platform_data;
+       struct radio_si4713_device *rsdev;
+       struct i2c_adapter *adapter;
+       struct v4l2_subdev *sd;
+       int rval = 0;
+
+       if (!pdata) {
+               dev_err(&pdev->dev, "Cannot proceed without platform data.\n");
+               rval = -EINVAL;
+               goto exit;
+       }
+
+       rsdev = kzalloc(sizeof *rsdev, GFP_KERNEL);
+       if (!rsdev) {
+               dev_err(&pdev->dev, "Failed to alloc video device.\n");
+               rval = -ENOMEM;
+               goto exit;
+       }
+
+       rval = v4l2_device_register(&pdev->dev, &rsdev->v4l2_dev);
+       if (rval) {
+               dev_err(&pdev->dev, "Failed to register v4l2 device.\n");
+               goto free_rsdev;
+       }
+
+       adapter = i2c_get_adapter(pdata->i2c_bus);
+       if (!adapter) {
+               dev_err(&pdev->dev, "Cannot get i2c adapter %d\n",
+                                                       pdata->i2c_bus);
+               rval = -ENODEV;
+               goto unregister_v4l2_dev;
+       }
+
+       sd = v4l2_i2c_new_subdev_board(&rsdev->v4l2_dev, adapter, "si4713_i2c",
+                                       pdata->subdev_board_info, NULL);
+       if (!sd) {
+               dev_err(&pdev->dev, "Cannot get v4l2 subdevice\n");
+               rval = -ENODEV;
+               goto unregister_v4l2_dev;
+       }
+
+       rsdev->radio_dev = video_device_alloc();
+       if (!rsdev->radio_dev) {
+               dev_err(&pdev->dev, "Failed to alloc video device.\n");
+               rval = -ENOMEM;
+               goto unregister_v4l2_dev;
+       }
+
+       memcpy(rsdev->radio_dev, &radio_si4713_vdev_template,
+                       sizeof(radio_si4713_vdev_template));
+       video_set_drvdata(rsdev->radio_dev, rsdev);
+       if (video_register_device(rsdev->radio_dev, VFL_TYPE_RADIO, radio_nr)) {
+               dev_err(&pdev->dev, "Could not register video device.\n");
+               rval = -EIO;
+               goto free_vdev;
+       }
+       dev_info(&pdev->dev, "New device successfully probed\n");
+
+       goto exit;
+
+free_vdev:
+       video_device_release(rsdev->radio_dev);
+unregister_v4l2_dev:
+       v4l2_device_unregister(&rsdev->v4l2_dev);
+free_rsdev:
+       kfree(rsdev);
+exit:
+       return rval;
+}
+
+/* radio_si4713_pdriver_remove - remove the device */
+static int __exit radio_si4713_pdriver_remove(struct platform_device *pdev)
+{
+       struct v4l2_device *v4l2_dev = platform_get_drvdata(pdev);
+       struct radio_si4713_device *rsdev = container_of(v4l2_dev,
+                                               struct radio_si4713_device,
+                                               v4l2_dev);
+
+       video_unregister_device(rsdev->radio_dev);
+       v4l2_device_unregister(&rsdev->v4l2_dev);
+       kfree(rsdev);
+
+       return 0;
+}
+
+static struct platform_driver radio_si4713_pdriver = {
+       .driver         = {
+               .name   = "radio-si4713",
+       },
+       .probe          = radio_si4713_pdriver_probe,
+       .remove         = __exit_p(radio_si4713_pdriver_remove),
+};
+
+/* Module Interface */
+static int __init radio_si4713_module_init(void)
+{
+       return platform_driver_register(&radio_si4713_pdriver);
+}
+
+static void __exit radio_si4713_module_exit(void)
+{
+       platform_driver_unregister(&radio_si4713_pdriver);
+}
+
+module_init(radio_si4713_module_init);
+module_exit(radio_si4713_module_exit);
+
diff --git a/drivers/media/radio/si470x/Kconfig b/drivers/media/radio/si470x/Kconfig
new file mode 100644 (file)
index 0000000..a466654
--- /dev/null
@@ -0,0 +1,37 @@
+config USB_SI470X
+       tristate "Silicon Labs Si470x FM Radio Receiver support with USB"
+       depends on USB && RADIO_SI470X
+       ---help---
+         This is a driver for USB devices with the Silicon Labs SI470x
+         chip. Currently these devices are known to work:
+         - 10c4:818a: Silicon Labs USB FM Radio Reference Design
+         - 06e1:a155: ADS/Tech FM Radio Receiver (formerly Instant FM Music)
+         - 1b80:d700: KWorld USB FM Radio SnapMusic Mobile 700 (FM700)
+         - 10c5:819a: Sanei Electric FM USB Radio (aka DealExtreme.com PCear)
+
+         Sound is provided by the ALSA USB Audio/MIDI driver. Therefore
+         if you don't want to use the device solely for RDS receiving,
+         it is recommended to also select SND_USB_AUDIO.
+
+         Please have a look at the documentation, especially on how
+         to redirect the audio stream from the radio to your sound device:
+         Documentation/video4linux/si470x.txt
+
+         Say Y here if you want to connect this type of radio to your
+         computer's USB port.
+
+         To compile this driver as a module, choose M here: the
+         module will be called radio-usb-si470x.
+
+config I2C_SI470X
+       tristate "Silicon Labs Si470x FM Radio Receiver support with I2C"
+       depends on I2C && RADIO_SI470X && !USB_SI470X
+       ---help---
+         This is a driver for I2C devices with the Silicon Labs SI470x
+         chip.
+
+         Say Y here if you want to connect this type of radio to your
+         computer's I2C port.
+
+         To compile this driver as a module, choose M here: the
+         module will be called radio-i2c-si470x.
diff --git a/drivers/media/radio/si470x/Makefile b/drivers/media/radio/si470x/Makefile
new file mode 100644 (file)
index 0000000..0696481
--- /dev/null
@@ -0,0 +1,9 @@
+#
+# Makefile for radios with Silicon Labs Si470x FM Radio Receivers
+#
+
+radio-usb-si470x-objs  := radio-si470x-usb.o radio-si470x-common.o
+radio-i2c-si470x-objs  := radio-si470x-i2c.o radio-si470x-common.o
+
+obj-$(CONFIG_USB_SI470X) += radio-usb-si470x.o
+obj-$(CONFIG_I2C_SI470X) += radio-i2c-si470x.o
diff --git a/drivers/media/radio/si470x/radio-si470x-common.c b/drivers/media/radio/si470x/radio-si470x-common.c
new file mode 100644 (file)
index 0000000..f33315f
--- /dev/null
@@ -0,0 +1,798 @@
+/*
+ *  drivers/media/radio/si470x/radio-si470x-common.c
+ *
+ *  Driver for radios with Silicon Labs Si470x FM Radio Receivers
+ *
+ *  Copyright (c) 2009 Tobias Lorenz <tobias.lorenz@gmx.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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+
+/*
+ * History:
+ * 2008-01-12  Tobias Lorenz <tobias.lorenz@gmx.net>
+ *             Version 1.0.0
+ *             - First working version
+ * 2008-01-13  Tobias Lorenz <tobias.lorenz@gmx.net>
+ *             Version 1.0.1
+ *             - Improved error handling, every function now returns errno
+ *             - Improved multi user access (start/mute/stop)
+ *             - Channel doesn't get lost anymore after start/mute/stop
+ *             - RDS support added (polling mode via interrupt EP 1)
+ *             - marked default module parameters with *value*
+ *             - switched from bit structs to bit masks
+ *             - header file cleaned and integrated
+ * 2008-01-14  Tobias Lorenz <tobias.lorenz@gmx.net>
+ *             Version 1.0.2
+ *             - hex values are now lower case
+ *             - commented USB ID for ADS/Tech moved on todo list
+ *             - blacklisted si470x in hid-quirks.c
+ *             - rds buffer handling functions integrated into *_work, *_read
+ *             - rds_command in si470x_poll exchanged against simple retval
+ *             - check for firmware version 15
+ *             - code order and prototypes still remain the same
+ *             - spacing and bottom of band codes remain the same
+ * 2008-01-16  Tobias Lorenz <tobias.lorenz@gmx.net>
+ *             Version 1.0.3
+ *             - code reordered to avoid function prototypes
+ *             - switch/case defaults are now more user-friendly
+ *             - unified comment style
+ *             - applied all checkpatch.pl v1.12 suggestions
+ *               except the warning about the too long lines with bit comments
+ *             - renamed FMRADIO to RADIO to cut line length (checkpatch.pl)
+ * 2008-01-22  Tobias Lorenz <tobias.lorenz@gmx.net>
+ *             Version 1.0.4
+ *             - avoid poss. locking when doing copy_to_user which may sleep
+ *             - RDS is automatically activated on read now
+ *             - code cleaned of unnecessary rds_commands
+ *             - USB Vendor/Product ID for ADS/Tech FM Radio Receiver verified
+ *               (thanks to Guillaume RAMOUSSE)
+ * 2008-01-27  Tobias Lorenz <tobias.lorenz@gmx.net>
+ *             Version 1.0.5
+ *             - number of seek_retries changed to tune_timeout
+ *             - fixed problem with incomplete tune operations by own buffers
+ *             - optimization of variables and printf types
+ *             - improved error logging
+ * 2008-01-31  Tobias Lorenz <tobias.lorenz@gmx.net>
+ *             Oliver Neukum <oliver@neukum.org>
+ *             Version 1.0.6
+ *             - fixed coverity checker warnings in *_usb_driver_disconnect
+ *             - probe()/open() race by correct ordering in probe()
+ *             - DMA coherency rules by separate allocation of all buffers
+ *             - use of endianness macros
+ *             - abuse of spinlock, replaced by mutex
+ *             - racy handling of timer in disconnect,
+ *               replaced by delayed_work
+ *             - racy interruptible_sleep_on(),
+ *               replaced with wait_event_interruptible()
+ *             - handle signals in read()
+ * 2008-02-08  Tobias Lorenz <tobias.lorenz@gmx.net>
+ *             Oliver Neukum <oliver@neukum.org>
+ *             Version 1.0.7
+ *             - usb autosuspend support
+ *             - unplugging fixed
+ * 2008-05-07  Tobias Lorenz <tobias.lorenz@gmx.net>
+ *             Version 1.0.8
+ *             - hardware frequency seek support
+ *             - afc indication
+ *             - more safety checks, let si470x_get_freq return errno
+ *             - vidioc behavior corrected according to v4l2 spec
+ * 2008-10-20  Alexey Klimov <klimov.linux@gmail.com>
+ *             - add support for KWorld USB FM Radio FM700
+ *             - blacklisted KWorld radio in hid-core.c and hid-ids.h
+ * 2008-12-03  Mark Lord <mlord@pobox.com>
+ *             - add support for DealExtreme USB Radio
+ * 2009-01-31  Bob Ross <pigiron@gmx.com>
+ *             - correction of stereo detection/setting
+ *             - correction of signal strength indicator scaling
+ * 2009-01-31  Rick Bronson <rick@efn.org>
+ *             Tobias Lorenz <tobias.lorenz@gmx.net>
+ *             - add LED status output
+ *             - get HW/SW version from scratchpad
+ * 2009-06-16   Edouard Lafargue <edouard@lafargue.name>
+ *             Version 1.0.10
+ *             - add support for interrupt mode for RDS endpoint,
+ *                instead of polling.
+ *                Improves RDS reception significantly
+ */
+
+
+/* kernel includes */
+#include "radio-si470x.h"
+
+
+
+/**************************************************************************
+ * Module Parameters
+ **************************************************************************/
+
+/* Spacing (kHz) */
+/* 0: 200 kHz (USA, Australia) */
+/* 1: 100 kHz (Europe, Japan) */
+/* 2:  50 kHz */
+static unsigned short space = 2;
+module_param(space, ushort, 0444);
+MODULE_PARM_DESC(space, "Spacing: 0=200kHz 1=100kHz *2=50kHz*");
+
+/* Bottom of Band (MHz) */
+/* 0: 87.5 - 108 MHz (USA, Europe)*/
+/* 1: 76   - 108 MHz (Japan wide band) */
+/* 2: 76   -  90 MHz (Japan) */
+static unsigned short band = 1;
+module_param(band, ushort, 0444);
+MODULE_PARM_DESC(band, "Band: 0=87.5..108MHz *1=76..108MHz* 2=76..90MHz");
+
+/* De-emphasis */
+/* 0: 75 us (USA) */
+/* 1: 50 us (Europe, Australia, Japan) */
+static unsigned short de = 1;
+module_param(de, ushort, 0444);
+MODULE_PARM_DESC(de, "De-emphasis: 0=75us *1=50us*");
+
+/* Tune timeout */
+static unsigned int tune_timeout = 3000;
+module_param(tune_timeout, uint, 0644);
+MODULE_PARM_DESC(tune_timeout, "Tune timeout: *3000*");
+
+/* Seek timeout */
+static unsigned int seek_timeout = 5000;
+module_param(seek_timeout, uint, 0644);
+MODULE_PARM_DESC(seek_timeout, "Seek timeout: *5000*");
+
+
+
+/**************************************************************************
+ * Generic Functions
+ **************************************************************************/
+
+/*
+ * si470x_set_chan - set the channel
+ */
+static int si470x_set_chan(struct si470x_device *radio, unsigned short chan)
+{
+       int retval;
+       unsigned long timeout;
+       bool timed_out = 0;
+
+       /* start tuning */
+       radio->registers[CHANNEL] &= ~CHANNEL_CHAN;
+       radio->registers[CHANNEL] |= CHANNEL_TUNE | chan;
+       retval = si470x_set_register(radio, CHANNEL);
+       if (retval < 0)
+               goto done;
+
+       /* wait till tune operation has completed */
+       timeout = jiffies + msecs_to_jiffies(tune_timeout);
+       do {
+               retval = si470x_get_register(radio, STATUSRSSI);
+               if (retval < 0)
+                       goto stop;
+               timed_out = time_after(jiffies, timeout);
+       } while (((radio->registers[STATUSRSSI] & STATUSRSSI_STC) == 0) &&
+               (!timed_out));
+       if ((radio->registers[STATUSRSSI] & STATUSRSSI_STC) == 0)
+               dev_warn(&radio->videodev->dev, "tune does not complete\n");
+       if (timed_out)
+               dev_warn(&radio->videodev->dev,
+                       "tune timed out after %u ms\n", tune_timeout);
+
+stop:
+       /* stop tuning */
+       radio->registers[CHANNEL] &= ~CHANNEL_TUNE;
+       retval = si470x_set_register(radio, CHANNEL);
+
+done:
+       return retval;
+}
+
+
+/*
+ * si470x_get_freq - get the frequency
+ */
+static int si470x_get_freq(struct si470x_device *radio, unsigned int *freq)
+{
+       unsigned int spacing, band_bottom;
+       unsigned short chan;
+       int retval;
+
+       /* Spacing (kHz) */
+       switch ((radio->registers[SYSCONFIG2] & SYSCONFIG2_SPACE) >> 4) {
+       /* 0: 200 kHz (USA, Australia) */
+       case 0:
+               spacing = 0.200 * FREQ_MUL; break;
+       /* 1: 100 kHz (Europe, Japan) */
+       case 1:
+               spacing = 0.100 * FREQ_MUL; break;
+       /* 2:  50 kHz */
+       default:
+               spacing = 0.050 * FREQ_MUL; break;
+       };
+
+       /* Bottom of Band (MHz) */
+       switch ((radio->registers[SYSCONFIG2] & SYSCONFIG2_BAND) >> 6) {
+       /* 0: 87.5 - 108 MHz (USA, Europe) */
+       case 0:
+               band_bottom = 87.5 * FREQ_MUL; break;
+       /* 1: 76   - 108 MHz (Japan wide band) */
+       default:
+               band_bottom = 76   * FREQ_MUL; break;
+       /* 2: 76   -  90 MHz (Japan) */
+       case 2:
+               band_bottom = 76   * FREQ_MUL; break;
+       };
+
+       /* read channel */
+       retval = si470x_get_register(radio, READCHAN);
+       chan = radio->registers[READCHAN] & READCHAN_READCHAN;
+
+       /* Frequency (MHz) = Spacing (kHz) x Channel + Bottom of Band (MHz) */
+       *freq = chan * spacing + band_bottom;
+
+       return retval;
+}
+
+
+/*
+ * si470x_set_freq - set the frequency
+ */
+int si470x_set_freq(struct si470x_device *radio, unsigned int freq)
+{
+       unsigned int spacing, band_bottom;
+       unsigned short chan;
+
+       /* Spacing (kHz) */
+       switch ((radio->registers[SYSCONFIG2] & SYSCONFIG2_SPACE) >> 4) {
+       /* 0: 200 kHz (USA, Australia) */
+       case 0:
+               spacing = 0.200 * FREQ_MUL; break;
+       /* 1: 100 kHz (Europe, Japan) */
+       case 1:
+               spacing = 0.100 * FREQ_MUL; break;
+       /* 2:  50 kHz */
+       default:
+               spacing = 0.050 * FREQ_MUL; break;
+       };
+
+       /* Bottom of Band (MHz) */
+       switch ((radio->registers[SYSCONFIG2] & SYSCONFIG2_BAND) >> 6) {
+       /* 0: 87.5 - 108 MHz (USA, Europe) */
+       case 0:
+               band_bottom = 87.5 * FREQ_MUL; break;
+       /* 1: 76   - 108 MHz (Japan wide band) */
+       default:
+               band_bottom = 76   * FREQ_MUL; break;
+       /* 2: 76   -  90 MHz (Japan) */
+       case 2:
+               band_bottom = 76   * FREQ_MUL; break;
+       };
+
+       /* Chan = [ Freq (Mhz) - Bottom of Band (MHz) ] / Spacing (kHz) */
+       chan = (freq - band_bottom) / spacing;
+
+       return si470x_set_chan(radio, chan);
+}
+
+
+/*
+ * si470x_set_seek - set seek
+ */
+static int si470x_set_seek(struct si470x_device *radio,
+               unsigned int wrap_around, unsigned int seek_upward)
+{
+       int retval = 0;
+       unsigned long timeout;
+       bool timed_out = 0;
+
+       /* start seeking */
+       radio->registers[POWERCFG] |= POWERCFG_SEEK;
+       if (wrap_around == 1)
+               radio->registers[POWERCFG] &= ~POWERCFG_SKMODE;
+       else
+               radio->registers[POWERCFG] |= POWERCFG_SKMODE;
+       if (seek_upward == 1)
+               radio->registers[POWERCFG] |= POWERCFG_SEEKUP;
+       else
+               radio->registers[POWERCFG] &= ~POWERCFG_SEEKUP;
+       retval = si470x_set_register(radio, POWERCFG);
+       if (retval < 0)
+               goto done;
+
+       /* wait till seek operation has completed */
+       timeout = jiffies + msecs_to_jiffies(seek_timeout);
+       do {
+               retval = si470x_get_register(radio, STATUSRSSI);
+               if (retval < 0)
+                       goto stop;
+               timed_out = time_after(jiffies, timeout);
+       } while (((radio->registers[STATUSRSSI] & STATUSRSSI_STC) == 0) &&
+               (!timed_out));
+       if ((radio->registers[STATUSRSSI] & STATUSRSSI_STC) == 0)
+               dev_warn(&radio->videodev->dev, "seek does not complete\n");
+       if (radio->registers[STATUSRSSI] & STATUSRSSI_SF)
+               dev_warn(&radio->videodev->dev,
+                       "seek failed / band limit reached\n");
+       if (timed_out)
+               dev_warn(&radio->videodev->dev,
+                       "seek timed out after %u ms\n", seek_timeout);
+
+stop:
+       /* stop seeking */
+       radio->registers[POWERCFG] &= ~POWERCFG_SEEK;
+       retval = si470x_set_register(radio, POWERCFG);
+
+done:
+       /* try again, if timed out */
+       if ((retval == 0) && timed_out)
+               retval = -EAGAIN;
+
+       return retval;
+}
+
+
+/*
+ * si470x_start - switch on radio
+ */
+int si470x_start(struct si470x_device *radio)
+{
+       int retval;
+
+       /* powercfg */
+       radio->registers[POWERCFG] =
+               POWERCFG_DMUTE | POWERCFG_ENABLE | POWERCFG_RDSM;
+       retval = si470x_set_register(radio, POWERCFG);
+       if (retval < 0)
+               goto done;
+
+       /* sysconfig 1 */
+       radio->registers[SYSCONFIG1] = SYSCONFIG1_DE;
+       retval = si470x_set_register(radio, SYSCONFIG1);
+       if (retval < 0)
+               goto done;
+
+       /* sysconfig 2 */
+       radio->registers[SYSCONFIG2] =
+               (0x3f  << 8) |                          /* SEEKTH */
+               ((band  << 6) & SYSCONFIG2_BAND)  |     /* BAND */
+               ((space << 4) & SYSCONFIG2_SPACE) |     /* SPACE */
+               15;                                     /* VOLUME (max) */
+       retval = si470x_set_register(radio, SYSCONFIG2);
+       if (retval < 0)
+               goto done;
+
+       /* reset last channel */
+       retval = si470x_set_chan(radio,
+               radio->registers[CHANNEL] & CHANNEL_CHAN);
+
+done:
+       return retval;
+}
+
+
+/*
+ * si470x_stop - switch off radio
+ */
+int si470x_stop(struct si470x_device *radio)
+{
+       int retval;
+
+       /* sysconfig 1 */
+       radio->registers[SYSCONFIG1] &= ~SYSCONFIG1_RDS;
+       retval = si470x_set_register(radio, SYSCONFIG1);
+       if (retval < 0)
+               goto done;
+
+       /* powercfg */
+       radio->registers[POWERCFG] &= ~POWERCFG_DMUTE;
+       /* POWERCFG_ENABLE has to automatically go low */
+       radio->registers[POWERCFG] |= POWERCFG_ENABLE | POWERCFG_DISABLE;
+       retval = si470x_set_register(radio, POWERCFG);
+
+done:
+       return retval;
+}
+
+
+/*
+ * si470x_rds_on - switch on rds reception
+ */
+int si470x_rds_on(struct si470x_device *radio)
+{
+       int retval;
+
+       /* sysconfig 1 */
+       mutex_lock(&radio->lock);
+       radio->registers[SYSCONFIG1] |= SYSCONFIG1_RDS;
+       retval = si470x_set_register(radio, SYSCONFIG1);
+       if (retval < 0)
+               radio->registers[SYSCONFIG1] &= ~SYSCONFIG1_RDS;
+       mutex_unlock(&radio->lock);
+
+       return retval;
+}
+
+
+
+/**************************************************************************
+ * Video4Linux Interface
+ **************************************************************************/
+
+/*
+ * si470x_vidioc_queryctrl - enumerate control items
+ */
+static int si470x_vidioc_queryctrl(struct file *file, void *priv,
+               struct v4l2_queryctrl *qc)
+{
+       struct si470x_device *radio = video_drvdata(file);
+       int retval = -EINVAL;
+
+       /* abort if qc->id is below V4L2_CID_BASE */
+       if (qc->id < V4L2_CID_BASE)
+               goto done;
+
+       /* search video control */
+       switch (qc->id) {
+       case V4L2_CID_AUDIO_VOLUME:
+               return v4l2_ctrl_query_fill(qc, 0, 15, 1, 15);
+       case V4L2_CID_AUDIO_MUTE:
+               return v4l2_ctrl_query_fill(qc, 0, 1, 1, 1);
+       }
+
+       /* disable unsupported base controls */
+       /* to satisfy kradio and such apps */
+       if ((retval == -EINVAL) && (qc->id < V4L2_CID_LASTP1)) {
+               qc->flags = V4L2_CTRL_FLAG_DISABLED;
+               retval = 0;
+       }
+
+done:
+       if (retval < 0)
+               dev_warn(&radio->videodev->dev,
+                       "query controls failed with %d\n", retval);
+       return retval;
+}
+
+
+/*
+ * si470x_vidioc_g_ctrl - get the value of a control
+ */
+static int si470x_vidioc_g_ctrl(struct file *file, void *priv,
+               struct v4l2_control *ctrl)
+{
+       struct si470x_device *radio = video_drvdata(file);
+       int retval = 0;
+
+       /* safety checks */
+       retval = si470x_disconnect_check(radio);
+       if (retval)
+               goto done;
+
+       switch (ctrl->id) {
+       case V4L2_CID_AUDIO_VOLUME:
+               ctrl->value = radio->registers[SYSCONFIG2] &
+                               SYSCONFIG2_VOLUME;
+               break;
+       case V4L2_CID_AUDIO_MUTE:
+               ctrl->value = ((radio->registers[POWERCFG] &
+                               POWERCFG_DMUTE) == 0) ? 1 : 0;
+               break;
+       default:
+               retval = -EINVAL;
+       }
+
+done:
+       if (retval < 0)
+               dev_warn(&radio->videodev->dev,
+                       "get control failed with %d\n", retval);
+       return retval;
+}
+
+
+/*
+ * si470x_vidioc_s_ctrl - set the value of a control
+ */
+static int si470x_vidioc_s_ctrl(struct file *file, void *priv,
+               struct v4l2_control *ctrl)
+{
+       struct si470x_device *radio = video_drvdata(file);
+       int retval = 0;
+
+       /* safety checks */
+       retval = si470x_disconnect_check(radio);
+       if (retval)
+               goto done;
+
+       switch (ctrl->id) {
+       case V4L2_CID_AUDIO_VOLUME:
+               radio->registers[SYSCONFIG2] &= ~SYSCONFIG2_VOLUME;
+               radio->registers[SYSCONFIG2] |= ctrl->value;
+               retval = si470x_set_register(radio, SYSCONFIG2);
+               break;
+       case V4L2_CID_AUDIO_MUTE:
+               if (ctrl->value == 1)
+                       radio->registers[POWERCFG] &= ~POWERCFG_DMUTE;
+               else
+                       radio->registers[POWERCFG] |= POWERCFG_DMUTE;
+               retval = si470x_set_register(radio, POWERCFG);
+               break;
+       default:
+               retval = -EINVAL;
+       }
+
+done:
+       if (retval < 0)
+               dev_warn(&radio->videodev->dev,
+                       "set control failed with %d\n", retval);
+       return retval;
+}
+
+
+/*
+ * si470x_vidioc_g_audio - get audio attributes
+ */
+static int si470x_vidioc_g_audio(struct file *file, void *priv,
+               struct v4l2_audio *audio)
+{
+       /* driver constants */
+       audio->index = 0;
+       strcpy(audio->name, "Radio");
+       audio->capability = V4L2_AUDCAP_STEREO;
+       audio->mode = 0;
+
+       return 0;
+}
+
+
+/*
+ * si470x_vidioc_g_tuner - get tuner attributes
+ */
+static int si470x_vidioc_g_tuner(struct file *file, void *priv,
+               struct v4l2_tuner *tuner)
+{
+       struct si470x_device *radio = video_drvdata(file);
+       int retval = 0;
+
+       /* safety checks */
+       retval = si470x_disconnect_check(radio);
+       if (retval)
+               goto done;
+
+       if (tuner->index != 0) {
+               retval = -EINVAL;
+               goto done;
+       }
+
+       retval = si470x_get_register(radio, STATUSRSSI);
+       if (retval < 0)
+               goto done;
+
+       /* driver constants */
+       strcpy(tuner->name, "FM");
+       tuner->type = V4L2_TUNER_RADIO;
+#if defined(CONFIG_USB_SI470X) || defined(CONFIG_USB_SI470X_MODULE)
+       tuner->capability = V4L2_TUNER_CAP_LOW | V4L2_TUNER_CAP_STEREO |
+                           V4L2_TUNER_CAP_RDS;
+#else
+       tuner->capability = V4L2_TUNER_CAP_LOW | V4L2_TUNER_CAP_STEREO;
+#endif
+
+       /* range limits */
+       switch ((radio->registers[SYSCONFIG2] & SYSCONFIG2_BAND) >> 6) {
+       /* 0: 87.5 - 108 MHz (USA, Europe, default) */
+       default:
+               tuner->rangelow  =  87.5 * FREQ_MUL;
+               tuner->rangehigh = 108   * FREQ_MUL;
+               break;
+       /* 1: 76   - 108 MHz (Japan wide band) */
+       case 1:
+               tuner->rangelow  =  76   * FREQ_MUL;
+               tuner->rangehigh = 108   * FREQ_MUL;
+               break;
+       /* 2: 76   -  90 MHz (Japan) */
+       case 2:
+               tuner->rangelow  =  76   * FREQ_MUL;
+               tuner->rangehigh =  90   * FREQ_MUL;
+               break;
+       };
+
+       /* stereo indicator == stereo (instead of mono) */
+       if ((radio->registers[STATUSRSSI] & STATUSRSSI_ST) == 0)
+               tuner->rxsubchans = V4L2_TUNER_SUB_MONO;
+       else
+               tuner->rxsubchans = V4L2_TUNER_SUB_MONO | V4L2_TUNER_SUB_STEREO;
+#if defined(CONFIG_USB_SI470X) || defined(CONFIG_USB_SI470X_MODULE)
+       /* If there is a reliable method of detecting an RDS channel,
+          then this code should check for that before setting this
+          RDS subchannel. */
+       tuner->rxsubchans |= V4L2_TUNER_SUB_RDS;
+#endif
+
+       /* mono/stereo selector */
+       if ((radio->registers[POWERCFG] & POWERCFG_MONO) == 0)
+               tuner->audmode = V4L2_TUNER_MODE_STEREO;
+       else
+               tuner->audmode = V4L2_TUNER_MODE_MONO;
+
+       /* min is worst, max is best; signal:0..0xffff; rssi: 0..0xff */
+       /* measured in units of db쨉V in 1 db increments (max at ~75 db쨉V) */
+       tuner->signal = (radio->registers[STATUSRSSI] & STATUSRSSI_RSSI);
+       /* the ideal factor is 0xffff/75 = 873,8 */
+       tuner->signal = (tuner->signal * 873) + (8 * tuner->signal / 10);
+
+       /* automatic frequency control: -1: freq to low, 1 freq to high */
+       /* AFCRL does only indicate that freq. differs, not if too low/high */
+       tuner->afc = (radio->registers[STATUSRSSI] & STATUSRSSI_AFCRL) ? 1 : 0;
+
+done:
+       if (retval < 0)
+               dev_warn(&radio->videodev->dev,
+                       "get tuner failed with %d\n", retval);
+       return retval;
+}
+
+
+/*
+ * si470x_vidioc_s_tuner - set tuner attributes
+ */
+static int si470x_vidioc_s_tuner(struct file *file, void *priv,
+               struct v4l2_tuner *tuner)
+{
+       struct si470x_device *radio = video_drvdata(file);
+       int retval = -EINVAL;
+
+       /* safety checks */
+       retval = si470x_disconnect_check(radio);
+       if (retval)
+               goto done;
+
+       if (tuner->index != 0)
+               goto done;
+
+       /* mono/stereo selector */
+       switch (tuner->audmode) {
+       case V4L2_TUNER_MODE_MONO:
+               radio->registers[POWERCFG] |= POWERCFG_MONO;  /* force mono */
+               break;
+       case V4L2_TUNER_MODE_STEREO:
+               radio->registers[POWERCFG] &= ~POWERCFG_MONO; /* try stereo */
+               break;
+       default:
+               goto done;
+       }
+
+       retval = si470x_set_register(radio, POWERCFG);
+
+done:
+       if (retval < 0)
+               dev_warn(&radio->videodev->dev,
+                       "set tuner failed with %d\n", retval);
+       return retval;
+}
+
+
+/*
+ * si470x_vidioc_g_frequency - get tuner or modulator radio frequency
+ */
+static int si470x_vidioc_g_frequency(struct file *file, void *priv,
+               struct v4l2_frequency *freq)
+{
+       struct si470x_device *radio = video_drvdata(file);
+       int retval = 0;
+
+       /* safety checks */
+       retval = si470x_disconnect_check(radio);
+       if (retval)
+               goto done;
+
+       if (freq->tuner != 0) {
+               retval = -EINVAL;
+               goto done;
+       }
+
+       freq->type = V4L2_TUNER_RADIO;
+       retval = si470x_get_freq(radio, &freq->frequency);
+
+done:
+       if (retval < 0)
+               dev_warn(&radio->videodev->dev,
+                       "get frequency failed with %d\n", retval);
+       return retval;
+}
+
+
+/*
+ * si470x_vidioc_s_frequency - set tuner or modulator radio frequency
+ */
+static int si470x_vidioc_s_frequency(struct file *file, void *priv,
+               struct v4l2_frequency *freq)
+{
+       struct si470x_device *radio = video_drvdata(file);
+       int retval = 0;
+
+       /* safety checks */
+       retval = si470x_disconnect_check(radio);
+       if (retval)
+               goto done;
+
+       if (freq->tuner != 0) {
+               retval = -EINVAL;
+               goto done;
+       }
+
+       retval = si470x_set_freq(radio, freq->frequency);
+
+done:
+       if (retval < 0)
+               dev_warn(&radio->videodev->dev,
+                       "set frequency failed with %d\n", retval);
+       return retval;
+}
+
+
+/*
+ * si470x_vidioc_s_hw_freq_seek - set hardware frequency seek
+ */
+static int si470x_vidioc_s_hw_freq_seek(struct file *file, void *priv,
+               struct v4l2_hw_freq_seek *seek)
+{
+       struct si470x_device *radio = video_drvdata(file);
+       int retval = 0;
+
+       /* safety checks */
+       retval = si470x_disconnect_check(radio);
+       if (retval)
+               goto done;
+
+       if (seek->tuner != 0) {
+               retval = -EINVAL;
+               goto done;
+       }
+
+       retval = si470x_set_seek(radio, seek->wrap_around, seek->seek_upward);
+
+done:
+       if (retval < 0)
+               dev_warn(&radio->videodev->dev,
+                       "set hardware frequency seek failed with %d\n", retval);
+       return retval;
+}
+
+
+/*
+ * si470x_ioctl_ops - video device ioctl operations
+ */
+static const struct v4l2_ioctl_ops si470x_ioctl_ops = {
+       .vidioc_querycap        = si470x_vidioc_querycap,
+       .vidioc_queryctrl       = si470x_vidioc_queryctrl,
+       .vidioc_g_ctrl          = si470x_vidioc_g_ctrl,
+       .vidioc_s_ctrl          = si470x_vidioc_s_ctrl,
+       .vidioc_g_audio         = si470x_vidioc_g_audio,
+       .vidioc_g_tuner         = si470x_vidioc_g_tuner,
+       .vidioc_s_tuner         = si470x_vidioc_s_tuner,
+       .vidioc_g_frequency     = si470x_vidioc_g_frequency,
+       .vidioc_s_frequency     = si470x_vidioc_s_frequency,
+       .vidioc_s_hw_freq_seek  = si470x_vidioc_s_hw_freq_seek,
+};
+
+
+/*
+ * si470x_viddev_template - video device interface
+ */
+struct video_device si470x_viddev_template = {
+       .fops                   = &si470x_fops,
+       .name                   = DRIVER_NAME,
+       .release                = video_device_release,
+       .ioctl_ops              = &si470x_ioctl_ops,
+};
diff --git a/drivers/media/radio/si470x/radio-si470x-i2c.c b/drivers/media/radio/si470x/radio-si470x-i2c.c
new file mode 100644 (file)
index 0000000..2d53b6a
--- /dev/null
@@ -0,0 +1,401 @@
+/*
+ * drivers/media/radio/si470x/radio-si470x-i2c.c
+ *
+ * I2C driver for radios with Silicon Labs Si470x FM Radio Receivers
+ *
+ * Copyright (c) 2009 Samsung Electronics Co.Ltd
+ * Author: Joonyoung Shim <jy0922.shim@samsung.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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+
+/*
+ * ToDo:
+ * - RDS support
+ */
+
+
+/* driver definitions */
+#define DRIVER_AUTHOR "Joonyoung Shim <jy0922.shim@samsung.com>";
+#define DRIVER_KERNEL_VERSION KERNEL_VERSION(1, 0, 0)
+#define DRIVER_CARD "Silicon Labs Si470x FM Radio Receiver"
+#define DRIVER_DESC "I2C radio driver for Si470x FM Radio Receivers"
+#define DRIVER_VERSION "1.0.0"
+
+/* kernel includes */
+#include <linux/i2c.h>
+#include <linux/delay.h>
+
+#include "radio-si470x.h"
+
+
+/* I2C Device ID List */
+static const struct i2c_device_id si470x_i2c_id[] = {
+       /* Generic Entry */
+       { "si470x", 0 },
+       /* Terminating entry */
+       { }
+};
+MODULE_DEVICE_TABLE(i2c, si470x_i2c_id);
+
+
+
+/**************************************************************************
+ * Module Parameters
+ **************************************************************************/
+
+/* Radio Nr */
+static int radio_nr = -1;
+module_param(radio_nr, int, 0444);
+MODULE_PARM_DESC(radio_nr, "Radio Nr");
+
+
+
+/**************************************************************************
+ * I2C Definitions
+ **************************************************************************/
+
+/* Write starts with the upper byte of register 0x02 */
+#define WRITE_REG_NUM          8
+#define WRITE_INDEX(i)         (i + 0x02)
+
+/* Read starts with the upper byte of register 0x0a */
+#define READ_REG_NUM           RADIO_REGISTER_NUM
+#define READ_INDEX(i)          ((i + RADIO_REGISTER_NUM - 0x0a) % READ_REG_NUM)
+
+
+
+/**************************************************************************
+ * General Driver Functions - REGISTERs
+ **************************************************************************/
+
+/*
+ * si470x_get_register - read register
+ */
+int si470x_get_register(struct si470x_device *radio, int regnr)
+{
+       u16 buf[READ_REG_NUM];
+       struct i2c_msg msgs[1] = {
+               { radio->client->addr, I2C_M_RD, sizeof(u16) * READ_REG_NUM,
+                       (void *)buf },
+       };
+
+       if (i2c_transfer(radio->client->adapter, msgs, 1) != 1)
+               return -EIO;
+
+       radio->registers[regnr] = __be16_to_cpu(buf[READ_INDEX(regnr)]);
+
+       return 0;
+}
+
+
+/*
+ * si470x_set_register - write register
+ */
+int si470x_set_register(struct si470x_device *radio, int regnr)
+{
+       int i;
+       u16 buf[WRITE_REG_NUM];
+       struct i2c_msg msgs[1] = {
+               { radio->client->addr, 0, sizeof(u16) * WRITE_REG_NUM,
+                       (void *)buf },
+       };
+
+       for (i = 0; i < WRITE_REG_NUM; i++)
+               buf[i] = __cpu_to_be16(radio->registers[WRITE_INDEX(i)]);
+
+       if (i2c_transfer(radio->client->adapter, msgs, 1) != 1)
+               return -EIO;
+
+       return 0;
+}
+
+
+
+/**************************************************************************
+ * General Driver Functions - ENTIRE REGISTERS
+ **************************************************************************/
+
+/*
+ * si470x_get_all_registers - read entire registers
+ */
+static int si470x_get_all_registers(struct si470x_device *radio)
+{
+       int i;
+       u16 buf[READ_REG_NUM];
+       struct i2c_msg msgs[1] = {
+               { radio->client->addr, I2C_M_RD, sizeof(u16) * READ_REG_NUM,
+                       (void *)buf },
+       };
+
+       if (i2c_transfer(radio->client->adapter, msgs, 1) != 1)
+               return -EIO;
+
+       for (i = 0; i < READ_REG_NUM; i++)
+               radio->registers[i] = __be16_to_cpu(buf[READ_INDEX(i)]);
+
+       return 0;
+}
+
+
+
+/**************************************************************************
+ * General Driver Functions - DISCONNECT_CHECK
+ **************************************************************************/
+
+/*
+ * si470x_disconnect_check - check whether radio disconnects
+ */
+int si470x_disconnect_check(struct si470x_device *radio)
+{
+       return 0;
+}
+
+
+
+/**************************************************************************
+ * File Operations Interface
+ **************************************************************************/
+
+/*
+ * si470x_fops_open - file open
+ */
+static int si470x_fops_open(struct file *file)
+{
+       struct si470x_device *radio = video_drvdata(file);
+       int retval = 0;
+
+       mutex_lock(&radio->lock);
+       radio->users++;
+
+       if (radio->users == 1)
+               /* start radio */
+               retval = si470x_start(radio);
+
+       mutex_unlock(&radio->lock);
+
+       return retval;
+}
+
+
+/*
+ * si470x_fops_release - file release
+ */
+static int si470x_fops_release(struct file *file)
+{
+       struct si470x_device *radio = video_drvdata(file);
+       int retval = 0;
+
+       /* safety check */
+       if (!radio)
+               return -ENODEV;
+
+       mutex_lock(&radio->lock);
+       radio->users--;
+       if (radio->users == 0)
+               /* stop radio */
+               retval = si470x_stop(radio);
+
+       mutex_unlock(&radio->lock);
+
+       return retval;
+}
+
+
+/*
+ * si470x_fops - file operations interface
+ */
+const struct v4l2_file_operations si470x_fops = {
+       .owner          = THIS_MODULE,
+       .ioctl          = video_ioctl2,
+       .open           = si470x_fops_open,
+       .release        = si470x_fops_release,
+};
+
+
+
+/**************************************************************************
+ * Video4Linux Interface
+ **************************************************************************/
+
+/*
+ * si470x_vidioc_querycap - query device capabilities
+ */
+int si470x_vidioc_querycap(struct file *file, void *priv,
+               struct v4l2_capability *capability)
+{
+       strlcpy(capability->driver, DRIVER_NAME, sizeof(capability->driver));
+       strlcpy(capability->card, DRIVER_CARD, sizeof(capability->card));
+       capability->version = DRIVER_KERNEL_VERSION;
+       capability->capabilities = V4L2_CAP_HW_FREQ_SEEK |
+               V4L2_CAP_TUNER | V4L2_CAP_RADIO;
+
+       return 0;
+}
+
+
+
+/**************************************************************************
+ * I2C Interface
+ **************************************************************************/
+
+/*
+ * si470x_i2c_probe - probe for the device
+ */
+static int __devinit si470x_i2c_probe(struct i2c_client *client,
+               const struct i2c_device_id *id)
+{
+       struct si470x_device *radio;
+       int retval = 0;
+       unsigned char version_warning = 0;
+
+       /* private data allocation and initialization */
+       radio = kzalloc(sizeof(struct si470x_device), GFP_KERNEL);
+       if (!radio) {
+               retval = -ENOMEM;
+               goto err_initial;
+       }
+       radio->users = 0;
+       radio->client = client;
+       mutex_init(&radio->lock);
+
+       /* video device allocation and initialization */
+       radio->videodev = video_device_alloc();
+       if (!radio->videodev) {
+               retval = -ENOMEM;
+               goto err_radio;
+       }
+       memcpy(radio->videodev, &si470x_viddev_template,
+                       sizeof(si470x_viddev_template));
+       video_set_drvdata(radio->videodev, radio);
+
+       /* power up : need 110ms */
+       radio->registers[POWERCFG] = POWERCFG_ENABLE;
+       if (si470x_set_register(radio, POWERCFG) < 0) {
+               retval = -EIO;
+               goto err_all;
+       }
+       msleep(110);
+
+       /* get device and chip versions */
+       if (si470x_get_all_registers(radio) < 0) {
+               retval = -EIO;
+               goto err_video;
+       }
+       dev_info(&client->dev, "DeviceID=0x%4.4hx ChipID=0x%4.4hx\n",
+                       radio->registers[DEVICEID], radio->registers[CHIPID]);
+       if ((radio->registers[CHIPID] & CHIPID_FIRMWARE) < RADIO_FW_VERSION) {
+               dev_warn(&client->dev,
+                       "This driver is known to work with "
+                       "firmware version %hu,\n", RADIO_FW_VERSION);
+               dev_warn(&client->dev,
+                       "but the device has firmware version %hu.\n",
+                       radio->registers[CHIPID] & CHIPID_FIRMWARE);
+               version_warning = 1;
+       }
+
+       /* give out version warning */
+       if (version_warning == 1) {
+               dev_warn(&client->dev,
+                       "If you have some trouble using this driver,\n");
+               dev_warn(&client->dev,
+                       "please report to V4L ML at "
+                       "linux-media@vger.kernel.org\n");
+       }
+
+       /* set initial frequency */
+       si470x_set_freq(radio, 87.5 * FREQ_MUL); /* available in all regions */
+
+       /* register video device */
+       retval = video_register_device(radio->videodev, VFL_TYPE_RADIO,
+                       radio_nr);
+       if (retval) {
+               dev_warn(&client->dev, "Could not register video device\n");
+               goto err_all;
+       }
+       i2c_set_clientdata(client, radio);
+
+       return 0;
+err_all:
+err_video:
+       video_device_release(radio->videodev);
+err_radio:
+       kfree(radio);
+err_initial:
+       return retval;
+}
+
+
+/*
+ * si470x_i2c_remove - remove the device
+ */
+static __devexit int si470x_i2c_remove(struct i2c_client *client)
+{
+       struct si470x_device *radio = i2c_get_clientdata(client);
+
+       video_unregister_device(radio->videodev);
+       kfree(radio);
+       i2c_set_clientdata(client, NULL);
+
+       return 0;
+}
+
+
+/*
+ * si470x_i2c_driver - i2c driver interface
+ */
+static struct i2c_driver si470x_i2c_driver = {
+       .driver = {
+               .name           = "si470x",
+               .owner          = THIS_MODULE,
+       },
+       .probe                  = si470x_i2c_probe,
+       .remove                 = __devexit_p(si470x_i2c_remove),
+       .id_table               = si470x_i2c_id,
+};
+
+
+
+/**************************************************************************
+ * Module Interface
+ **************************************************************************/
+
+/*
+ * si470x_i2c_init - module init
+ */
+static int __init si470x_i2c_init(void)
+{
+       printk(KERN_INFO DRIVER_DESC ", Version " DRIVER_VERSION "\n");
+       return i2c_add_driver(&si470x_i2c_driver);
+}
+
+
+/*
+ * si470x_i2c_exit - module exit
+ */
+static void __exit si470x_i2c_exit(void)
+{
+       i2c_del_driver(&si470x_i2c_driver);
+}
+
+
+module_init(si470x_i2c_init);
+module_exit(si470x_i2c_exit);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR(DRIVER_AUTHOR);
+MODULE_DESCRIPTION(DRIVER_DESC);
+MODULE_VERSION(DRIVER_VERSION);
diff --git a/drivers/media/radio/si470x/radio-si470x-usb.c b/drivers/media/radio/si470x/radio-si470x-usb.c
new file mode 100644 (file)
index 0000000..f2d0e1d
--- /dev/null
@@ -0,0 +1,988 @@
+/*
+ *  drivers/media/radio/si470x/radio-si470x-usb.c
+ *
+ *  USB driver for radios with Silicon Labs Si470x FM Radio Receivers
+ *
+ *  Copyright (c) 2009 Tobias Lorenz <tobias.lorenz@gmx.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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+
+/*
+ * ToDo:
+ * - add firmware download/update support
+ */
+
+
+/* driver definitions */
+#define DRIVER_AUTHOR "Tobias Lorenz <tobias.lorenz@gmx.net>"
+#define DRIVER_KERNEL_VERSION KERNEL_VERSION(1, 0, 10)
+#define DRIVER_CARD "Silicon Labs Si470x FM Radio Receiver"
+#define DRIVER_DESC "USB radio driver for Si470x FM Radio Receivers"
+#define DRIVER_VERSION "1.0.10"
+
+/* kernel includes */
+#include <linux/usb.h>
+#include <linux/hid.h>
+
+#include "radio-si470x.h"
+
+
+/* USB Device ID List */
+static struct usb_device_id si470x_usb_driver_id_table[] = {
+       /* Silicon Labs USB FM Radio Reference Design */
+       { USB_DEVICE_AND_INTERFACE_INFO(0x10c4, 0x818a, USB_CLASS_HID, 0, 0) },
+       /* ADS/Tech FM Radio Receiver (formerly Instant FM Music) */
+       { USB_DEVICE_AND_INTERFACE_INFO(0x06e1, 0xa155, USB_CLASS_HID, 0, 0) },
+       /* KWorld USB FM Radio SnapMusic Mobile 700 (FM700) */
+       { USB_DEVICE_AND_INTERFACE_INFO(0x1b80, 0xd700, USB_CLASS_HID, 0, 0) },
+       /* Sanei Electric, Inc. FM USB Radio (sold as DealExtreme.com PCear) */
+       { USB_DEVICE_AND_INTERFACE_INFO(0x10c5, 0x819a, USB_CLASS_HID, 0, 0) },
+       /* Terminating entry */
+       { }
+};
+MODULE_DEVICE_TABLE(usb, si470x_usb_driver_id_table);
+
+
+
+/**************************************************************************
+ * Module Parameters
+ **************************************************************************/
+
+/* Radio Nr */
+static int radio_nr = -1;
+module_param(radio_nr, int, 0444);
+MODULE_PARM_DESC(radio_nr, "Radio Nr");
+
+/* USB timeout */
+static unsigned int usb_timeout = 500;
+module_param(usb_timeout, uint, 0644);
+MODULE_PARM_DESC(usb_timeout, "USB timeout (ms): *500*");
+
+/* RDS buffer blocks */
+static unsigned int rds_buf = 100;
+module_param(rds_buf, uint, 0444);
+MODULE_PARM_DESC(rds_buf, "RDS buffer entries: *100*");
+
+/* RDS maximum block errors */
+static unsigned short max_rds_errors = 1;
+/* 0 means   0  errors requiring correction */
+/* 1 means 1-2  errors requiring correction (used by original USBRadio.exe) */
+/* 2 means 3-5  errors requiring correction */
+/* 3 means   6+ errors or errors in checkword, correction not possible */
+module_param(max_rds_errors, ushort, 0644);
+MODULE_PARM_DESC(max_rds_errors, "RDS maximum block errors: *1*");
+
+
+
+/**************************************************************************
+ * USB HID Reports
+ **************************************************************************/
+
+/* Reports 1-16 give direct read/write access to the 16 Si470x registers */
+/* with the (REPORT_ID - 1) corresponding to the register address across USB */
+/* endpoint 0 using GET_REPORT and SET_REPORT */
+#define REGISTER_REPORT_SIZE   (RADIO_REGISTER_SIZE + 1)
+#define REGISTER_REPORT(reg)   ((reg) + 1)
+
+/* Report 17 gives direct read/write access to the entire Si470x register */
+/* map across endpoint 0 using GET_REPORT and SET_REPORT */
+#define ENTIRE_REPORT_SIZE     (RADIO_REGISTER_NUM * RADIO_REGISTER_SIZE + 1)
+#define ENTIRE_REPORT          17
+
+/* Report 18 is used to send the lowest 6 Si470x registers up the HID */
+/* interrupt endpoint 1 to Windows every 20 milliseconds for status */
+#define RDS_REPORT_SIZE                (RDS_REGISTER_NUM * RADIO_REGISTER_SIZE + 1)
+#define RDS_REPORT             18
+
+/* Report 19: LED state */
+#define LED_REPORT_SIZE                3
+#define LED_REPORT             19
+
+/* Report 19: stream */
+#define STREAM_REPORT_SIZE     3
+#define STREAM_REPORT          19
+
+/* Report 20: scratch */
+#define SCRATCH_PAGE_SIZE      63
+#define SCRATCH_REPORT_SIZE    (SCRATCH_PAGE_SIZE + 1)
+#define SCRATCH_REPORT         20
+
+/* Reports 19-22: flash upgrade of the C8051F321 */
+#define WRITE_REPORT_SIZE      4
+#define WRITE_REPORT           19
+#define FLASH_REPORT_SIZE      64
+#define FLASH_REPORT           20
+#define CRC_REPORT_SIZE                3
+#define CRC_REPORT             21
+#define RESPONSE_REPORT_SIZE   2
+#define RESPONSE_REPORT                22
+
+/* Report 23: currently unused, but can accept 60 byte reports on the HID */
+/* interrupt out endpoint 2 every 1 millisecond */
+#define UNUSED_REPORT          23
+
+
+
+/**************************************************************************
+ * Software/Hardware Versions from Scratch Page
+ **************************************************************************/
+#define RADIO_SW_VERSION_NOT_BOOTLOADABLE      6
+#define RADIO_SW_VERSION                       7
+#define RADIO_HW_VERSION                       1
+
+
+
+/**************************************************************************
+ * LED State Definitions
+ **************************************************************************/
+#define LED_COMMAND            0x35
+
+#define NO_CHANGE_LED          0x00
+#define ALL_COLOR_LED          0x01    /* streaming state */
+#define BLINK_GREEN_LED                0x02    /* connect state */
+#define BLINK_RED_LED          0x04
+#define BLINK_ORANGE_LED       0x10    /* disconnect state */
+#define SOLID_GREEN_LED                0x20    /* tuning/seeking state */
+#define SOLID_RED_LED          0x40    /* bootload state */
+#define SOLID_ORANGE_LED       0x80
+
+
+
+/**************************************************************************
+ * Stream State Definitions
+ **************************************************************************/
+#define STREAM_COMMAND 0x36
+#define STREAM_VIDPID  0x00
+#define STREAM_AUDIO   0xff
+
+
+
+/**************************************************************************
+ * Bootloader / Flash Commands
+ **************************************************************************/
+
+/* unique id sent to bootloader and required to put into a bootload state */
+#define UNIQUE_BL_ID           0x34
+
+/* mask for the flash data */
+#define FLASH_DATA_MASK                0x55
+
+/* bootloader commands */
+#define GET_SW_VERSION_COMMAND 0x00
+#define SET_PAGE_COMMAND       0x01
+#define ERASE_PAGE_COMMAND     0x02
+#define WRITE_PAGE_COMMAND     0x03
+#define CRC_ON_PAGE_COMMAND    0x04
+#define READ_FLASH_BYTE_COMMAND        0x05
+#define RESET_DEVICE_COMMAND   0x06
+#define GET_HW_VERSION_COMMAND 0x07
+#define BLANK                  0xff
+
+/* bootloader command responses */
+#define COMMAND_OK             0x01
+#define COMMAND_FAILED         0x02
+#define COMMAND_PENDING                0x03
+
+
+
+/**************************************************************************
+ * General Driver Functions - REGISTER_REPORTs
+ **************************************************************************/
+
+/*
+ * si470x_get_report - receive a HID report
+ */
+static int si470x_get_report(struct si470x_device *radio, void *buf, int size)
+{
+       unsigned char *report = (unsigned char *) buf;
+       int retval;
+
+       retval = usb_control_msg(radio->usbdev,
+               usb_rcvctrlpipe(radio->usbdev, 0),
+               HID_REQ_GET_REPORT,
+               USB_TYPE_CLASS | USB_RECIP_INTERFACE | USB_DIR_IN,
+               report[0], 2,
+               buf, size, usb_timeout);
+
+       if (retval < 0)
+               dev_warn(&radio->intf->dev,
+                       "si470x_get_report: usb_control_msg returned %d\n",
+                       retval);
+       return retval;
+}
+
+
+/*
+ * si470x_set_report - send a HID report
+ */
+static int si470x_set_report(struct si470x_device *radio, void *buf, int size)
+{
+       unsigned char *report = (unsigned char *) buf;
+       int retval;
+
+       retval = usb_control_msg(radio->usbdev,
+               usb_sndctrlpipe(radio->usbdev, 0),
+               HID_REQ_SET_REPORT,
+               USB_TYPE_CLASS | USB_RECIP_INTERFACE | USB_DIR_OUT,
+               report[0], 2,
+               buf, size, usb_timeout);
+
+       if (retval < 0)
+               dev_warn(&radio->intf->dev,
+                       "si470x_set_report: usb_control_msg returned %d\n",
+                       retval);
+       return retval;
+}
+
+
+/*
+ * si470x_get_register - read register
+ */
+int si470x_get_register(struct si470x_device *radio, int regnr)
+{
+       unsigned char buf[REGISTER_REPORT_SIZE];
+       int retval;
+
+       buf[0] = REGISTER_REPORT(regnr);
+
+       retval = si470x_get_report(radio, (void *) &buf, sizeof(buf));
+
+       if (retval >= 0)
+               radio->registers[regnr] = get_unaligned_be16(&buf[1]);
+
+       return (retval < 0) ? -EINVAL : 0;
+}
+
+
+/*
+ * si470x_set_register - write register
+ */
+int si470x_set_register(struct si470x_device *radio, int regnr)
+{
+       unsigned char buf[REGISTER_REPORT_SIZE];
+       int retval;
+
+       buf[0] = REGISTER_REPORT(regnr);
+       put_unaligned_be16(radio->registers[regnr], &buf[1]);
+
+       retval = si470x_set_report(radio, (void *) &buf, sizeof(buf));
+
+       return (retval < 0) ? -EINVAL : 0;
+}
+
+
+
+/**************************************************************************
+ * General Driver Functions - ENTIRE_REPORT
+ **************************************************************************/
+
+/*
+ * si470x_get_all_registers - read entire registers
+ */
+static int si470x_get_all_registers(struct si470x_device *radio)
+{
+       unsigned char buf[ENTIRE_REPORT_SIZE];
+       int retval;
+       unsigned char regnr;
+
+       buf[0] = ENTIRE_REPORT;
+
+       retval = si470x_get_report(radio, (void *) &buf, sizeof(buf));
+
+       if (retval >= 0)
+               for (regnr = 0; regnr < RADIO_REGISTER_NUM; regnr++)
+                       radio->registers[regnr] = get_unaligned_be16(
+                               &buf[regnr * RADIO_REGISTER_SIZE + 1]);
+
+       return (retval < 0) ? -EINVAL : 0;
+}
+
+
+
+/**************************************************************************
+ * General Driver Functions - LED_REPORT
+ **************************************************************************/
+
+/*
+ * si470x_set_led_state - sets the led state
+ */
+static int si470x_set_led_state(struct si470x_device *radio,
+               unsigned char led_state)
+{
+       unsigned char buf[LED_REPORT_SIZE];
+       int retval;
+
+       buf[0] = LED_REPORT;
+       buf[1] = LED_COMMAND;
+       buf[2] = led_state;
+
+       retval = si470x_set_report(radio, (void *) &buf, sizeof(buf));
+
+       return (retval < 0) ? -EINVAL : 0;
+}
+
+
+
+/**************************************************************************
+ * General Driver Functions - SCRATCH_REPORT
+ **************************************************************************/
+
+/*
+ * si470x_get_scratch_versions - gets the scratch page and version infos
+ */
+static int si470x_get_scratch_page_versions(struct si470x_device *radio)
+{
+       unsigned char buf[SCRATCH_REPORT_SIZE];
+       int retval;
+
+       buf[0] = SCRATCH_REPORT;
+
+       retval = si470x_get_report(radio, (void *) &buf, sizeof(buf));
+
+       if (retval < 0)
+               dev_warn(&radio->intf->dev, "si470x_get_scratch: "
+                       "si470x_get_report returned %d\n", retval);
+       else {
+               radio->software_version = buf[1];
+               radio->hardware_version = buf[2];
+       }
+
+       return (retval < 0) ? -EINVAL : 0;
+}
+
+
+
+/**************************************************************************
+ * General Driver Functions - DISCONNECT_CHECK
+ **************************************************************************/
+
+/*
+ * si470x_disconnect_check - check whether radio disconnects
+ */
+int si470x_disconnect_check(struct si470x_device *radio)
+{
+       if (radio->disconnected)
+               return -EIO;
+       else
+               return 0;
+}
+
+
+
+/**************************************************************************
+ * RDS Driver Functions
+ **************************************************************************/
+
+/*
+ * si470x_int_in_callback - rds callback and processing function
+ *
+ * TODO: do we need to use mutex locks in some sections?
+ */
+static void si470x_int_in_callback(struct urb *urb)
+{
+       struct si470x_device *radio = urb->context;
+       unsigned char buf[RDS_REPORT_SIZE];
+       int retval;
+       unsigned char regnr;
+       unsigned char blocknum;
+       unsigned short bler; /* rds block errors */
+       unsigned short rds;
+       unsigned char tmpbuf[3];
+
+       if (urb->status) {
+               if (urb->status == -ENOENT ||
+                               urb->status == -ECONNRESET ||
+                               urb->status == -ESHUTDOWN) {
+                       return;
+               } else {
+                       dev_warn(&radio->intf->dev,
+                        "non-zero urb status (%d)\n", urb->status);
+                       goto resubmit; /* Maybe we can recover. */
+               }
+       }
+
+       /* safety checks */
+       if (radio->disconnected)
+               return;
+       if ((radio->registers[SYSCONFIG1] & SYSCONFIG1_RDS) == 0)
+               goto resubmit;
+
+       if (urb->actual_length > 0) {
+               /* Update RDS registers with URB data */
+               buf[0] = RDS_REPORT;
+               for (regnr = 0; regnr < RDS_REGISTER_NUM; regnr++)
+                       radio->registers[STATUSRSSI + regnr] =
+                           get_unaligned_be16(&radio->int_in_buffer[
+                               regnr * RADIO_REGISTER_SIZE + 1]);
+               /* get rds blocks */
+               if ((radio->registers[STATUSRSSI] & STATUSRSSI_RDSR) == 0) {
+                       /* No RDS group ready, better luck next time */
+                       goto resubmit;
+               }
+               if ((radio->registers[STATUSRSSI] & STATUSRSSI_RDSS) == 0) {
+                       /* RDS decoder not synchronized */
+                       goto resubmit;
+               }
+               for (blocknum = 0; blocknum < 4; blocknum++) {
+                       switch (blocknum) {
+                       default:
+                               bler = (radio->registers[STATUSRSSI] &
+                                               STATUSRSSI_BLERA) >> 9;
+                               rds = radio->registers[RDSA];
+                               break;
+                       case 1:
+                               bler = (radio->registers[READCHAN] &
+                                               READCHAN_BLERB) >> 14;
+                               rds = radio->registers[RDSB];
+                               break;
+                       case 2:
+                               bler = (radio->registers[READCHAN] &
+                                               READCHAN_BLERC) >> 12;
+                               rds = radio->registers[RDSC];
+                               break;
+                       case 3:
+                               bler = (radio->registers[READCHAN] &
+                                               READCHAN_BLERD) >> 10;
+                               rds = radio->registers[RDSD];
+                               break;
+                       };
+
+                       /* Fill the V4L2 RDS buffer */
+                       put_unaligned_le16(rds, &tmpbuf);
+                       tmpbuf[2] = blocknum;           /* offset name */
+                       tmpbuf[2] |= blocknum << 3;     /* received offset */
+                       if (bler > max_rds_errors)
+                               tmpbuf[2] |= 0x80; /* uncorrectable errors */
+                       else if (bler > 0)
+                               tmpbuf[2] |= 0x40; /* corrected error(s) */
+
+                       /* copy RDS block to internal buffer */
+                       memcpy(&radio->buffer[radio->wr_index], &tmpbuf, 3);
+                       radio->wr_index += 3;
+
+                       /* wrap write pointer */
+                       if (radio->wr_index >= radio->buf_size)
+                               radio->wr_index = 0;
+
+                       /* check for overflow */
+                       if (radio->wr_index == radio->rd_index) {
+                               /* increment and wrap read pointer */
+                               radio->rd_index += 3;
+                               if (radio->rd_index >= radio->buf_size)
+                                       radio->rd_index = 0;
+                       }
+               }
+               if (radio->wr_index != radio->rd_index)
+                       wake_up_interruptible(&radio->read_queue);
+       }
+
+resubmit:
+       /* Resubmit if we're still running. */
+       if (radio->int_in_running && radio->usbdev) {
+               retval = usb_submit_urb(radio->int_in_urb, GFP_ATOMIC);
+               if (retval) {
+                       dev_warn(&radio->intf->dev,
+                              "resubmitting urb failed (%d)", retval);
+                       radio->int_in_running = 0;
+               }
+       }
+}
+
+
+
+/**************************************************************************
+ * File Operations Interface
+ **************************************************************************/
+
+/*
+ * si470x_fops_read - read RDS data
+ */
+static ssize_t si470x_fops_read(struct file *file, char __user *buf,
+               size_t count, loff_t *ppos)
+{
+       struct si470x_device *radio = video_drvdata(file);
+       int retval = 0;
+       unsigned int block_count = 0;
+
+       /* switch on rds reception */
+       if ((radio->registers[SYSCONFIG1] & SYSCONFIG1_RDS) == 0)
+               si470x_rds_on(radio);
+
+       /* block if no new data available */
+       while (radio->wr_index == radio->rd_index) {
+               if (file->f_flags & O_NONBLOCK) {
+                       retval = -EWOULDBLOCK;
+                       goto done;
+               }
+               if (wait_event_interruptible(radio->read_queue,
+                       radio->wr_index != radio->rd_index) < 0) {
+                       retval = -EINTR;
+                       goto done;
+               }
+       }
+
+       /* calculate block count from byte count */
+       count /= 3;
+
+       /* copy RDS block out of internal buffer and to user buffer */
+       mutex_lock(&radio->lock);
+       while (block_count < count) {
+               if (radio->rd_index == radio->wr_index)
+                       break;
+
+               /* always transfer rds complete blocks */
+               if (copy_to_user(buf, &radio->buffer[radio->rd_index], 3))
+                       /* retval = -EFAULT; */
+                       break;
+
+               /* increment and wrap read pointer */
+               radio->rd_index += 3;
+               if (radio->rd_index >= radio->buf_size)
+                       radio->rd_index = 0;
+
+               /* increment counters */
+               block_count++;
+               buf += 3;
+               retval += 3;
+       }
+       mutex_unlock(&radio->lock);
+
+done:
+       return retval;
+}
+
+
+/*
+ * si470x_fops_poll - poll RDS data
+ */
+static unsigned int si470x_fops_poll(struct file *file,
+               struct poll_table_struct *pts)
+{
+       struct si470x_device *radio = video_drvdata(file);
+       int retval = 0;
+
+       /* switch on rds reception */
+       if ((radio->registers[SYSCONFIG1] & SYSCONFIG1_RDS) == 0)
+               si470x_rds_on(radio);
+
+       poll_wait(file, &radio->read_queue, pts);
+
+       if (radio->rd_index != radio->wr_index)
+               retval = POLLIN | POLLRDNORM;
+
+       return retval;
+}
+
+
+/*
+ * si470x_fops_open - file open
+ */
+static int si470x_fops_open(struct file *file)
+{
+       struct si470x_device *radio = video_drvdata(file);
+       int retval;
+
+       lock_kernel();
+       radio->users++;
+
+       retval = usb_autopm_get_interface(radio->intf);
+       if (retval < 0) {
+               radio->users--;
+               retval = -EIO;
+               goto done;
+       }
+
+       if (radio->users == 1) {
+               /* start radio */
+               retval = si470x_start(radio);
+               if (retval < 0) {
+                       usb_autopm_put_interface(radio->intf);
+                       goto done;
+               }
+
+               /* initialize interrupt urb */
+               usb_fill_int_urb(radio->int_in_urb, radio->usbdev,
+                       usb_rcvintpipe(radio->usbdev,
+                       radio->int_in_endpoint->bEndpointAddress),
+                       radio->int_in_buffer,
+                       le16_to_cpu(radio->int_in_endpoint->wMaxPacketSize),
+                       si470x_int_in_callback,
+                       radio,
+                       radio->int_in_endpoint->bInterval);
+
+               radio->int_in_running = 1;
+               mb();
+
+               retval = usb_submit_urb(radio->int_in_urb, GFP_KERNEL);
+               if (retval) {
+                       dev_info(&radio->intf->dev,
+                                "submitting int urb failed (%d)\n", retval);
+                       radio->int_in_running = 0;
+                       usb_autopm_put_interface(radio->intf);
+               }
+       }
+
+done:
+       unlock_kernel();
+       return retval;
+}
+
+
+/*
+ * si470x_fops_release - file release
+ */
+static int si470x_fops_release(struct file *file)
+{
+       struct si470x_device *radio = video_drvdata(file);
+       int retval = 0;
+
+       /* safety check */
+       if (!radio) {
+               retval = -ENODEV;
+               goto done;
+       }
+
+       mutex_lock(&radio->disconnect_lock);
+       radio->users--;
+       if (radio->users == 0) {
+               /* shutdown interrupt handler */
+               if (radio->int_in_running) {
+                       radio->int_in_running = 0;
+               if (radio->int_in_urb)
+                       usb_kill_urb(radio->int_in_urb);
+               }
+
+               if (radio->disconnected) {
+                       video_unregister_device(radio->videodev);
+                       kfree(radio->int_in_buffer);
+                       kfree(radio->buffer);
+                       kfree(radio);
+                       goto unlock;
+               }
+
+               /* cancel read processes */
+               wake_up_interruptible(&radio->read_queue);
+
+               /* stop radio */
+               retval = si470x_stop(radio);
+               usb_autopm_put_interface(radio->intf);
+       }
+unlock:
+       mutex_unlock(&radio->disconnect_lock);
+done:
+       return retval;
+}
+
+
+/*
+ * si470x_fops - file operations interface
+ */
+const struct v4l2_file_operations si470x_fops = {
+       .owner          = THIS_MODULE,
+       .read           = si470x_fops_read,
+       .poll           = si470x_fops_poll,
+       .ioctl          = video_ioctl2,
+       .open           = si470x_fops_open,
+       .release        = si470x_fops_release,
+};
+
+
+
+/**************************************************************************
+ * Video4Linux Interface
+ **************************************************************************/
+
+/*
+ * si470x_vidioc_querycap - query device capabilities
+ */
+int si470x_vidioc_querycap(struct file *file, void *priv,
+               struct v4l2_capability *capability)
+{
+       struct si470x_device *radio = video_drvdata(file);
+
+       strlcpy(capability->driver, DRIVER_NAME, sizeof(capability->driver));
+       strlcpy(capability->card, DRIVER_CARD, sizeof(capability->card));
+       usb_make_path(radio->usbdev, capability->bus_info,
+                       sizeof(capability->bus_info));
+       capability->version = DRIVER_KERNEL_VERSION;
+       capability->capabilities = V4L2_CAP_HW_FREQ_SEEK |
+               V4L2_CAP_TUNER | V4L2_CAP_RADIO | V4L2_CAP_RDS_CAPTURE;
+
+       return 0;
+}
+
+
+
+/**************************************************************************
+ * USB Interface
+ **************************************************************************/
+
+/*
+ * si470x_usb_driver_probe - probe for the device
+ */
+static int si470x_usb_driver_probe(struct usb_interface *intf,
+               const struct usb_device_id *id)
+{
+       struct si470x_device *radio;
+       struct usb_host_interface *iface_desc;
+       struct usb_endpoint_descriptor *endpoint;
+       int i, int_end_size, retval = 0;
+       unsigned char version_warning = 0;
+
+       /* private data allocation and initialization */
+       radio = kzalloc(sizeof(struct si470x_device), GFP_KERNEL);
+       if (!radio) {
+               retval = -ENOMEM;
+               goto err_initial;
+       }
+       radio->users = 0;
+       radio->disconnected = 0;
+       radio->usbdev = interface_to_usbdev(intf);
+       radio->intf = intf;
+       mutex_init(&radio->disconnect_lock);
+       mutex_init(&radio->lock);
+
+       iface_desc = intf->cur_altsetting;
+
+       /* Set up interrupt endpoint information. */
+       for (i = 0; i < iface_desc->desc.bNumEndpoints; ++i) {
+               endpoint = &iface_desc->endpoint[i].desc;
+               if (((endpoint->bEndpointAddress & USB_ENDPOINT_DIR_MASK) ==
+                USB_DIR_IN) && ((endpoint->bmAttributes &
+                USB_ENDPOINT_XFERTYPE_MASK) == USB_ENDPOINT_XFER_INT))
+                       radio->int_in_endpoint = endpoint;
+       }
+       if (!radio->int_in_endpoint) {
+               dev_info(&intf->dev, "could not find interrupt in endpoint\n");
+               retval = -EIO;
+               goto err_radio;
+       }
+
+       int_end_size = le16_to_cpu(radio->int_in_endpoint->wMaxPacketSize);
+
+       radio->int_in_buffer = kmalloc(int_end_size, GFP_KERNEL);
+       if (!radio->int_in_buffer) {
+               dev_info(&intf->dev, "could not allocate int_in_buffer");
+               retval = -ENOMEM;
+               goto err_radio;
+       }
+
+       radio->int_in_urb = usb_alloc_urb(0, GFP_KERNEL);
+       if (!radio->int_in_urb) {
+               dev_info(&intf->dev, "could not allocate int_in_urb");
+               retval = -ENOMEM;
+               goto err_intbuffer;
+       }
+
+       /* video device allocation and initialization */
+       radio->videodev = video_device_alloc();
+       if (!radio->videodev) {
+               retval = -ENOMEM;
+               goto err_intbuffer;
+       }
+       memcpy(radio->videodev, &si470x_viddev_template,
+                       sizeof(si470x_viddev_template));
+       video_set_drvdata(radio->videodev, radio);
+
+       /* get device and chip versions */
+       if (si470x_get_all_registers(radio) < 0) {
+               retval = -EIO;
+               goto err_video;
+       }
+       dev_info(&intf->dev, "DeviceID=0x%4.4hx ChipID=0x%4.4hx\n",
+                       radio->registers[DEVICEID], radio->registers[CHIPID]);
+       if ((radio->registers[CHIPID] & CHIPID_FIRMWARE) < RADIO_FW_VERSION) {
+               dev_warn(&intf->dev,
+                       "This driver is known to work with "
+                       "firmware version %hu,\n", RADIO_FW_VERSION);
+               dev_warn(&intf->dev,
+                       "but the device has firmware version %hu.\n",
+                       radio->registers[CHIPID] & CHIPID_FIRMWARE);
+               version_warning = 1;
+       }
+
+       /* get software and hardware versions */
+       if (si470x_get_scratch_page_versions(radio) < 0) {
+               retval = -EIO;
+               goto err_video;
+       }
+       dev_info(&intf->dev, "software version %d, hardware version %d\n",
+                       radio->software_version, radio->hardware_version);
+       if (radio->software_version < RADIO_SW_VERSION) {
+               dev_warn(&intf->dev,
+                       "This driver is known to work with "
+                       "software version %hu,\n", RADIO_SW_VERSION);
+               dev_warn(&intf->dev,
+                       "but the device has software version %hu.\n",
+                       radio->software_version);
+               version_warning = 1;
+       }
+       if (radio->hardware_version < RADIO_HW_VERSION) {
+               dev_warn(&intf->dev,
+                       "This driver is known to work with "
+                       "hardware version %hu,\n", RADIO_HW_VERSION);
+               dev_warn(&intf->dev,
+                       "but the device has hardware version %hu.\n",
+                       radio->hardware_version);
+               version_warning = 1;
+       }
+
+       /* give out version warning */
+       if (version_warning == 1) {
+               dev_warn(&intf->dev,
+                       "If you have some trouble using this driver,\n");
+               dev_warn(&intf->dev,
+                       "please report to V4L ML at "
+                       "linux-media@vger.kernel.org\n");
+       }
+
+       /* set initial frequency */
+       si470x_set_freq(radio, 87.5 * FREQ_MUL); /* available in all regions */
+
+       /* set led to connect state */
+       si470x_set_led_state(radio, BLINK_GREEN_LED);
+
+       /* rds buffer allocation */
+       radio->buf_size = rds_buf * 3;
+       radio->buffer = kmalloc(radio->buf_size, GFP_KERNEL);
+       if (!radio->buffer) {
+               retval = -EIO;
+               goto err_video;
+       }
+
+       /* rds buffer configuration */
+       radio->wr_index = 0;
+       radio->rd_index = 0;
+       init_waitqueue_head(&radio->read_queue);
+
+       /* register video device */
+       retval = video_register_device(radio->videodev, VFL_TYPE_RADIO,
+                       radio_nr);
+       if (retval) {
+               dev_warn(&intf->dev, "Could not register video device\n");
+               goto err_all;
+       }
+       usb_set_intfdata(intf, radio);
+
+       return 0;
+err_all:
+       kfree(radio->buffer);
+err_video:
+       video_device_release(radio->videodev);
+err_intbuffer:
+       kfree(radio->int_in_buffer);
+err_radio:
+       kfree(radio);
+err_initial:
+       return retval;
+}
+
+
+/*
+ * si470x_usb_driver_suspend - suspend the device
+ */
+static int si470x_usb_driver_suspend(struct usb_interface *intf,
+               pm_message_t message)
+{
+       dev_info(&intf->dev, "suspending now...\n");
+
+       return 0;
+}
+
+
+/*
+ * si470x_usb_driver_resume - resume the device
+ */
+static int si470x_usb_driver_resume(struct usb_interface *intf)
+{
+       dev_info(&intf->dev, "resuming now...\n");
+
+       return 0;
+}
+
+
+/*
+ * si470x_usb_driver_disconnect - disconnect the device
+ */
+static void si470x_usb_driver_disconnect(struct usb_interface *intf)
+{
+       struct si470x_device *radio = usb_get_intfdata(intf);
+
+       mutex_lock(&radio->disconnect_lock);
+       radio->disconnected = 1;
+       usb_set_intfdata(intf, NULL);
+       if (radio->users == 0) {
+               /* set led to disconnect state */
+               si470x_set_led_state(radio, BLINK_ORANGE_LED);
+
+               /* Free data structures. */
+               usb_free_urb(radio->int_in_urb);
+
+               kfree(radio->int_in_buffer);
+               video_unregister_device(radio->videodev);
+               kfree(radio->buffer);
+               kfree(radio);
+       }
+       mutex_unlock(&radio->disconnect_lock);
+}
+
+
+/*
+ * si470x_usb_driver - usb driver interface
+ */
+static struct usb_driver si470x_usb_driver = {
+       .name                   = DRIVER_NAME,
+       .probe                  = si470x_usb_driver_probe,
+       .disconnect             = si470x_usb_driver_disconnect,
+       .suspend                = si470x_usb_driver_suspend,
+       .resume                 = si470x_usb_driver_resume,
+       .id_table               = si470x_usb_driver_id_table,
+       .supports_autosuspend   = 1,
+};
+
+
+
+/**************************************************************************
+ * Module Interface
+ **************************************************************************/
+
+/*
+ * si470x_module_init - module init
+ */
+static int __init si470x_module_init(void)
+{
+       printk(KERN_INFO DRIVER_DESC ", Version " DRIVER_VERSION "\n");
+       return usb_register(&si470x_usb_driver);
+}
+
+
+/*
+ * si470x_module_exit - module exit
+ */
+static void __exit si470x_module_exit(void)
+{
+       usb_deregister(&si470x_usb_driver);
+}
+
+
+module_init(si470x_module_init);
+module_exit(si470x_module_exit);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR(DRIVER_AUTHOR);
+MODULE_DESCRIPTION(DRIVER_DESC);
+MODULE_VERSION(DRIVER_VERSION);
diff --git a/drivers/media/radio/si470x/radio-si470x.h b/drivers/media/radio/si470x/radio-si470x.h
new file mode 100644 (file)
index 0000000..d0af194
--- /dev/null
@@ -0,0 +1,225 @@
+/*
+ *  drivers/media/radio/si470x/radio-si470x.h
+ *
+ *  Driver for radios with Silicon Labs Si470x FM Radio Receivers
+ *
+ *  Copyright (c) 2009 Tobias Lorenz <tobias.lorenz@gmx.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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+
+/* driver definitions */
+#define DRIVER_NAME "radio-si470x"
+
+
+/* kernel includes */
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/smp_lock.h>
+#include <linux/input.h>
+#include <linux/version.h>
+#include <linux/videodev2.h>
+#include <linux/mutex.h>
+#include <media/v4l2-common.h>
+#include <media/v4l2-ioctl.h>
+#include <media/rds.h>
+#include <asm/unaligned.h>
+
+
+
+/**************************************************************************
+ * Register Definitions
+ **************************************************************************/
+#define RADIO_REGISTER_SIZE    2       /* 16 register bit width */
+#define RADIO_REGISTER_NUM     16      /* DEVICEID   ... RDSD */
+#define RDS_REGISTER_NUM       6       /* STATUSRSSI ... RDSD */
+
+#define DEVICEID               0       /* Device ID */
+#define DEVICEID_PN            0xf000  /* bits 15..12: Part Number */
+#define DEVICEID_MFGID         0x0fff  /* bits 11..00: Manufacturer ID */
+
+#define CHIPID                 1       /* Chip ID */
+#define CHIPID_REV             0xfc00  /* bits 15..10: Chip Version */
+#define CHIPID_DEV             0x0200  /* bits 09..09: Device */
+#define CHIPID_FIRMWARE                0x01ff  /* bits 08..00: Firmware Version */
+
+#define POWERCFG               2       /* Power Configuration */
+#define POWERCFG_DSMUTE                0x8000  /* bits 15..15: Softmute Disable */
+#define POWERCFG_DMUTE         0x4000  /* bits 14..14: Mute Disable */
+#define POWERCFG_MONO          0x2000  /* bits 13..13: Mono Select */
+#define POWERCFG_RDSM          0x0800  /* bits 11..11: RDS Mode (Si4701 only) */
+#define POWERCFG_SKMODE                0x0400  /* bits 10..10: Seek Mode */
+#define POWERCFG_SEEKUP                0x0200  /* bits 09..09: Seek Direction */
+#define POWERCFG_SEEK          0x0100  /* bits 08..08: Seek */
+#define POWERCFG_DISABLE       0x0040  /* bits 06..06: Powerup Disable */
+#define POWERCFG_ENABLE                0x0001  /* bits 00..00: Powerup Enable */
+
+#define CHANNEL                        3       /* Channel */
+#define CHANNEL_TUNE           0x8000  /* bits 15..15: Tune */
+#define CHANNEL_CHAN           0x03ff  /* bits 09..00: Channel Select */
+
+#define SYSCONFIG1             4       /* System Configuration 1 */
+#define SYSCONFIG1_RDSIEN      0x8000  /* bits 15..15: RDS Interrupt Enable (Si4701 only) */
+#define SYSCONFIG1_STCIEN      0x4000  /* bits 14..14: Seek/Tune Complete Interrupt Enable */
+#define SYSCONFIG1_RDS         0x1000  /* bits 12..12: RDS Enable (Si4701 only) */
+#define SYSCONFIG1_DE          0x0800  /* bits 11..11: De-emphasis (0=75us 1=50us) */
+#define SYSCONFIG1_AGCD                0x0400  /* bits 10..10: AGC Disable */
+#define SYSCONFIG1_BLNDADJ     0x00c0  /* bits 07..06: Stereo/Mono Blend Level Adjustment */
+#define SYSCONFIG1_GPIO3       0x0030  /* bits 05..04: General Purpose I/O 3 */
+#define SYSCONFIG1_GPIO2       0x000c  /* bits 03..02: General Purpose I/O 2 */
+#define SYSCONFIG1_GPIO1       0x0003  /* bits 01..00: General Purpose I/O 1 */
+
+#define SYSCONFIG2             5       /* System Configuration 2 */
+#define SYSCONFIG2_SEEKTH      0xff00  /* bits 15..08: RSSI Seek Threshold */
+#define SYSCONFIG2_BAND                0x0080  /* bits 07..06: Band Select */
+#define SYSCONFIG2_SPACE       0x0030  /* bits 05..04: Channel Spacing */
+#define SYSCONFIG2_VOLUME      0x000f  /* bits 03..00: Volume */
+
+#define SYSCONFIG3             6       /* System Configuration 3 */
+#define SYSCONFIG3_SMUTER      0xc000  /* bits 15..14: Softmute Attack/Recover Rate */
+#define SYSCONFIG3_SMUTEA      0x3000  /* bits 13..12: Softmute Attenuation */
+#define SYSCONFIG3_SKSNR       0x00f0  /* bits 07..04: Seek SNR Threshold */
+#define SYSCONFIG3_SKCNT       0x000f  /* bits 03..00: Seek FM Impulse Detection Threshold */
+
+#define TEST1                  7       /* Test 1 */
+#define TEST1_AHIZEN           0x4000  /* bits 14..14: Audio High-Z Enable */
+
+#define TEST2                  8       /* Test 2 */
+/* TEST2 only contains reserved bits */
+
+#define BOOTCONFIG             9       /* Boot Configuration */
+/* BOOTCONFIG only contains reserved bits */
+
+#define STATUSRSSI             10      /* Status RSSI */
+#define STATUSRSSI_RDSR                0x8000  /* bits 15..15: RDS Ready (Si4701 only) */
+#define STATUSRSSI_STC         0x4000  /* bits 14..14: Seek/Tune Complete */
+#define STATUSRSSI_SF          0x2000  /* bits 13..13: Seek Fail/Band Limit */
+#define STATUSRSSI_AFCRL       0x1000  /* bits 12..12: AFC Rail */
+#define STATUSRSSI_RDSS                0x0800  /* bits 11..11: RDS Synchronized (Si4701 only) */
+#define STATUSRSSI_BLERA       0x0600  /* bits 10..09: RDS Block A Errors (Si4701 only) */
+#define STATUSRSSI_ST          0x0100  /* bits 08..08: Stereo Indicator */
+#define STATUSRSSI_RSSI                0x00ff  /* bits 07..00: RSSI (Received Signal Strength Indicator) */
+
+#define READCHAN               11      /* Read Channel */
+#define READCHAN_BLERB         0xc000  /* bits 15..14: RDS Block D Errors (Si4701 only) */
+#define READCHAN_BLERC         0x3000  /* bits 13..12: RDS Block C Errors (Si4701 only) */
+#define READCHAN_BLERD         0x0c00  /* bits 11..10: RDS Block B Errors (Si4701 only) */
+#define READCHAN_READCHAN      0x03ff  /* bits 09..00: Read Channel */
+
+#define RDSA                   12      /* RDSA */
+#define RDSA_RDSA              0xffff  /* bits 15..00: RDS Block A Data (Si4701 only) */
+
+#define RDSB                   13      /* RDSB */
+#define RDSB_RDSB              0xffff  /* bits 15..00: RDS Block B Data (Si4701 only) */
+
+#define RDSC                   14      /* RDSC */
+#define RDSC_RDSC              0xffff  /* bits 15..00: RDS Block C Data (Si4701 only) */
+
+#define RDSD                   15      /* RDSD */
+#define RDSD_RDSD              0xffff  /* bits 15..00: RDS Block D Data (Si4701 only) */
+
+
+
+/**************************************************************************
+ * General Driver Definitions
+ **************************************************************************/
+
+/*
+ * si470x_device - private data
+ */
+struct si470x_device {
+       struct video_device *videodev;
+
+       /* driver management */
+       unsigned int users;
+
+       /* Silabs internal registers (0..15) */
+       unsigned short registers[RADIO_REGISTER_NUM];
+
+       /* RDS receive buffer */
+       wait_queue_head_t read_queue;
+       struct mutex lock;              /* buffer locking */
+       unsigned char *buffer;          /* size is always multiple of three */
+       unsigned int buf_size;
+       unsigned int rd_index;
+       unsigned int wr_index;
+
+#if defined(CONFIG_USB_SI470X) || defined(CONFIG_USB_SI470X_MODULE)
+       /* reference to USB and video device */
+       struct usb_device *usbdev;
+       struct usb_interface *intf;
+
+       /* Interrupt endpoint handling */
+       char *int_in_buffer;
+       struct usb_endpoint_descriptor *int_in_endpoint;
+       struct urb *int_in_urb;
+       int int_in_running;
+
+       /* scratch page */
+       unsigned char software_version;
+       unsigned char hardware_version;
+
+       /* driver management */
+       unsigned char disconnected;
+       struct mutex disconnect_lock;
+#endif
+
+#if defined(CONFIG_I2C_SI470X) || defined(CONFIG_I2C_SI470X_MODULE)
+       struct i2c_client *client;
+#endif
+};
+
+
+
+/**************************************************************************
+ * Firmware Versions
+ **************************************************************************/
+
+#define RADIO_FW_VERSION       15
+
+
+
+/**************************************************************************
+ * Frequency Multiplicator
+ **************************************************************************/
+
+/*
+ * The frequency is set in units of 62.5 Hz when using V4L2_TUNER_CAP_LOW,
+ * 62.5 kHz otherwise.
+ * The tuner is able to have a channel spacing of 50, 100 or 200 kHz.
+ * tuner->capability is therefore set to V4L2_TUNER_CAP_LOW
+ * The FREQ_MUL is then: 1 MHz / 62.5 Hz = 16000
+ */
+#define FREQ_MUL (1000000 / 62.5)
+
+
+
+/**************************************************************************
+ * Common Functions
+ **************************************************************************/
+extern const struct v4l2_file_operations si470x_fops;
+extern struct video_device si470x_viddev_template;
+int si470x_get_register(struct si470x_device *radio, int regnr);
+int si470x_set_register(struct si470x_device *radio, int regnr);
+int si470x_disconnect_check(struct si470x_device *radio);
+int si470x_set_freq(struct si470x_device *radio, unsigned int freq);
+int si470x_start(struct si470x_device *radio);
+int si470x_stop(struct si470x_device *radio);
+int si470x_rds_on(struct si470x_device *radio);
+int si470x_vidioc_querycap(struct file *file, void *priv,
+               struct v4l2_capability *capability);
diff --git a/drivers/media/radio/si4713-i2c.c b/drivers/media/radio/si4713-i2c.c
new file mode 100644 (file)
index 0000000..6a0028e
--- /dev/null
@@ -0,0 +1,2060 @@
+/*
+ * drivers/media/radio/si4713-i2c.c
+ *
+ * Silicon Labs Si4713 FM Radio Transmitter I2C commands.
+ *
+ * Copyright (c) 2009 Nokia Corporation
+ * Contact: Eduardo Valentin <eduardo.valentin@nokia.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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include <linux/mutex.h>
+#include <linux/completion.h>
+#include <linux/delay.h>
+#include <linux/interrupt.h>
+#include <linux/i2c.h>
+#include <media/v4l2-device.h>
+#include <media/v4l2-ioctl.h>
+#include <media/v4l2-common.h>
+
+#include "si4713-i2c.h"
+
+/* module parameters */
+static int debug;
+module_param(debug, int, S_IRUGO | S_IWUSR);
+MODULE_PARM_DESC(debug, "Debug level (0 - 2)");
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Eduardo Valentin <eduardo.valentin@nokia.com>");
+MODULE_DESCRIPTION("I2C driver for Si4713 FM Radio Transmitter");
+MODULE_VERSION("0.0.1");
+
+#define DEFAULT_RDS_PI                 0x00
+#define DEFAULT_RDS_PTY                        0x00
+#define DEFAULT_RDS_PS_NAME            ""
+#define DEFAULT_RDS_RADIO_TEXT         DEFAULT_RDS_PS_NAME
+#define DEFAULT_RDS_DEVIATION          0x00C8
+#define DEFAULT_RDS_PS_REPEAT_COUNT    0x0003
+#define DEFAULT_LIMITER_RTIME          0x1392
+#define DEFAULT_LIMITER_DEV            0x102CA
+#define DEFAULT_PILOT_FREQUENCY        0x4A38
+#define DEFAULT_PILOT_DEVIATION                0x1A5E
+#define DEFAULT_ACOMP_ATIME            0x0000
+#define DEFAULT_ACOMP_RTIME            0xF4240L
+#define DEFAULT_ACOMP_GAIN             0x0F
+#define DEFAULT_ACOMP_THRESHOLD        (-0x28)
+#define DEFAULT_MUTE                   0x01
+#define DEFAULT_POWER_LEVEL            88
+#define DEFAULT_FREQUENCY              8800
+#define DEFAULT_PREEMPHASIS            FMPE_EU
+#define DEFAULT_TUNE_RNL               0xFF
+
+#define to_si4713_device(sd)   container_of(sd, struct si4713_device, sd)
+
+/* frequency domain transformation (using times 10 to avoid floats) */
+#define FREQDEV_UNIT   100000
+#define FREQV4L2_MULTI 625
+#define si4713_to_v4l2(f)      ((f * FREQDEV_UNIT) / FREQV4L2_MULTI)
+#define v4l2_to_si4713(f)      ((f * FREQV4L2_MULTI) / FREQDEV_UNIT)
+#define FREQ_RANGE_LOW                 7600
+#define FREQ_RANGE_HIGH                        10800
+
+#define MAX_ARGS 7
+
+#define RDS_BLOCK                      8
+#define RDS_BLOCK_CLEAR                        0x03
+#define RDS_BLOCK_LOAD                 0x04
+#define RDS_RADIOTEXT_2A               0x20
+#define RDS_RADIOTEXT_BLK_SIZE         4
+#define RDS_RADIOTEXT_INDEX_MAX                0x0F
+#define RDS_CARRIAGE_RETURN            0x0D
+
+#define rds_ps_nblocks(len)    ((len / RDS_BLOCK) + (len % RDS_BLOCK ? 1 : 0))
+
+#define get_status_bit(p, b, m)        (((p) & (m)) >> (b))
+#define set_bits(p, v, b, m)   (((p) & ~(m)) | ((v) << (b)))
+
+#define ATTACK_TIME_UNIT       500
+
+#define POWER_OFF                      0x00
+#define POWER_ON                       0x01
+
+#define msb(x)                  ((u8)((u16) x >> 8))
+#define lsb(x)                  ((u8)((u16) x &  0x00FF))
+#define compose_u16(msb, lsb)  (((u16)msb << 8) | lsb)
+#define check_command_failed(status)   (!(status & SI4713_CTS) || \
+                                       (status & SI4713_ERR))
+/* mute definition */
+#define set_mute(p)    ((p & 1) | ((p & 1) << 1));
+#define get_mute(p)    (p & 0x01)
+
+#ifdef DEBUG
+#define DBG_BUFFER(device, message, buffer, size)                      \
+       {                                                               \
+               int i;                                                  \
+               char str[(size)*5];                                     \
+               for (i = 0; i < size; i++)                              \
+                       sprintf(str + i * 5, " 0x%02x", buffer[i]);     \
+               v4l2_dbg(2, debug, device, "%s:%s\n", message, str);    \
+       }
+#else
+#define DBG_BUFFER(device, message, buffer, size)
+#endif
+
+/*
+ * Values for limiter release time (sorted by second column)
+ *     device  release
+ *     value   time (us)
+ */
+static long limiter_times[] = {
+       2000,   250,
+       1000,   500,
+       510,    1000,
+       255,    2000,
+       170,    3000,
+       127,    4020,
+       102,    5010,
+       85,     6020,
+       73,     7010,
+       64,     7990,
+       57,     8970,
+       51,     10030,
+       25,     20470,
+       17,     30110,
+       13,     39380,
+       10,     51190,
+       8,      63690,
+       7,      73140,
+       6,      85330,
+       5,      102390,
+};
+
+/*
+ * Values for audio compression release time (sorted by second column)
+ *     device  release
+ *     value   time (us)
+ */
+static unsigned long acomp_rtimes[] = {
+       0,      100000,
+       1,      200000,
+       2,      350000,
+       3,      525000,
+       4,      1000000,
+};
+
+/*
+ * Values for preemphasis (sorted by second column)
+ *     device  preemphasis
+ *     value   value (v4l2)
+ */
+static unsigned long preemphasis_values[] = {
+       FMPE_DISABLED,  V4L2_PREEMPHASIS_DISABLED,
+       FMPE_EU,        V4L2_PREEMPHASIS_50_uS,
+       FMPE_USA,       V4L2_PREEMPHASIS_75_uS,
+};
+
+static int usecs_to_dev(unsigned long usecs, unsigned long const array[],
+                       int size)
+{
+       int i;
+       int rval = -EINVAL;
+
+       for (i = 0; i < size / 2; i++)
+               if (array[(i * 2) + 1] >= usecs) {
+                       rval = array[i * 2];
+                       break;
+               }
+
+       return rval;
+}
+
+static unsigned long dev_to_usecs(int value, unsigned long const array[],
+                       int size)
+{
+       int i;
+       int rval = -EINVAL;
+
+       for (i = 0; i < size / 2; i++)
+               if (array[i * 2] == value) {
+                       rval = array[(i * 2) + 1];
+                       break;
+               }
+
+       return rval;
+}
+
+/* si4713_handler: IRQ handler, just complete work */
+static irqreturn_t si4713_handler(int irq, void *dev)
+{
+       struct si4713_device *sdev = dev;
+
+       v4l2_dbg(2, debug, &sdev->sd,
+                       "%s: sending signal to completion work.\n", __func__);
+       complete(&sdev->work);
+
+       return IRQ_HANDLED;
+}
+
+/*
+ * si4713_send_command - sends a command to si4713 and waits its response
+ * @sdev: si4713_device structure for the device we are communicating
+ * @command: command id
+ * @args: command arguments we are sending (up to 7)
+ * @argn: actual size of @args
+ * @response: buffer to place the expected response from the device (up to 15)
+ * @respn: actual size of @response
+ * @usecs: amount of time to wait before reading the response (in usecs)
+ */
+static int si4713_send_command(struct si4713_device *sdev, const u8 command,
+                               const u8 args[], const int argn,
+                               u8 response[], const int respn, const int usecs)
+{
+       struct i2c_client *client = v4l2_get_subdevdata(&sdev->sd);
+       u8 data1[MAX_ARGS + 1];
+       int err;
+
+       if (!client->adapter)
+               return -ENODEV;
+
+       /* First send the command and its arguments */
+       data1[0] = command;
+       memcpy(data1 + 1, args, argn);
+       DBG_BUFFER(&sdev->sd, "Parameters", data1, argn + 1);
+
+       err = i2c_master_send(client, data1, argn + 1);
+       if (err != argn + 1) {
+               v4l2_err(&sdev->sd, "Error while sending command 0x%02x\n",
+                       command);
+               return (err > 0) ? -EIO : err;
+       }
+
+       /* Wait response from interrupt */
+       if (!wait_for_completion_timeout(&sdev->work,
+                               usecs_to_jiffies(usecs) + 1))
+               v4l2_warn(&sdev->sd,
+                               "(%s) Device took too much time to answer.\n",
+                               __func__);
+
+       /* Then get the response */
+       err = i2c_master_recv(client, response, respn);
+       if (err != respn) {
+               v4l2_err(&sdev->sd,
+                       "Error while reading response for command 0x%02x\n",
+                       command);
+               return (err > 0) ? -EIO : err;
+       }
+
+       DBG_BUFFER(&sdev->sd, "Response", response, respn);
+       if (check_command_failed(response[0]))
+               return -EBUSY;
+
+       return 0;
+}
+
+/*
+ * si4713_read_property - reads a si4713 property
+ * @sdev: si4713_device structure for the device we are communicating
+ * @prop: property identification number
+ * @pv: property value to be returned on success
+ */
+static int si4713_read_property(struct si4713_device *sdev, u16 prop, u32 *pv)
+{
+       int err;
+       u8 val[SI4713_GET_PROP_NRESP];
+       /*
+        *      .First byte = 0
+        *      .Second byte = property's MSB
+        *      .Third byte = property's LSB
+        */
+       const u8 args[SI4713_GET_PROP_NARGS] = {
+               0x00,
+               msb(prop),
+               lsb(prop),
+       };
+
+       err = si4713_send_command(sdev, SI4713_CMD_GET_PROPERTY,
+                                 args, ARRAY_SIZE(args), val,
+                                 ARRAY_SIZE(val), DEFAULT_TIMEOUT);
+
+       if (err < 0)
+               return err;
+
+       *pv = compose_u16(val[2], val[3]);
+
+       v4l2_dbg(1, debug, &sdev->sd,
+                       "%s: property=0x%02x value=0x%02x status=0x%02x\n",
+                       __func__, prop, *pv, val[0]);
+
+       return err;
+}
+
+/*
+ * si4713_write_property - modifies a si4713 property
+ * @sdev: si4713_device structure for the device we are communicating
+ * @prop: property identification number
+ * @val: new value for that property
+ */
+static int si4713_write_property(struct si4713_device *sdev, u16 prop, u16 val)
+{
+       int rval;
+       u8 resp[SI4713_SET_PROP_NRESP];
+       /*
+        *      .First byte = 0
+        *      .Second byte = property's MSB
+        *      .Third byte = property's LSB
+        *      .Fourth byte = value's MSB
+        *      .Fifth byte = value's LSB
+        */
+       const u8 args[SI4713_SET_PROP_NARGS] = {
+               0x00,
+               msb(prop),
+               lsb(prop),
+               msb(val),
+               lsb(val),
+       };
+
+       rval = si4713_send_command(sdev, SI4713_CMD_SET_PROPERTY,
+                                       args, ARRAY_SIZE(args),
+                                       resp, ARRAY_SIZE(resp),
+                                       DEFAULT_TIMEOUT);
+
+       if (rval < 0)
+               return rval;
+
+       v4l2_dbg(1, debug, &sdev->sd,
+                       "%s: property=0x%02x value=0x%02x status=0x%02x\n",
+                       __func__, prop, val, resp[0]);
+
+       /*
+        * As there is no command response for SET_PROPERTY,
+        * wait Tcomp time to finish before proceed, in order
+        * to have property properly set.
+        */
+       msleep(TIMEOUT_SET_PROPERTY);
+
+       return rval;
+}
+
+/*
+ * si4713_powerup - Powers the device up
+ * @sdev: si4713_device structure for the device we are communicating
+ */
+static int si4713_powerup(struct si4713_device *sdev)
+{
+       int err;
+       u8 resp[SI4713_PWUP_NRESP];
+       /*
+        *      .First byte = Enabled interrupts and boot function
+        *      .Second byte = Input operation mode
+        */
+       const u8 args[SI4713_PWUP_NARGS] = {
+               SI4713_PWUP_CTSIEN | SI4713_PWUP_GPO2OEN | SI4713_PWUP_FUNC_TX,
+               SI4713_PWUP_OPMOD_ANALOG,
+       };
+
+       if (sdev->power_state)
+               return 0;
+
+       sdev->platform_data->set_power(1);
+       err = si4713_send_command(sdev, SI4713_CMD_POWER_UP,
+                                       args, ARRAY_SIZE(args),
+                                       resp, ARRAY_SIZE(resp),
+                                       TIMEOUT_POWER_UP);
+
+       if (!err) {
+               v4l2_dbg(1, debug, &sdev->sd, "Powerup response: 0x%02x\n",
+                               resp[0]);
+               v4l2_dbg(1, debug, &sdev->sd, "Device in power up mode\n");
+               sdev->power_state = POWER_ON;
+
+               err = si4713_write_property(sdev, SI4713_GPO_IEN,
+                                               SI4713_STC_INT | SI4713_CTS);
+       } else {
+               sdev->platform_data->set_power(0);
+       }
+
+       return err;
+}
+
+/*
+ * si4713_powerdown - Powers the device down
+ * @sdev: si4713_device structure for the device we are communicating
+ */
+static int si4713_powerdown(struct si4713_device *sdev)
+{
+       int err;
+       u8 resp[SI4713_PWDN_NRESP];
+
+       if (!sdev->power_state)
+               return 0;
+
+       err = si4713_send_command(sdev, SI4713_CMD_POWER_DOWN,
+                                       NULL, 0,
+                                       resp, ARRAY_SIZE(resp),
+                                       DEFAULT_TIMEOUT);
+
+       if (!err) {
+               v4l2_dbg(1, debug, &sdev->sd, "Power down response: 0x%02x\n",
+                               resp[0]);
+               v4l2_dbg(1, debug, &sdev->sd, "Device in reset mode\n");
+               sdev->platform_data->set_power(0);
+               sdev->power_state = POWER_OFF;
+       }
+
+       return err;
+}
+
+/*
+ * si4713_checkrev - Checks if we are treating a device with the correct rev.
+ * @sdev: si4713_device structure for the device we are communicating
+ */
+static int si4713_checkrev(struct si4713_device *sdev)
+{
+       struct i2c_client *client = v4l2_get_subdevdata(&sdev->sd);
+       int rval;
+       u8 resp[SI4713_GETREV_NRESP];
+
+       mutex_lock(&sdev->mutex);
+
+       rval = si4713_send_command(sdev, SI4713_CMD_GET_REV,
+                                       NULL, 0,
+                                       resp, ARRAY_SIZE(resp),
+                                       DEFAULT_TIMEOUT);
+
+       if (rval < 0)
+               goto unlock;
+
+       if (resp[1] == SI4713_PRODUCT_NUMBER) {
+               v4l2_info(&sdev->sd, "chip found @ 0x%02x (%s)\n",
+                               client->addr << 1, client->adapter->name);
+       } else {
+               v4l2_err(&sdev->sd, "Invalid product number\n");
+               rval = -EINVAL;
+       }
+
+unlock:
+       mutex_unlock(&sdev->mutex);
+       return rval;
+}
+
+/*
+ * si4713_wait_stc - Waits STC interrupt and clears status bits. Usefull
+ *                  for TX_TUNE_POWER, TX_TUNE_FREQ and TX_TUNE_MEAS
+ * @sdev: si4713_device structure for the device we are communicating
+ * @usecs: timeout to wait for STC interrupt signal
+ */
+static int si4713_wait_stc(struct si4713_device *sdev, const int usecs)
+{
+       int err;
+       u8 resp[SI4713_GET_STATUS_NRESP];
+
+       /* Wait response from STC interrupt */
+       if (!wait_for_completion_timeout(&sdev->work,
+                       usecs_to_jiffies(usecs) + 1))
+               v4l2_warn(&sdev->sd,
+                       "%s: device took too much time to answer (%d usec).\n",
+                               __func__, usecs);
+
+       /* Clear status bits */
+       err = si4713_send_command(sdev, SI4713_CMD_GET_INT_STATUS,
+                                       NULL, 0,
+                                       resp, ARRAY_SIZE(resp),
+                                       DEFAULT_TIMEOUT);
+
+       if (err < 0)
+               goto exit;
+
+       v4l2_dbg(1, debug, &sdev->sd,
+                       "%s: status bits: 0x%02x\n", __func__, resp[0]);
+
+       if (!(resp[0] & SI4713_STC_INT))
+               err = -EIO;
+
+exit:
+       return err;
+}
+
+/*
+ * si4713_tx_tune_freq - Sets the state of the RF carrier and sets the tuning
+ *                     frequency between 76 and 108 MHz in 10 kHz units and
+ *                     steps of 50 kHz.
+ * @sdev: si4713_device structure for the device we are communicating
+ * @frequency: desired frequency (76 - 108 MHz, unit 10 KHz, step 50 kHz)
+ */
+static int si4713_tx_tune_freq(struct si4713_device *sdev, u16 frequency)
+{
+       int err;
+       u8 val[SI4713_TXFREQ_NRESP];
+       /*
+        *      .First byte = 0
+        *      .Second byte = frequency's MSB
+        *      .Third byte = frequency's LSB
+        */
+       const u8 args[SI4713_TXFREQ_NARGS] = {
+               0x00,
+               msb(frequency),
+               lsb(frequency),
+       };
+
+       err = si4713_send_command(sdev, SI4713_CMD_TX_TUNE_FREQ,
+                                 args, ARRAY_SIZE(args), val,
+                                 ARRAY_SIZE(val), DEFAULT_TIMEOUT);
+
+       if (err < 0)
+               return err;
+
+       v4l2_dbg(1, debug, &sdev->sd,
+                       "%s: frequency=0x%02x status=0x%02x\n", __func__,
+                       frequency, val[0]);
+
+       err = si4713_wait_stc(sdev, TIMEOUT_TX_TUNE);
+       if (err < 0)
+               return err;
+
+       return compose_u16(args[1], args[2]);
+}
+
+/*
+ * si4713_tx_tune_power - Sets the RF voltage level between 88 and 115 dBuV in
+ *                     1 dB units. A value of 0x00 indicates off. The command
+ *                     also sets the antenna tuning capacitance. A value of 0
+ *                     indicates autotuning, and a value of 1 - 191 indicates
+ *                     a manual override, which results in a tuning
+ *                     capacitance of 0.25 pF x @antcap.
+ * @sdev: si4713_device structure for the device we are communicating
+ * @power: tuning power (88 - 115 dBuV, unit/step 1 dB)
+ * @antcap: value of antenna tuning capacitor (0 - 191)
+ */
+static int si4713_tx_tune_power(struct si4713_device *sdev, u8 power,
+                               u8 antcap)
+{
+       int err;
+       u8 val[SI4713_TXPWR_NRESP];
+       /*
+        *      .First byte = 0
+        *      .Second byte = 0
+        *      .Third byte = power
+        *      .Fourth byte = antcap
+        */
+       const u8 args[SI4713_TXPWR_NARGS] = {
+               0x00,
+               0x00,
+               power,
+               antcap,
+       };
+
+       if (((power > 0) && (power < SI4713_MIN_POWER)) ||
+               power > SI4713_MAX_POWER || antcap > SI4713_MAX_ANTCAP)
+               return -EDOM;
+
+       err = si4713_send_command(sdev, SI4713_CMD_TX_TUNE_POWER,
+                                 args, ARRAY_SIZE(args), val,
+                                 ARRAY_SIZE(val), DEFAULT_TIMEOUT);
+
+       if (err < 0)
+               return err;
+
+       v4l2_dbg(1, debug, &sdev->sd,
+                       "%s: power=0x%02x antcap=0x%02x status=0x%02x\n",
+                       __func__, power, antcap, val[0]);
+
+       return si4713_wait_stc(sdev, TIMEOUT_TX_TUNE_POWER);
+}
+
+/*
+ * si4713_tx_tune_measure - Enters receive mode and measures the received noise
+ *                     level in units of dBuV on the selected frequency.
+ *                     The Frequency must be between 76 and 108 MHz in 10 kHz
+ *                     units and steps of 50 kHz. The command also sets the
+ *                     antenna tuning capacitance. A value of 0 means
+ *                     autotuning, and a value of 1 to 191 indicates manual
+ *                     override.
+ * @sdev: si4713_device structure for the device we are communicating
+ * @frequency: desired frequency (76 - 108 MHz, unit 10 KHz, step 50 kHz)
+ * @antcap: value of antenna tuning capacitor (0 - 191)
+ */
+static int si4713_tx_tune_measure(struct si4713_device *sdev, u16 frequency,
+                                       u8 antcap)
+{
+       int err;
+       u8 val[SI4713_TXMEA_NRESP];
+       /*
+        *      .First byte = 0
+        *      .Second byte = frequency's MSB
+        *      .Third byte = frequency's LSB
+        *      .Fourth byte = antcap
+        */
+       const u8 args[SI4713_TXMEA_NARGS] = {
+               0x00,
+               msb(frequency),
+               lsb(frequency),
+               antcap,
+       };
+
+       sdev->tune_rnl = DEFAULT_TUNE_RNL;
+
+       if (antcap > SI4713_MAX_ANTCAP)
+               return -EDOM;
+
+       err = si4713_send_command(sdev, SI4713_CMD_TX_TUNE_MEASURE,
+                                 args, ARRAY_SIZE(args), val,
+                                 ARRAY_SIZE(val), DEFAULT_TIMEOUT);
+
+       if (err < 0)
+               return err;
+
+       v4l2_dbg(1, debug, &sdev->sd,
+                       "%s: frequency=0x%02x antcap=0x%02x status=0x%02x\n",
+                       __func__, frequency, antcap, val[0]);
+
+       return si4713_wait_stc(sdev, TIMEOUT_TX_TUNE);
+}
+
+/*
+ * si4713_tx_tune_status- Returns the status of the tx_tune_freq, tx_tune_mea or
+ *                     tx_tune_power commands. This command return the current
+ *                     frequency, output voltage in dBuV, the antenna tunning
+ *                     capacitance value and the received noise level. The
+ *                     command also clears the stcint interrupt bit when the
+ *                     first bit of its arguments is high.
+ * @sdev: si4713_device structure for the device we are communicating
+ * @intack: 0x01 to clear the seek/tune complete interrupt status indicator.
+ * @frequency: returned frequency
+ * @power: returned power
+ * @antcap: returned antenna capacitance
+ * @noise: returned noise level
+ */
+static int si4713_tx_tune_status(struct si4713_device *sdev, u8 intack,
+                                       u16 *frequency, u8 *power,
+                                       u8 *antcap, u8 *noise)
+{
+       int err;
+       u8 val[SI4713_TXSTATUS_NRESP];
+       /*
+        *      .First byte = intack bit
+        */
+       const u8 args[SI4713_TXSTATUS_NARGS] = {
+               intack & SI4713_INTACK_MASK,
+       };
+
+       err = si4713_send_command(sdev, SI4713_CMD_TX_TUNE_STATUS,
+                                 args, ARRAY_SIZE(args), val,
+                                 ARRAY_SIZE(val), DEFAULT_TIMEOUT);
+
+       if (!err) {
+               v4l2_dbg(1, debug, &sdev->sd,
+                       "%s: status=0x%02x\n", __func__, val[0]);
+               *frequency = compose_u16(val[2], val[3]);
+               sdev->frequency = *frequency;
+               *power = val[5];
+               *antcap = val[6];
+               *noise = val[7];
+               v4l2_dbg(1, debug, &sdev->sd, "%s: response: %d x 10 kHz "
+                               "(power %d, antcap %d, rnl %d)\n", __func__,
+                               *frequency, *power, *antcap, *noise);
+       }
+
+       return err;
+}
+
+/*
+ * si4713_tx_rds_buff - Loads the RDS group buffer FIFO or circular buffer.
+ * @sdev: si4713_device structure for the device we are communicating
+ * @mode: the buffer operation mode.
+ * @rdsb: RDS Block B
+ * @rdsc: RDS Block C
+ * @rdsd: RDS Block D
+ * @cbleft: returns the number of available circular buffer blocks minus the
+ *          number of used circular buffer blocks.
+ */
+static int si4713_tx_rds_buff(struct si4713_device *sdev, u8 mode, u16 rdsb,
+                               u16 rdsc, u16 rdsd, s8 *cbleft)
+{
+       int err;
+       u8 val[SI4713_RDSBUFF_NRESP];
+
+       const u8 args[SI4713_RDSBUFF_NARGS] = {
+               mode & SI4713_RDSBUFF_MODE_MASK,
+               msb(rdsb),
+               lsb(rdsb),
+               msb(rdsc),
+               lsb(rdsc),
+               msb(rdsd),
+               lsb(rdsd),
+       };
+
+       err = si4713_send_command(sdev, SI4713_CMD_TX_RDS_BUFF,
+                                 args, ARRAY_SIZE(args), val,
+                                 ARRAY_SIZE(val), DEFAULT_TIMEOUT);
+
+       if (!err) {
+               v4l2_dbg(1, debug, &sdev->sd,
+                       "%s: status=0x%02x\n", __func__, val[0]);
+               *cbleft = (s8)val[2] - val[3];
+               v4l2_dbg(1, debug, &sdev->sd, "%s: response: interrupts"
+                               " 0x%02x cb avail: %d cb used %d fifo avail"
+                               " %d fifo used %d\n", __func__, val[1],
+                               val[2], val[3], val[4], val[5]);
+       }
+
+       return err;
+}
+
+/*
+ * si4713_tx_rds_ps - Loads the program service buffer.
+ * @sdev: si4713_device structure for the device we are communicating
+ * @psid: program service id to be loaded.
+ * @pschar: assumed 4 size char array to be loaded into the program service
+ */
+static int si4713_tx_rds_ps(struct si4713_device *sdev, u8 psid,
+                               unsigned char *pschar)
+{
+       int err;
+       u8 val[SI4713_RDSPS_NRESP];
+
+       const u8 args[SI4713_RDSPS_NARGS] = {
+               psid & SI4713_RDSPS_PSID_MASK,
+               pschar[0],
+               pschar[1],
+               pschar[2],
+               pschar[3],
+       };
+
+       err = si4713_send_command(sdev, SI4713_CMD_TX_RDS_PS,
+                                 args, ARRAY_SIZE(args), val,
+                                 ARRAY_SIZE(val), DEFAULT_TIMEOUT);
+
+       if (err < 0)
+               return err;
+
+       v4l2_dbg(1, debug, &sdev->sd, "%s: status=0x%02x\n", __func__, val[0]);
+
+       return err;
+}
+
+static int si4713_set_power_state(struct si4713_device *sdev, u8 value)
+{
+       int rval;
+
+       mutex_lock(&sdev->mutex);
+
+       if (value)
+               rval = si4713_powerup(sdev);
+       else
+               rval = si4713_powerdown(sdev);
+
+       mutex_unlock(&sdev->mutex);
+       return rval;
+}
+
+static int si4713_set_mute(struct si4713_device *sdev, u16 mute)
+{
+       int rval = 0;
+
+       mute = set_mute(mute);
+
+       mutex_lock(&sdev->mutex);
+
+       if (sdev->power_state)
+               rval = si4713_write_property(sdev,
+                               SI4713_TX_LINE_INPUT_MUTE, mute);
+
+       if (rval >= 0)
+               sdev->mute = get_mute(mute);
+
+       mutex_unlock(&sdev->mutex);
+
+       return rval;
+}
+
+static int si4713_set_rds_ps_name(struct si4713_device *sdev, char *ps_name)
+{
+       int rval = 0, i;
+       u8 len = 0;
+
+       /* We want to clear the whole thing */
+       if (!strlen(ps_name))
+               memset(ps_name, 0, MAX_RDS_PS_NAME + 1);
+
+       mutex_lock(&sdev->mutex);
+
+       if (sdev->power_state) {
+               /* Write the new ps name and clear the padding */
+               for (i = 0; i < MAX_RDS_PS_NAME; i += (RDS_BLOCK / 2)) {
+                       rval = si4713_tx_rds_ps(sdev, (i / (RDS_BLOCK / 2)),
+                                               ps_name + i);
+                       if (rval < 0)
+                               goto unlock;
+               }
+
+               /* Setup the size to be sent */
+               if (strlen(ps_name))
+                       len = strlen(ps_name) - 1;
+               else
+                       len = 1;
+
+               rval = si4713_write_property(sdev,
+                               SI4713_TX_RDS_PS_MESSAGE_COUNT,
+                               rds_ps_nblocks(len));
+               if (rval < 0)
+                       goto unlock;
+
+               rval = si4713_write_property(sdev,
+                               SI4713_TX_RDS_PS_REPEAT_COUNT,
+                               DEFAULT_RDS_PS_REPEAT_COUNT * 2);
+               if (rval < 0)
+                       goto unlock;
+       }
+
+       strncpy(sdev->rds_info.ps_name, ps_name, MAX_RDS_PS_NAME);
+
+unlock:
+       mutex_unlock(&sdev->mutex);
+       return rval;
+}
+
+static int si4713_set_rds_radio_text(struct si4713_device *sdev, char *rt)
+{
+       int rval = 0, i;
+       u16 t_index = 0;
+       u8 b_index = 0, cr_inserted = 0;
+       s8 left;
+
+       mutex_lock(&sdev->mutex);
+
+       if (!sdev->power_state)
+               goto copy;
+
+       rval = si4713_tx_rds_buff(sdev, RDS_BLOCK_CLEAR, 0, 0, 0, &left);
+       if (rval < 0)
+               goto unlock;
+
+       if (!strlen(rt))
+               goto copy;
+
+       do {
+               /* RDS spec says that if the last block isn't used,
+                * then apply a carriage return
+                */
+               if (t_index < (RDS_RADIOTEXT_INDEX_MAX *
+                       RDS_RADIOTEXT_BLK_SIZE)) {
+                       for (i = 0; i < RDS_RADIOTEXT_BLK_SIZE; i++) {
+                               if (!rt[t_index + i] || rt[t_index + i] ==
+                                       RDS_CARRIAGE_RETURN) {
+                                       rt[t_index + i] = RDS_CARRIAGE_RETURN;
+                                       cr_inserted = 1;
+                                       break;
+                               }
+                       }
+               }
+
+               rval = si4713_tx_rds_buff(sdev, RDS_BLOCK_LOAD,
+                               compose_u16(RDS_RADIOTEXT_2A, b_index++),
+                               compose_u16(rt[t_index], rt[t_index + 1]),
+                               compose_u16(rt[t_index + 2], rt[t_index + 3]),
+                               &left);
+               if (rval < 0)
+                       goto unlock;
+
+               t_index += RDS_RADIOTEXT_BLK_SIZE;
+
+               if (cr_inserted)
+                       break;
+       } while (left > 0);
+
+copy:
+       strncpy(sdev->rds_info.radio_text, rt, MAX_RDS_RADIO_TEXT);
+
+unlock:
+       mutex_unlock(&sdev->mutex);
+       return rval;
+}
+
+static int si4713_choose_econtrol_action(struct si4713_device *sdev, u32 id,
+               u32 **shadow, s32 *bit, s32 *mask, u16 *property, int *mul,
+               unsigned long **table, int *size)
+{
+       s32 rval = 0;
+
+       switch (id) {
+       /* FM_TX class controls */
+       case V4L2_CID_RDS_TX_PI:
+               *property = SI4713_TX_RDS_PI;
+               *mul = 1;
+               *shadow = &sdev->rds_info.pi;
+               break;
+       case V4L2_CID_AUDIO_COMPRESSION_THRESHOLD:
+               *property = SI4713_TX_ACOMP_THRESHOLD;
+               *mul = 1;
+               *shadow = &sdev->acomp_info.threshold;
+               break;
+       case V4L2_CID_AUDIO_COMPRESSION_GAIN:
+               *property = SI4713_TX_ACOMP_GAIN;
+               *mul = 1;
+               *shadow = &sdev->acomp_info.gain;
+               break;
+       case V4L2_CID_PILOT_TONE_FREQUENCY:
+               *property = SI4713_TX_PILOT_FREQUENCY;
+               *mul = 1;
+               *shadow = &sdev->pilot_info.frequency;
+               break;
+       case V4L2_CID_AUDIO_COMPRESSION_ATTACK_TIME:
+               *property = SI4713_TX_ACOMP_ATTACK_TIME;
+               *mul = ATTACK_TIME_UNIT;
+               *shadow = &sdev->acomp_info.attack_time;
+               break;
+       case V4L2_CID_PILOT_TONE_DEVIATION:
+               *property = SI4713_TX_PILOT_DEVIATION;
+               *mul = 10;
+               *shadow = &sdev->pilot_info.deviation;
+               break;
+       case V4L2_CID_AUDIO_LIMITER_DEVIATION:
+               *property = SI4713_TX_AUDIO_DEVIATION;
+               *mul = 10;
+               *shadow = &sdev->limiter_info.deviation;
+               break;
+       case V4L2_CID_RDS_TX_DEVIATION:
+               *property = SI4713_TX_RDS_DEVIATION;
+               *mul = 1;
+               *shadow = &sdev->rds_info.deviation;
+               break;
+
+       case V4L2_CID_RDS_TX_PTY:
+               *property = SI4713_TX_RDS_PS_MISC;
+               *bit = 5;
+               *mask = 0x1F << 5;
+               *shadow = &sdev->rds_info.pty;
+               break;
+       case V4L2_CID_AUDIO_LIMITER_ENABLED:
+               *property = SI4713_TX_ACOMP_ENABLE;
+               *bit = 1;
+               *mask = 1 << 1;
+               *shadow = &sdev->limiter_info.enabled;
+               break;
+       case V4L2_CID_AUDIO_COMPRESSION_ENABLED:
+               *property = SI4713_TX_ACOMP_ENABLE;
+               *bit = 0;
+               *mask = 1 << 0;
+               *shadow = &sdev->acomp_info.enabled;
+               break;
+       case V4L2_CID_PILOT_TONE_ENABLED:
+               *property = SI4713_TX_COMPONENT_ENABLE;
+               *bit = 0;
+               *mask = 1 << 0;
+               *shadow = &sdev->pilot_info.enabled;
+               break;
+
+       case V4L2_CID_AUDIO_LIMITER_RELEASE_TIME:
+               *property = SI4713_TX_LIMITER_RELEASE_TIME;
+               *table = limiter_times;
+               *size = ARRAY_SIZE(limiter_times);
+               *shadow = &sdev->limiter_info.release_time;
+               break;
+       case V4L2_CID_AUDIO_COMPRESSION_RELEASE_TIME:
+               *property = SI4713_TX_ACOMP_RELEASE_TIME;
+               *table = acomp_rtimes;
+               *size = ARRAY_SIZE(acomp_rtimes);
+               *shadow = &sdev->acomp_info.release_time;
+               break;
+       case V4L2_CID_TUNE_PREEMPHASIS:
+               *property = SI4713_TX_PREEMPHASIS;
+               *table = preemphasis_values;
+               *size = ARRAY_SIZE(preemphasis_values);
+               *shadow = &sdev->preemphasis;
+               break;
+
+       default:
+               rval = -EINVAL;
+       };
+
+       return rval;
+}
+
+static int si4713_queryctrl(struct v4l2_subdev *sd, struct v4l2_queryctrl *qc);
+
+/* write string property */
+static int si4713_write_econtrol_string(struct si4713_device *sdev,
+                               struct v4l2_ext_control *control)
+{
+       struct v4l2_queryctrl vqc;
+       int len;
+       s32 rval = 0;
+
+       vqc.id = control->id;
+       rval = si4713_queryctrl(&sdev->sd, &vqc);
+       if (rval < 0)
+               goto exit;
+
+       switch (control->id) {
+       case V4L2_CID_RDS_TX_PS_NAME: {
+               char ps_name[MAX_RDS_PS_NAME + 1];
+
+               len = control->size - 1;
+               if (len > MAX_RDS_PS_NAME) {
+                       rval = -ERANGE;
+                       goto exit;
+               }
+               rval = copy_from_user(ps_name, control->string, len);
+               if (rval < 0)
+                       goto exit;
+               ps_name[len] = '\0';
+
+               if (strlen(ps_name) % vqc.step) {
+                       rval = -ERANGE;
+                       goto exit;
+               }
+
+               rval = si4713_set_rds_ps_name(sdev, ps_name);
+       }
+               break;
+
+       case V4L2_CID_RDS_TX_RADIO_TEXT: {
+               char radio_text[MAX_RDS_RADIO_TEXT + 1];
+
+               len = control->size - 1;
+               if (len > MAX_RDS_RADIO_TEXT) {
+                       rval = -ERANGE;
+                       goto exit;
+               }
+               rval = copy_from_user(radio_text, control->string, len);
+               if (rval < 0)
+                       goto exit;
+               radio_text[len] = '\0';
+
+               if (strlen(radio_text) % vqc.step) {
+                       rval = -ERANGE;
+                       goto exit;
+               }
+
+               rval = si4713_set_rds_radio_text(sdev, radio_text);
+       }
+               break;
+
+       default:
+               rval = -EINVAL;
+               break;
+       };
+
+exit:
+       return rval;
+}
+
+static int validate_range(struct v4l2_subdev *sd,
+                                       struct v4l2_ext_control *control)
+{
+       struct v4l2_queryctrl vqc;
+       int rval;
+
+       vqc.id = control->id;
+       rval = si4713_queryctrl(sd, &vqc);
+       if (rval < 0)
+               goto exit;
+
+       if (control->value < vqc.minimum || control->value > vqc.maximum)
+               rval = -ERANGE;
+
+exit:
+       return rval;
+}
+
+/* properties which use tx_tune_power*/
+static int si4713_write_econtrol_tune(struct si4713_device *sdev,
+                               struct v4l2_ext_control *control)
+{
+       s32 rval = 0;
+       u8 power, antcap;
+
+       rval = validate_range(&sdev->sd, control);
+       if (rval < 0)
+               goto exit;
+
+       mutex_lock(&sdev->mutex);
+
+       switch (control->id) {
+       case V4L2_CID_TUNE_POWER_LEVEL:
+               power = control->value;
+               antcap = sdev->antenna_capacitor;
+               break;
+       case V4L2_CID_TUNE_ANTENNA_CAPACITOR:
+               power = sdev->power_level;
+               antcap = control->value;
+               break;
+       default:
+               rval = -EINVAL;
+               goto unlock;
+       };
+
+       if (sdev->power_state)
+               rval = si4713_tx_tune_power(sdev, power, antcap);
+
+       if (rval == 0) {
+               sdev->power_level = power;
+               sdev->antenna_capacitor = antcap;
+       }
+
+unlock:
+       mutex_unlock(&sdev->mutex);
+exit:
+       return rval;
+}
+
+static int si4713_write_econtrol_integers(struct si4713_device *sdev,
+                                       struct v4l2_ext_control *control)
+{
+       s32 rval;
+       u32 *shadow = NULL, val = 0;
+       s32 bit = 0, mask = 0;
+       u16 property = 0;
+       int mul = 0;
+       unsigned long *table = NULL;
+       int size = 0;
+
+       rval = validate_range(&sdev->sd, control);
+       if (rval < 0)
+               goto exit;
+
+       rval = si4713_choose_econtrol_action(sdev, control->id, &shadow, &bit,
+                       &mask, &property, &mul, &table, &size);
+       if (rval < 0)
+               goto exit;
+
+       val = control->value;
+       if (mul) {
+               val = control->value / mul;
+       } else if (table) {
+               rval = usecs_to_dev(control->value, table, size);
+               if (rval < 0)
+                       goto exit;
+               val = rval;
+               rval = 0;
+       }
+
+       mutex_lock(&sdev->mutex);
+
+       if (sdev->power_state) {
+               if (mask) {
+                       rval = si4713_read_property(sdev, property, &val);
+                       if (rval < 0)
+                               goto unlock;
+                       val = set_bits(val, control->value, bit, mask);
+               }
+
+               rval = si4713_write_property(sdev, property, val);
+               if (rval < 0)
+                       goto unlock;
+               if (mask)
+                       val = control->value;
+       }
+
+       if (mul) {
+               *shadow = val * mul;
+       } else if (table) {
+               rval = dev_to_usecs(val, table, size);
+               if (rval < 0)
+                       goto unlock;
+               *shadow = rval;
+               rval = 0;
+       } else {
+               *shadow = val;
+       }
+
+unlock:
+       mutex_unlock(&sdev->mutex);
+exit:
+       return rval;
+}
+
+static int si4713_s_frequency(struct v4l2_subdev *sd, struct v4l2_frequency *f);
+static int si4713_s_modulator(struct v4l2_subdev *sd, struct v4l2_modulator *);
+/*
+ * si4713_setup - Sets the device up with current configuration.
+ * @sdev: si4713_device structure for the device we are communicating
+ */
+static int si4713_setup(struct si4713_device *sdev)
+{
+       struct v4l2_ext_control ctrl;
+       struct v4l2_frequency f;
+       struct v4l2_modulator vm;
+       struct si4713_device *tmp;
+       int rval = 0;
+
+       tmp = kmalloc(sizeof(*tmp), GFP_KERNEL);
+       if (!tmp)
+               return -ENOMEM;
+
+       /* Get a local copy to avoid race */
+       mutex_lock(&sdev->mutex);
+       memcpy(tmp, sdev, sizeof(*sdev));
+       mutex_unlock(&sdev->mutex);
+
+       ctrl.id = V4L2_CID_RDS_TX_PI;
+       ctrl.value = tmp->rds_info.pi;
+       rval |= si4713_write_econtrol_integers(sdev, &ctrl);
+
+       ctrl.id = V4L2_CID_AUDIO_COMPRESSION_THRESHOLD;
+       ctrl.value = tmp->acomp_info.threshold;
+       rval |= si4713_write_econtrol_integers(sdev, &ctrl);
+
+       ctrl.id = V4L2_CID_AUDIO_COMPRESSION_GAIN;
+       ctrl.value = tmp->acomp_info.gain;
+       rval |= si4713_write_econtrol_integers(sdev, &ctrl);
+
+       ctrl.id = V4L2_CID_PILOT_TONE_FREQUENCY;
+       ctrl.value = tmp->pilot_info.frequency;
+       rval |= si4713_write_econtrol_integers(sdev, &ctrl);
+
+       ctrl.id = V4L2_CID_AUDIO_COMPRESSION_ATTACK_TIME;
+       ctrl.value = tmp->acomp_info.attack_time;
+       rval |= si4713_write_econtrol_integers(sdev, &ctrl);
+
+       ctrl.id = V4L2_CID_PILOT_TONE_DEVIATION;
+       ctrl.value = tmp->pilot_info.deviation;
+       rval |= si4713_write_econtrol_integers(sdev, &ctrl);
+
+       ctrl.id = V4L2_CID_AUDIO_LIMITER_DEVIATION;
+       ctrl.value = tmp->limiter_info.deviation;
+       rval |= si4713_write_econtrol_integers(sdev, &ctrl);
+
+       ctrl.id = V4L2_CID_RDS_TX_DEVIATION;
+       ctrl.value = tmp->rds_info.deviation;
+       rval |= si4713_write_econtrol_integers(sdev, &ctrl);
+
+       ctrl.id = V4L2_CID_RDS_TX_PTY;
+       ctrl.value = tmp->rds_info.pty;
+       rval |= si4713_write_econtrol_integers(sdev, &ctrl);
+
+       ctrl.id = V4L2_CID_AUDIO_LIMITER_ENABLED;
+       ctrl.value = tmp->limiter_info.enabled;
+       rval |= si4713_write_econtrol_integers(sdev, &ctrl);
+
+       ctrl.id = V4L2_CID_AUDIO_COMPRESSION_ENABLED;
+       ctrl.value = tmp->acomp_info.enabled;
+       rval |= si4713_write_econtrol_integers(sdev, &ctrl);
+
+       ctrl.id = V4L2_CID_PILOT_TONE_ENABLED;
+       ctrl.value = tmp->pilot_info.enabled;
+       rval |= si4713_write_econtrol_integers(sdev, &ctrl);
+
+       ctrl.id = V4L2_CID_AUDIO_LIMITER_RELEASE_TIME;
+       ctrl.value = tmp->limiter_info.release_time;
+       rval |= si4713_write_econtrol_integers(sdev, &ctrl);
+
+       ctrl.id = V4L2_CID_AUDIO_COMPRESSION_RELEASE_TIME;
+       ctrl.value = tmp->acomp_info.release_time;
+       rval |= si4713_write_econtrol_integers(sdev, &ctrl);
+
+       ctrl.id = V4L2_CID_TUNE_PREEMPHASIS;
+       ctrl.value = tmp->preemphasis;
+       rval |= si4713_write_econtrol_integers(sdev, &ctrl);
+
+       ctrl.id = V4L2_CID_RDS_TX_PS_NAME;
+       rval |= si4713_set_rds_ps_name(sdev, tmp->rds_info.ps_name);
+
+       ctrl.id = V4L2_CID_RDS_TX_RADIO_TEXT;
+       rval |= si4713_set_rds_radio_text(sdev, tmp->rds_info.radio_text);
+
+       /* Device procedure needs to set frequency first */
+       f.frequency = tmp->frequency ? tmp->frequency : DEFAULT_FREQUENCY;
+       f.frequency = si4713_to_v4l2(f.frequency);
+       rval |= si4713_s_frequency(&sdev->sd, &f);
+
+       ctrl.id = V4L2_CID_TUNE_POWER_LEVEL;
+       ctrl.value = tmp->power_level;
+       rval |= si4713_write_econtrol_tune(sdev, &ctrl);
+
+       ctrl.id = V4L2_CID_TUNE_ANTENNA_CAPACITOR;
+       ctrl.value = tmp->antenna_capacitor;
+       rval |= si4713_write_econtrol_tune(sdev, &ctrl);
+
+       vm.index = 0;
+       if (tmp->stereo)
+               vm.txsubchans = V4L2_TUNER_SUB_STEREO;
+       else
+               vm.txsubchans = V4L2_TUNER_SUB_MONO;
+       if (tmp->rds_info.enabled)
+               vm.txsubchans |= V4L2_TUNER_SUB_RDS;
+       si4713_s_modulator(&sdev->sd, &vm);
+
+       kfree(tmp);
+
+       return rval;
+}
+
+/*
+ * si4713_initialize - Sets the device up with default configuration.
+ * @sdev: si4713_device structure for the device we are communicating
+ */
+static int si4713_initialize(struct si4713_device *sdev)
+{
+       int rval;
+
+       rval = si4713_set_power_state(sdev, POWER_ON);
+       if (rval < 0)
+               goto exit;
+
+       rval = si4713_checkrev(sdev);
+       if (rval < 0)
+               goto exit;
+
+       rval = si4713_set_power_state(sdev, POWER_OFF);
+       if (rval < 0)
+               goto exit;
+
+       mutex_lock(&sdev->mutex);
+
+       sdev->rds_info.pi = DEFAULT_RDS_PI;
+       sdev->rds_info.pty = DEFAULT_RDS_PTY;
+       sdev->rds_info.deviation = DEFAULT_RDS_DEVIATION;
+       strlcpy(sdev->rds_info.ps_name, DEFAULT_RDS_PS_NAME, MAX_RDS_PS_NAME);
+       strlcpy(sdev->rds_info.radio_text, DEFAULT_RDS_RADIO_TEXT,
+                                                       MAX_RDS_RADIO_TEXT);
+       sdev->rds_info.enabled = 1;
+
+       sdev->limiter_info.release_time = DEFAULT_LIMITER_RTIME;
+       sdev->limiter_info.deviation = DEFAULT_LIMITER_DEV;
+       sdev->limiter_info.enabled = 1;
+
+       sdev->pilot_info.deviation = DEFAULT_PILOT_DEVIATION;
+       sdev->pilot_info.frequency = DEFAULT_PILOT_FREQUENCY;
+       sdev->pilot_info.enabled = 1;
+
+       sdev->acomp_info.release_time = DEFAULT_ACOMP_RTIME;
+       sdev->acomp_info.attack_time = DEFAULT_ACOMP_ATIME;
+       sdev->acomp_info.threshold = DEFAULT_ACOMP_THRESHOLD;
+       sdev->acomp_info.gain = DEFAULT_ACOMP_GAIN;
+       sdev->acomp_info.enabled = 1;
+
+       sdev->frequency = DEFAULT_FREQUENCY;
+       sdev->preemphasis = DEFAULT_PREEMPHASIS;
+       sdev->mute = DEFAULT_MUTE;
+       sdev->power_level = DEFAULT_POWER_LEVEL;
+       sdev->antenna_capacitor = 0;
+       sdev->stereo = 1;
+       sdev->tune_rnl = DEFAULT_TUNE_RNL;
+
+       mutex_unlock(&sdev->mutex);
+
+exit:
+       return rval;
+}
+
+/* read string property */
+static int si4713_read_econtrol_string(struct si4713_device *sdev,
+                               struct v4l2_ext_control *control)
+{
+       s32 rval = 0;
+
+       switch (control->id) {
+       case V4L2_CID_RDS_TX_PS_NAME:
+               if (strlen(sdev->rds_info.ps_name) + 1 > control->size) {
+                       control->size = MAX_RDS_PS_NAME + 1;
+                       rval = -ENOSPC;
+                       goto exit;
+               }
+               rval = copy_to_user(control->string, sdev->rds_info.ps_name,
+                                       strlen(sdev->rds_info.ps_name) + 1);
+               break;
+
+       case V4L2_CID_RDS_TX_RADIO_TEXT:
+               if (strlen(sdev->rds_info.radio_text) + 1 > control->size) {
+                       control->size = MAX_RDS_RADIO_TEXT + 1;
+                       rval = -ENOSPC;
+                       goto exit;
+               }
+               rval = copy_to_user(control->string, sdev->rds_info.radio_text,
+                                       strlen(sdev->rds_info.radio_text) + 1);
+               break;
+
+       default:
+               rval = -EINVAL;
+               break;
+       };
+
+exit:
+       return rval;
+}
+
+/*
+ * si4713_update_tune_status - update properties from tx_tune_status
+ * command. Must be called with sdev->mutex held.
+ * @sdev: si4713_device structure for the device we are communicating
+ */
+static int si4713_update_tune_status(struct si4713_device *sdev)
+{
+       int rval;
+       u16 f = 0;
+       u8 p = 0, a = 0, n = 0;
+
+       rval = si4713_tx_tune_status(sdev, 0x00, &f, &p, &a, &n);
+
+       if (rval < 0)
+               goto exit;
+
+       sdev->power_level = p;
+       sdev->antenna_capacitor = a;
+       sdev->tune_rnl = n;
+
+exit:
+       return rval;
+}
+
+/* properties which use tx_tune_status */
+static int si4713_read_econtrol_tune(struct si4713_device *sdev,
+                               struct v4l2_ext_control *control)
+{
+       s32 rval = 0;
+
+       mutex_lock(&sdev->mutex);
+
+       if (sdev->power_state) {
+               rval = si4713_update_tune_status(sdev);
+               if (rval < 0)
+                       goto unlock;
+       }
+
+       switch (control->id) {
+       case V4L2_CID_TUNE_POWER_LEVEL:
+               control->value = sdev->power_level;
+               break;
+       case V4L2_CID_TUNE_ANTENNA_CAPACITOR:
+               control->value = sdev->antenna_capacitor;
+               break;
+       default:
+               rval = -EINVAL;
+       };
+
+unlock:
+       mutex_unlock(&sdev->mutex);
+       return rval;
+}
+
+static int si4713_read_econtrol_integers(struct si4713_device *sdev,
+                               struct v4l2_ext_control *control)
+{
+       s32 rval;
+       u32 *shadow = NULL, val = 0;
+       s32 bit = 0, mask = 0;
+       u16 property = 0;
+       int mul = 0;
+       unsigned long *table = NULL;
+       int size = 0;
+
+       rval = si4713_choose_econtrol_action(sdev, control->id, &shadow, &bit,
+                       &mask, &property, &mul, &table, &size);
+       if (rval < 0)
+               goto exit;
+
+       mutex_lock(&sdev->mutex);
+
+       if (sdev->power_state) {
+               rval = si4713_read_property(sdev, property, &val);
+               if (rval < 0)
+                       goto unlock;
+
+               /* Keep negative values for threshold */
+               if (control->id == V4L2_CID_AUDIO_COMPRESSION_THRESHOLD)
+                       *shadow = (s16)val;
+               else if (mask)
+                       *shadow = get_status_bit(val, bit, mask);
+               else if (mul)
+                       *shadow = val * mul;
+               else
+                       *shadow = dev_to_usecs(val, table, size);
+       }
+
+       control->value = *shadow;
+
+unlock:
+       mutex_unlock(&sdev->mutex);
+exit:
+       return rval;
+}
+
+/*
+ * Video4Linux Subdev Interface
+ */
+/* si4713_s_ext_ctrls - set extended controls value */
+static int si4713_s_ext_ctrls(struct v4l2_subdev *sd,
+                               struct v4l2_ext_controls *ctrls)
+{
+       struct si4713_device *sdev = to_si4713_device(sd);
+       int i;
+
+       if (ctrls->ctrl_class != V4L2_CTRL_CLASS_FM_TX)
+               return -EINVAL;
+
+       for (i = 0; i < ctrls->count; i++) {
+               int err;
+
+               switch ((ctrls->controls + i)->id) {
+               case V4L2_CID_RDS_TX_PS_NAME:
+               case V4L2_CID_RDS_TX_RADIO_TEXT:
+                       err = si4713_write_econtrol_string(sdev,
+                                                       ctrls->controls + i);
+                       break;
+               case V4L2_CID_TUNE_ANTENNA_CAPACITOR:
+               case V4L2_CID_TUNE_POWER_LEVEL:
+                       err = si4713_write_econtrol_tune(sdev,
+                                                       ctrls->controls + i);
+                       break;
+               default:
+                       err = si4713_write_econtrol_integers(sdev,
+                                                       ctrls->controls + i);
+               }
+
+               if (err < 0) {
+                       ctrls->error_idx = i;
+                       return err;
+               }
+       }
+
+       return 0;
+}
+
+/* si4713_g_ext_ctrls - get extended controls value */
+static int si4713_g_ext_ctrls(struct v4l2_subdev *sd,
+                               struct v4l2_ext_controls *ctrls)
+{
+       struct si4713_device *sdev = to_si4713_device(sd);
+       int i;
+
+       if (ctrls->ctrl_class != V4L2_CTRL_CLASS_FM_TX)
+               return -EINVAL;
+
+       for (i = 0; i < ctrls->count; i++) {
+               int err;
+
+               switch ((ctrls->controls + i)->id) {
+               case V4L2_CID_RDS_TX_PS_NAME:
+               case V4L2_CID_RDS_TX_RADIO_TEXT:
+                       err = si4713_read_econtrol_string(sdev,
+                                                       ctrls->controls + i);
+                       break;
+               case V4L2_CID_TUNE_ANTENNA_CAPACITOR:
+               case V4L2_CID_TUNE_POWER_LEVEL:
+                       err = si4713_read_econtrol_tune(sdev,
+                                                       ctrls->controls + i);
+                       break;
+               default:
+                       err = si4713_read_econtrol_integers(sdev,
+                                                       ctrls->controls + i);
+               }
+
+               if (err < 0) {
+                       ctrls->error_idx = i;
+                       return err;
+               }
+       }
+
+       return 0;
+}
+
+/* si4713_queryctrl - enumerate control items */
+static int si4713_queryctrl(struct v4l2_subdev *sd, struct v4l2_queryctrl *qc)
+{
+       int rval = 0;
+
+       switch (qc->id) {
+       /* User class controls */
+       case V4L2_CID_AUDIO_MUTE:
+               rval = v4l2_ctrl_query_fill(qc, 0, 1, 1, DEFAULT_MUTE);
+               break;
+       /* FM_TX class controls */
+       case V4L2_CID_RDS_TX_PI:
+               rval = v4l2_ctrl_query_fill(qc, 0, 0xFFFF, 1, DEFAULT_RDS_PI);
+               break;
+       case V4L2_CID_RDS_TX_PTY:
+               rval = v4l2_ctrl_query_fill(qc, 0, 31, 1, DEFAULT_RDS_PTY);
+               break;
+       case V4L2_CID_RDS_TX_DEVIATION:
+               rval = v4l2_ctrl_query_fill(qc, 0, MAX_RDS_DEVIATION,
+                                               10, DEFAULT_RDS_DEVIATION);
+               break;
+       case V4L2_CID_RDS_TX_PS_NAME:
+               /*
+                * Report step as 8. From RDS spec, psname
+                * should be 8. But there are receivers which scroll strings
+                * sized as 8xN.
+                */
+               rval = v4l2_ctrl_query_fill(qc, 0, MAX_RDS_PS_NAME, 8, 0);
+               break;
+       case V4L2_CID_RDS_TX_RADIO_TEXT:
+               /*
+                * Report step as 32 (2A block). From RDS spec,
+                * radio text should be 32 for 2A block. But there are receivers
+                * which scroll strings sized as 32xN. Setting default to 32.
+                */
+               rval = v4l2_ctrl_query_fill(qc, 0, MAX_RDS_RADIO_TEXT, 32, 0);
+               break;
+
+       case V4L2_CID_AUDIO_LIMITER_ENABLED:
+               rval = v4l2_ctrl_query_fill(qc, 0, 1, 1, 1);
+               break;
+       case V4L2_CID_AUDIO_LIMITER_RELEASE_TIME:
+               rval = v4l2_ctrl_query_fill(qc, 250, MAX_LIMITER_RELEASE_TIME,
+                                               50, DEFAULT_LIMITER_RTIME);
+               break;
+       case V4L2_CID_AUDIO_LIMITER_DEVIATION:
+               rval = v4l2_ctrl_query_fill(qc, 0, MAX_LIMITER_DEVIATION,
+                                               10, DEFAULT_LIMITER_DEV);
+               break;
+
+       case V4L2_CID_AUDIO_COMPRESSION_ENABLED:
+               rval = v4l2_ctrl_query_fill(qc, 0, 1, 1, 1);
+               break;
+       case V4L2_CID_AUDIO_COMPRESSION_GAIN:
+               rval = v4l2_ctrl_query_fill(qc, 0, MAX_ACOMP_GAIN, 1,
+                                               DEFAULT_ACOMP_GAIN);
+               break;
+       case V4L2_CID_AUDIO_COMPRESSION_THRESHOLD:
+               rval = v4l2_ctrl_query_fill(qc, MIN_ACOMP_THRESHOLD,
+                                               MAX_ACOMP_THRESHOLD, 1,
+                                               DEFAULT_ACOMP_THRESHOLD);
+               break;
+       case V4L2_CID_AUDIO_COMPRESSION_ATTACK_TIME:
+               rval = v4l2_ctrl_query_fill(qc, 0, MAX_ACOMP_ATTACK_TIME,
+                                               500, DEFAULT_ACOMP_ATIME);
+               break;
+       case V4L2_CID_AUDIO_COMPRESSION_RELEASE_TIME:
+               rval = v4l2_ctrl_query_fill(qc, 100000, MAX_ACOMP_RELEASE_TIME,
+                                               100000, DEFAULT_ACOMP_RTIME);
+               break;
+
+       case V4L2_CID_PILOT_TONE_ENABLED:
+               rval = v4l2_ctrl_query_fill(qc, 0, 1, 1, 1);
+               break;
+       case V4L2_CID_PILOT_TONE_DEVIATION:
+               rval = v4l2_ctrl_query_fill(qc, 0, MAX_PILOT_DEVIATION,
+                                               10, DEFAULT_PILOT_DEVIATION);
+               break;
+       case V4L2_CID_PILOT_TONE_FREQUENCY:
+               rval = v4l2_ctrl_query_fill(qc, 0, MAX_PILOT_FREQUENCY,
+                                               1, DEFAULT_PILOT_FREQUENCY);
+               break;
+
+       case V4L2_CID_TUNE_PREEMPHASIS:
+               rval = v4l2_ctrl_query_fill(qc, V4L2_PREEMPHASIS_DISABLED,
+                                               V4L2_PREEMPHASIS_75_uS, 1,
+                                               V4L2_PREEMPHASIS_50_uS);
+               break;
+       case V4L2_CID_TUNE_POWER_LEVEL:
+               rval = v4l2_ctrl_query_fill(qc, 0, 120, 1, DEFAULT_POWER_LEVEL);
+               break;
+       case V4L2_CID_TUNE_ANTENNA_CAPACITOR:
+               rval = v4l2_ctrl_query_fill(qc, 0, 191, 1, 0);
+               break;
+       default:
+               rval = -EINVAL;
+               break;
+       };
+
+       return rval;
+}
+
+/* si4713_g_ctrl - get the value of a control */
+static int si4713_g_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl)
+{
+       struct si4713_device *sdev = to_si4713_device(sd);
+       int rval = 0;
+
+       if (!sdev)
+               return -ENODEV;
+
+       mutex_lock(&sdev->mutex);
+
+       if (sdev->power_state) {
+               rval = si4713_read_property(sdev, SI4713_TX_LINE_INPUT_MUTE,
+                                               &sdev->mute);
+
+               if (rval < 0)
+                       goto unlock;
+       }
+
+       switch (ctrl->id) {
+       case V4L2_CID_AUDIO_MUTE:
+               ctrl->value = get_mute(sdev->mute);
+               break;
+       }
+
+unlock:
+       mutex_unlock(&sdev->mutex);
+       return rval;
+}
+
+/* si4713_s_ctrl - set the value of a control */
+static int si4713_s_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl)
+{
+       struct si4713_device *sdev = to_si4713_device(sd);
+       int rval = 0;
+
+       if (!sdev)
+               return -ENODEV;
+
+       switch (ctrl->id) {
+       case V4L2_CID_AUDIO_MUTE:
+               if (ctrl->value) {
+                       rval = si4713_set_mute(sdev, ctrl->value);
+                       if (rval < 0)
+                               goto exit;
+
+                       rval = si4713_set_power_state(sdev, POWER_DOWN);
+               } else {
+                       rval = si4713_set_power_state(sdev, POWER_UP);
+                       if (rval < 0)
+                               goto exit;
+
+                       rval = si4713_setup(sdev);
+                       if (rval < 0)
+                               goto exit;
+
+                       rval = si4713_set_mute(sdev, ctrl->value);
+               }
+               break;
+       }
+
+exit:
+       return rval;
+}
+
+/* si4713_ioctl - deal with private ioctls (only rnl for now) */
+long si4713_ioctl(struct v4l2_subdev *sd, unsigned int cmd, void *arg)
+{
+       struct si4713_device *sdev = to_si4713_device(sd);
+       struct si4713_rnl *rnl = arg;
+       u16 frequency;
+       int rval = 0;
+
+       if (!arg)
+               return -EINVAL;
+
+       mutex_lock(&sdev->mutex);
+       switch (cmd) {
+       case SI4713_IOC_MEASURE_RNL:
+               frequency = v4l2_to_si4713(rnl->frequency);
+
+               if (sdev->power_state) {
+                       /* Set desired measurement frequency */
+                       rval = si4713_tx_tune_measure(sdev, frequency, 0);
+                       if (rval < 0)
+                               goto unlock;
+                       /* get results from tune status */
+                       rval = si4713_update_tune_status(sdev);
+                       if (rval < 0)
+                               goto unlock;
+               }
+               rnl->rnl = sdev->tune_rnl;
+               break;
+
+       default:
+               /* nothing */
+               rval = -ENOIOCTLCMD;
+       }
+
+unlock:
+       mutex_unlock(&sdev->mutex);
+       return rval;
+}
+
+static const struct v4l2_subdev_core_ops si4713_subdev_core_ops = {
+       .queryctrl      = si4713_queryctrl,
+       .g_ext_ctrls    = si4713_g_ext_ctrls,
+       .s_ext_ctrls    = si4713_s_ext_ctrls,
+       .g_ctrl         = si4713_g_ctrl,
+       .s_ctrl         = si4713_s_ctrl,
+       .ioctl          = si4713_ioctl,
+};
+
+/* si4713_g_modulator - get modulator attributes */
+static int si4713_g_modulator(struct v4l2_subdev *sd, struct v4l2_modulator *vm)
+{
+       struct si4713_device *sdev = to_si4713_device(sd);
+       int rval = 0;
+
+       if (!sdev) {
+               rval = -ENODEV;
+               goto exit;
+       }
+
+       if (vm->index > 0) {
+               rval = -EINVAL;
+               goto exit;
+       }
+
+       strncpy(vm->name, "FM Modulator", 32);
+       vm->capability = V4L2_TUNER_CAP_STEREO | V4L2_TUNER_CAP_LOW |
+                                               V4L2_TUNER_CAP_RDS;
+
+       /* Report current frequency range limits */
+       vm->rangelow = si4713_to_v4l2(FREQ_RANGE_LOW);
+       vm->rangehigh = si4713_to_v4l2(FREQ_RANGE_HIGH);
+
+       mutex_lock(&sdev->mutex);
+
+       if (sdev->power_state) {
+               u32 comp_en = 0;
+
+               rval = si4713_read_property(sdev, SI4713_TX_COMPONENT_ENABLE,
+                                               &comp_en);
+               if (rval < 0)
+                       goto unlock;
+
+               sdev->stereo = get_status_bit(comp_en, 1, 1 << 1);
+               sdev->rds_info.enabled = get_status_bit(comp_en, 2, 1 << 2);
+       }
+
+       /* Report current audio mode: mono or stereo */
+       if (sdev->stereo)
+               vm->txsubchans = V4L2_TUNER_SUB_STEREO;
+       else
+               vm->txsubchans = V4L2_TUNER_SUB_MONO;
+
+       /* Report rds feature status */
+       if (sdev->rds_info.enabled)
+               vm->txsubchans |= V4L2_TUNER_SUB_RDS;
+       else
+               vm->txsubchans &= ~V4L2_TUNER_SUB_RDS;
+
+unlock:
+       mutex_unlock(&sdev->mutex);
+exit:
+       return rval;
+}
+
+/* si4713_s_modulator - set modulator attributes */
+static int si4713_s_modulator(struct v4l2_subdev *sd, struct v4l2_modulator *vm)
+{
+       struct si4713_device *sdev = to_si4713_device(sd);
+       int rval = 0;
+       u16 stereo, rds;
+       u32 p;
+
+       if (!sdev)
+               return -ENODEV;
+
+       if (vm->index > 0)
+               return -EINVAL;
+
+       /* Set audio mode: mono or stereo */
+       if (vm->txsubchans & V4L2_TUNER_SUB_STEREO)
+               stereo = 1;
+       else if (vm->txsubchans & V4L2_TUNER_SUB_MONO)
+               stereo = 0;
+       else
+               return -EINVAL;
+
+       rds = !!(vm->txsubchans & V4L2_TUNER_SUB_RDS);
+
+       mutex_lock(&sdev->mutex);
+
+       if (sdev->power_state) {
+               rval = si4713_read_property(sdev,
+                                               SI4713_TX_COMPONENT_ENABLE, &p);
+               if (rval < 0)
+                       goto unlock;
+
+               p = set_bits(p, stereo, 1, 1 << 1);
+               p = set_bits(p, rds, 2, 1 << 2);
+
+               rval = si4713_write_property(sdev,
+                                               SI4713_TX_COMPONENT_ENABLE, p);
+               if (rval < 0)
+                       goto unlock;
+       }
+
+       sdev->stereo = stereo;
+       sdev->rds_info.enabled = rds;
+
+unlock:
+       mutex_unlock(&sdev->mutex);
+       return rval;
+}
+
+/* si4713_g_frequency - get tuner or modulator radio frequency */
+static int si4713_g_frequency(struct v4l2_subdev *sd, struct v4l2_frequency *f)
+{
+       struct si4713_device *sdev = to_si4713_device(sd);
+       int rval = 0;
+
+       f->type = V4L2_TUNER_RADIO;
+
+       mutex_lock(&sdev->mutex);
+
+       if (sdev->power_state) {
+               u16 freq;
+               u8 p, a, n;
+
+               rval = si4713_tx_tune_status(sdev, 0x00, &freq, &p, &a, &n);
+               if (rval < 0)
+                       goto unlock;
+
+               sdev->frequency = freq;
+       }
+
+       f->frequency = si4713_to_v4l2(sdev->frequency);
+
+unlock:
+       mutex_unlock(&sdev->mutex);
+       return rval;
+}
+
+/* si4713_s_frequency - set tuner or modulator radio frequency */
+static int si4713_s_frequency(struct v4l2_subdev *sd, struct v4l2_frequency *f)
+{
+       struct si4713_device *sdev = to_si4713_device(sd);
+       int rval = 0;
+       u16 frequency = v4l2_to_si4713(f->frequency);
+
+       /* Check frequency range */
+       if (frequency < FREQ_RANGE_LOW || frequency > FREQ_RANGE_HIGH)
+               return -EDOM;
+
+       mutex_lock(&sdev->mutex);
+
+       if (sdev->power_state) {
+               rval = si4713_tx_tune_freq(sdev, frequency);
+               if (rval < 0)
+                       goto unlock;
+               frequency = rval;
+               rval = 0;
+       }
+       sdev->frequency = frequency;
+       f->frequency = si4713_to_v4l2(frequency);
+
+unlock:
+       mutex_unlock(&sdev->mutex);
+       return rval;
+}
+
+static const struct v4l2_subdev_tuner_ops si4713_subdev_tuner_ops = {
+       .g_frequency    = si4713_g_frequency,
+       .s_frequency    = si4713_s_frequency,
+       .g_modulator    = si4713_g_modulator,
+       .s_modulator    = si4713_s_modulator,
+};
+
+static const struct v4l2_subdev_ops si4713_subdev_ops = {
+       .core           = &si4713_subdev_core_ops,
+       .tuner          = &si4713_subdev_tuner_ops,
+};
+
+/*
+ * I2C driver interface
+ */
+/* si4713_probe - probe for the device */
+static int si4713_probe(struct i2c_client *client,
+                                       const struct i2c_device_id *id)
+{
+       struct si4713_device *sdev;
+       int rval;
+
+       sdev = kzalloc(sizeof *sdev, GFP_KERNEL);
+       if (!sdev) {
+               dev_err(&client->dev, "Failed to alloc video device.\n");
+               rval = -ENOMEM;
+               goto exit;
+       }
+
+       sdev->platform_data = client->dev.platform_data;
+       if (!sdev->platform_data) {
+               v4l2_err(&sdev->sd, "No platform data registered.\n");
+               rval = -ENODEV;
+               goto free_sdev;
+       }
+
+       v4l2_i2c_subdev_init(&sdev->sd, client, &si4713_subdev_ops);
+
+       mutex_init(&sdev->mutex);
+       init_completion(&sdev->work);
+
+       if (client->irq) {
+               rval = request_irq(client->irq,
+                       si4713_handler, IRQF_TRIGGER_FALLING | IRQF_DISABLED,
+                       client->name, sdev);
+               if (rval < 0) {
+                       v4l2_err(&sdev->sd, "Could not request IRQ\n");
+                       goto free_sdev;
+               }
+               v4l2_dbg(1, debug, &sdev->sd, "IRQ requested.\n");
+       } else {
+               v4l2_warn(&sdev->sd, "IRQ not configured. Using timeouts.\n");
+       }
+
+       rval = si4713_initialize(sdev);
+       if (rval < 0) {
+               v4l2_err(&sdev->sd, "Failed to probe device information.\n");
+               goto free_irq;
+       }
+
+       return 0;
+
+free_irq:
+       if (client->irq)
+               free_irq(client->irq, sdev);
+free_sdev:
+       kfree(sdev);
+exit:
+       return rval;
+}
+
+/* si4713_remove - remove the device */
+static int si4713_remove(struct i2c_client *client)
+{
+       struct v4l2_subdev *sd = i2c_get_clientdata(client);
+       struct si4713_device *sdev = to_si4713_device(sd);
+
+       if (sdev->power_state)
+               si4713_set_power_state(sdev, POWER_DOWN);
+
+       if (client->irq > 0)
+               free_irq(client->irq, sdev);
+
+       v4l2_device_unregister_subdev(sd);
+
+       kfree(sdev);
+
+       return 0;
+}
+
+/* si4713_i2c_driver - i2c driver interface */
+static const struct i2c_device_id si4713_id[] = {
+       { "si4713" , 0 },
+       { },
+};
+MODULE_DEVICE_TABLE(i2c, si4713_id);
+
+static struct i2c_driver si4713_i2c_driver = {
+       .driver         = {
+               .name   = "si4713",
+       },
+       .probe          = si4713_probe,
+       .remove         = si4713_remove,
+       .id_table       = si4713_id,
+};
+
+/* Module Interface */
+static int __init si4713_module_init(void)
+{
+       return i2c_add_driver(&si4713_i2c_driver);
+}
+
+static void __exit si4713_module_exit(void)
+{
+       i2c_del_driver(&si4713_i2c_driver);
+}
+
+module_init(si4713_module_init);
+module_exit(si4713_module_exit);
+
diff --git a/drivers/media/radio/si4713-i2c.h b/drivers/media/radio/si4713-i2c.h
new file mode 100644 (file)
index 0000000..faf8cff
--- /dev/null
@@ -0,0 +1,237 @@
+/*
+ * drivers/media/radio/si4713-i2c.h
+ *
+ * Property and commands definitions for Si4713 radio transmitter chip.
+ *
+ * Copyright (c) 2008 Instituto Nokia de Tecnologia - INdT
+ * Contact: Eduardo Valentin <eduardo.valentin@nokia.com>
+ *
+ * This file is licensed under the terms of the GNU General Public License
+ * version 2. This program is licensed "as is" without any warranty of any
+ * kind, whether express or implied.
+ *
+ */
+
+#ifndef SI4713_I2C_H
+#define SI4713_I2C_H
+
+#include <media/v4l2-subdev.h>
+#include <media/si4713.h>
+
+#define SI4713_PRODUCT_NUMBER          0x0D
+
+/* Command Timeouts */
+#define DEFAULT_TIMEOUT                        500
+#define TIMEOUT_SET_PROPERTY           20
+#define TIMEOUT_TX_TUNE_POWER          30000
+#define TIMEOUT_TX_TUNE                        110000
+#define TIMEOUT_POWER_UP               200000
+
+/*
+ * Command and its arguments definitions
+ */
+#define SI4713_PWUP_CTSIEN             (1<<7)
+#define SI4713_PWUP_GPO2OEN            (1<<6)
+#define SI4713_PWUP_PATCH              (1<<5)
+#define SI4713_PWUP_XOSCEN             (1<<4)
+#define SI4713_PWUP_FUNC_TX            0x02
+#define SI4713_PWUP_FUNC_PATCH         0x0F
+#define SI4713_PWUP_OPMOD_ANALOG       0x50
+#define SI4713_PWUP_OPMOD_DIGITAL      0x0F
+#define SI4713_PWUP_NARGS              2
+#define SI4713_PWUP_NRESP              1
+#define SI4713_CMD_POWER_UP            0x01
+
+#define SI4713_GETREV_NRESP            9
+#define SI4713_CMD_GET_REV             0x10
+
+#define SI4713_PWDN_NRESP              1
+#define SI4713_CMD_POWER_DOWN          0x11
+
+#define SI4713_SET_PROP_NARGS          5
+#define SI4713_SET_PROP_NRESP          1
+#define SI4713_CMD_SET_PROPERTY                0x12
+
+#define SI4713_GET_PROP_NARGS          3
+#define SI4713_GET_PROP_NRESP          4
+#define SI4713_CMD_GET_PROPERTY                0x13
+
+#define SI4713_GET_STATUS_NRESP                1
+#define SI4713_CMD_GET_INT_STATUS      0x14
+
+#define SI4713_CMD_PATCH_ARGS          0x15
+#define SI4713_CMD_PATCH_DATA          0x16
+
+#define SI4713_MAX_FREQ                        10800
+#define SI4713_MIN_FREQ                        7600
+#define SI4713_TXFREQ_NARGS            3
+#define SI4713_TXFREQ_NRESP            1
+#define SI4713_CMD_TX_TUNE_FREQ                0x30
+
+#define SI4713_MAX_POWER               120
+#define SI4713_MIN_POWER               88
+#define SI4713_MAX_ANTCAP              191
+#define SI4713_MIN_ANTCAP              0
+#define SI4713_TXPWR_NARGS             4
+#define SI4713_TXPWR_NRESP             1
+#define SI4713_CMD_TX_TUNE_POWER       0x31
+
+#define SI4713_TXMEA_NARGS             4
+#define SI4713_TXMEA_NRESP             1
+#define SI4713_CMD_TX_TUNE_MEASURE     0x32
+
+#define SI4713_INTACK_MASK             0x01
+#define SI4713_TXSTATUS_NARGS          1
+#define SI4713_TXSTATUS_NRESP          8
+#define SI4713_CMD_TX_TUNE_STATUS      0x33
+
+#define SI4713_OVERMOD_BIT             (1 << 2)
+#define SI4713_IALH_BIT                        (1 << 1)
+#define SI4713_IALL_BIT                        (1 << 0)
+#define SI4713_ASQSTATUS_NARGS         1
+#define SI4713_ASQSTATUS_NRESP         5
+#define SI4713_CMD_TX_ASQ_STATUS       0x34
+
+#define SI4713_RDSBUFF_MODE_MASK       0x87
+#define SI4713_RDSBUFF_NARGS           7
+#define SI4713_RDSBUFF_NRESP           6
+#define SI4713_CMD_TX_RDS_BUFF         0x35
+
+#define SI4713_RDSPS_PSID_MASK         0x1F
+#define SI4713_RDSPS_NARGS             5
+#define SI4713_RDSPS_NRESP             1
+#define SI4713_CMD_TX_RDS_PS           0x36
+
+#define SI4713_CMD_GPO_CTL             0x80
+#define SI4713_CMD_GPO_SET             0x81
+
+/*
+ * Bits from status response
+ */
+#define SI4713_CTS                     (1<<7)
+#define SI4713_ERR                     (1<<6)
+#define SI4713_RDS_INT                 (1<<2)
+#define SI4713_ASQ_INT                 (1<<1)
+#define SI4713_STC_INT                 (1<<0)
+
+/*
+ * Property definitions
+ */
+#define SI4713_GPO_IEN                 0x0001
+#define SI4713_DIG_INPUT_FORMAT                0x0101
+#define SI4713_DIG_INPUT_SAMPLE_RATE   0x0103
+#define SI4713_REFCLK_FREQ             0x0201
+#define SI4713_REFCLK_PRESCALE         0x0202
+#define SI4713_TX_COMPONENT_ENABLE     0x2100
+#define SI4713_TX_AUDIO_DEVIATION      0x2101
+#define SI4713_TX_PILOT_DEVIATION      0x2102
+#define SI4713_TX_RDS_DEVIATION                0x2103
+#define SI4713_TX_LINE_INPUT_LEVEL     0x2104
+#define SI4713_TX_LINE_INPUT_MUTE      0x2105
+#define SI4713_TX_PREEMPHASIS          0x2106
+#define SI4713_TX_PILOT_FREQUENCY      0x2107
+#define SI4713_TX_ACOMP_ENABLE         0x2200
+#define SI4713_TX_ACOMP_THRESHOLD      0x2201
+#define SI4713_TX_ACOMP_ATTACK_TIME    0x2202
+#define SI4713_TX_ACOMP_RELEASE_TIME   0x2203
+#define SI4713_TX_ACOMP_GAIN           0x2204
+#define SI4713_TX_LIMITER_RELEASE_TIME 0x2205
+#define SI4713_TX_ASQ_INTERRUPT_SOURCE 0x2300
+#define SI4713_TX_ASQ_LEVEL_LOW                0x2301
+#define SI4713_TX_ASQ_DURATION_LOW     0x2302
+#define SI4713_TX_ASQ_LEVEL_HIGH       0x2303
+#define SI4713_TX_ASQ_DURATION_HIGH    0x2304
+#define SI4713_TX_RDS_INTERRUPT_SOURCE 0x2C00
+#define SI4713_TX_RDS_PI               0x2C01
+#define SI4713_TX_RDS_PS_MIX           0x2C02
+#define SI4713_TX_RDS_PS_MISC          0x2C03
+#define SI4713_TX_RDS_PS_REPEAT_COUNT  0x2C04
+#define SI4713_TX_RDS_PS_MESSAGE_COUNT 0x2C05
+#define SI4713_TX_RDS_PS_AF            0x2C06
+#define SI4713_TX_RDS_FIFO_SIZE                0x2C07
+
+#define PREEMPHASIS_USA                        75
+#define PREEMPHASIS_EU                 50
+#define PREEMPHASIS_DISABLED           0
+#define FMPE_USA                       0x00
+#define FMPE_EU                                0x01
+#define FMPE_DISABLED                  0x02
+
+#define POWER_UP                       0x01
+#define POWER_DOWN                     0x00
+
+struct rds_info {
+       u32 pi;
+#define MAX_RDS_PTY                    31
+       u32 pty;
+#define MAX_RDS_DEVIATION              90000
+       u32 deviation;
+/*
+ * PSNAME is known to be defined as 8 character sized (RDS Spec).
+ * However, there is receivers which scroll PSNAME 8xN sized.
+ */
+#define MAX_RDS_PS_NAME                        96
+       u8 ps_name[MAX_RDS_PS_NAME + 1];
+/*
+ * MAX_RDS_RADIO_TEXT is known to be defined as 32 (2A group) or 64 (2B group)
+ * character sized (RDS Spec).
+ * However, there is receivers which scroll them as well.
+ */
+#define MAX_RDS_RADIO_TEXT             384
+       u8 radio_text[MAX_RDS_RADIO_TEXT + 1];
+       u32 enabled;
+};
+
+struct limiter_info {
+#define MAX_LIMITER_RELEASE_TIME       102390
+       u32 release_time;
+#define MAX_LIMITER_DEVIATION          90000
+       u32 deviation;
+       u32 enabled;
+};
+
+struct pilot_info {
+#define MAX_PILOT_DEVIATION            90000
+       u32 deviation;
+#define MAX_PILOT_FREQUENCY            19000
+       u32 frequency;
+       u32 enabled;
+};
+
+struct acomp_info {
+#define MAX_ACOMP_RELEASE_TIME         1000000
+       u32 release_time;
+#define MAX_ACOMP_ATTACK_TIME          5000
+       u32 attack_time;
+#define MAX_ACOMP_THRESHOLD            0
+#define MIN_ACOMP_THRESHOLD            (-40)
+       s32 threshold;
+#define MAX_ACOMP_GAIN                 20
+       u32 gain;
+       u32 enabled;
+};
+
+/*
+ * si4713_device - private data
+ */
+struct si4713_device {
+       /* v4l2_subdev and i2c reference (v4l2_subdev priv data) */
+       struct v4l2_subdev sd;
+       /* private data structures */
+       struct mutex mutex;
+       struct completion work;
+       struct si4713_platform_data *platform_data;
+       struct rds_info rds_info;
+       struct limiter_info limiter_info;
+       struct pilot_info pilot_info;
+       struct acomp_info acomp_info;
+       u32 frequency;
+       u32 preemphasis;
+       u32 mute;
+       u32 power_level;
+       u32 power_state;
+       u32 antenna_capacitor;
+       u32 stereo;
+       u32 tune_rnl;
+};
+#endif /* ifndef SI4713_I2C_H */
index dcf9fa9264bb720856775748a3e6e69d373fcee4..1d758525d2362352437abeae6d563db50588e68c 100644 (file)
@@ -203,9 +203,9 @@ config VIDEO_CS53L32A
          module will be called cs53l32a.
 
 config VIDEO_M52790
-       tristate "Mitsubishi M52790 A/V switch"
-       depends on VIDEO_V4L2 && I2C
-       ---help---
+       tristate "Mitsubishi M52790 A/V switch"
+       depends on VIDEO_V4L2 && I2C
+       ---help---
         Support for the Mitsubishi M52790 A/V switch.
 
         To compile this driver as a module, choose M here: the
index 14baffc221920d87febcffe22a65caebe062ffd6..b8a4b52e8d472c3041230d8600d25371f399ba16 100644 (file)
@@ -151,7 +151,7 @@ static int start_urb_transfer(struct au0828_dev *dev)
        dprintk(2, "%s()\n", __func__);
 
        if (dev->urb_streaming) {
-               dprintk(2, "%s: iso xfer already running!\n", __func__);
+               dprintk(2, "%s: bulk xfer already running!\n", __func__);
                return 0;
        }
 
index 13e494365e706d54a2bfc42dd64ac41140c75e4a..cbdb65c34f219081387fce62731b1f74e0b05f41 100644 (file)
@@ -320,7 +320,6 @@ static struct i2c_algorithm au0828_i2c_algo_template = {
 static struct i2c_adapter au0828_i2c_adap_template = {
        .name              = DRIVER_NAME,
        .owner             = THIS_MODULE,
-       .id                = I2C_HW_B_AU0828,
        .algo              = &au0828_i2c_algo_template,
 };
 
index ca6558c394be0c97484bc5f67093c9e3962bfe24..b42251fa96ba4ae2fae903565d054eb243468efc 100644 (file)
@@ -1274,6 +1274,7 @@ struct tvcard bttv_tvcards[] = {
                .pll            = PLL_28,
                .tuner_type     = TUNER_TEMIC_PAL,
                .tuner_addr     = ADDR_UNSET,
+               .has_remote     = 1,
        },
 
        /* ---- card 0x3c ---------------------------------- */
index 8cc6dd28d6a7a1ca4109064d6d98994d280003a2..939d1e5129746a1d3cfece3ec5f36b1332fdc0f2 100644 (file)
@@ -2652,6 +2652,8 @@ static int bttv_querycap(struct file *file, void  *priv,
                V4L2_CAP_VBI_CAPTURE |
                V4L2_CAP_READWRITE |
                V4L2_CAP_STREAMING;
+       if (btv->has_saa6588)
+               cap->capabilities |= V4L2_CAP_RDS_CAPTURE;
        if (no_overlay <= 0)
                cap->capabilities |= V4L2_CAP_VIDEO_OVERLAY;
 
@@ -4593,14 +4595,10 @@ static int bttv_resume(struct pci_dev *pci_dev)
 #endif
 
 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_BT849,
-        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_VENDOR_ID_BROOKTREE, PCI_DEVICE_ID_BT879,
-        PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+       {PCI_VDEVICE(BROOKTREE, PCI_DEVICE_ID_BT848), 0},
+       {PCI_VDEVICE(BROOKTREE, PCI_DEVICE_ID_BT849), 0},
+       {PCI_VDEVICE(BROOKTREE, PCI_DEVICE_ID_BT878), 0},
+       {PCI_VDEVICE(BROOKTREE, PCI_DEVICE_ID_BT879), 0},
        {0,}
 };
 
index ebd1ee9dc871d222f6f918b8670aa407037e9777..beda363418b0e6f28c5bc1ed1342ef16a9676817 100644 (file)
@@ -352,7 +352,6 @@ int __devinit init_bttv_i2c(struct bttv *btv)
                /* bt878 */
                strlcpy(btv->c.i2c_adap.name, "bt878",
                        sizeof(btv->c.i2c_adap.name));
-               btv->c.i2c_adap.id = I2C_HW_B_BT848;    /* FIXME */
                btv->c.i2c_adap.algo = &bttv_algo;
        } else {
                /* bt848 */
@@ -362,7 +361,6 @@ int __devinit init_bttv_i2c(struct bttv *btv)
 
                strlcpy(btv->c.i2c_adap.name, "bttv",
                        sizeof(btv->c.i2c_adap.name));
-               btv->c.i2c_adap.id = I2C_HW_B_BT848;
                memcpy(&btv->i2c_algo, &bttv_i2c_algo_bit_template,
                       sizeof(bttv_i2c_algo_bit_template));
                btv->i2c_algo.udelay = i2c_udelay;
index 2f289d981fe62d3b3b2fba62ccc824e3d303935d..ebd51afe876199006b2dbbb2c8d49940b3f3279b 100644 (file)
@@ -245,7 +245,7 @@ static void bttv_ir_stop(struct bttv *btv)
 int bttv_input_init(struct bttv *btv)
 {
        struct card_ir *ir;
-       IR_KEYTAB_TYPE *ir_codes = NULL;
+       struct ir_scancode_table *ir_codes = NULL;
        struct input_dev *input_dev;
        int ir_type = IR_TYPE_OTHER;
        int err = -ENOMEM;
@@ -263,7 +263,7 @@ int bttv_input_init(struct bttv *btv)
        case BTTV_BOARD_AVERMEDIA:
        case BTTV_BOARD_AVPHONE98:
        case BTTV_BOARD_AVERMEDIA98:
-               ir_codes         = ir_codes_avermedia;
+               ir_codes         = &ir_codes_avermedia_table;
                ir->mask_keycode = 0xf88000;
                ir->mask_keydown = 0x010000;
                ir->polling      = 50; // ms
@@ -271,14 +271,14 @@ int bttv_input_init(struct bttv *btv)
 
        case BTTV_BOARD_AVDVBT_761:
        case BTTV_BOARD_AVDVBT_771:
-               ir_codes         = ir_codes_avermedia_dvbt;
+               ir_codes         = &ir_codes_avermedia_dvbt_table;
                ir->mask_keycode = 0x0f00c0;
                ir->mask_keydown = 0x000020;
                ir->polling      = 50; // ms
                break;
 
        case BTTV_BOARD_PXELVWPLTVPAK:
-               ir_codes         = ir_codes_pixelview;
+               ir_codes         = &ir_codes_pixelview_table;
                ir->mask_keycode = 0x003e00;
                ir->mask_keyup   = 0x010000;
                ir->polling      = 50; // ms
@@ -286,54 +286,55 @@ int bttv_input_init(struct bttv *btv)
        case BTTV_BOARD_PV_M4900:
        case BTTV_BOARD_PV_BT878P_9B:
        case BTTV_BOARD_PV_BT878P_PLUS:
-               ir_codes         = ir_codes_pixelview;
+               ir_codes         = &ir_codes_pixelview_table;
                ir->mask_keycode = 0x001f00;
                ir->mask_keyup   = 0x008000;
                ir->polling      = 50; // ms
                break;
 
        case BTTV_BOARD_WINFAST2000:
-               ir_codes         = ir_codes_winfast;
+               ir_codes         = &ir_codes_winfast_table;
                ir->mask_keycode = 0x1f8;
                break;
        case BTTV_BOARD_MAGICTVIEW061:
        case BTTV_BOARD_MAGICTVIEW063:
-               ir_codes         = ir_codes_winfast;
+               ir_codes         = &ir_codes_winfast_table;
                ir->mask_keycode = 0x0008e000;
                ir->mask_keydown = 0x00200000;
                break;
        case BTTV_BOARD_APAC_VIEWCOMP:
-               ir_codes         = ir_codes_apac_viewcomp;
+               ir_codes         = &ir_codes_apac_viewcomp_table;
                ir->mask_keycode = 0x001f00;
                ir->mask_keyup   = 0x008000;
                ir->polling      = 50; // ms
                break;
+       case BTTV_BOARD_ASKEY_CPH03X:
        case BTTV_BOARD_CONCEPTRONIC_CTVFMI2:
        case BTTV_BOARD_CONTVFMI:
-               ir_codes         = ir_codes_pixelview;
+               ir_codes         = &ir_codes_pixelview_table;
                ir->mask_keycode = 0x001F00;
                ir->mask_keyup   = 0x006000;
                ir->polling      = 50; // ms
                break;
        case BTTV_BOARD_NEBULA_DIGITV:
-               ir_codes = ir_codes_nebula;
+               ir_codes = &ir_codes_nebula_table;
                btv->custom_irq = bttv_rc5_irq;
                ir->rc5_gpio = 1;
                break;
        case BTTV_BOARD_MACHTV_MAGICTV:
-               ir_codes         = ir_codes_apac_viewcomp;
+               ir_codes         = &ir_codes_apac_viewcomp_table;
                ir->mask_keycode = 0x001F00;
                ir->mask_keyup   = 0x004000;
                ir->polling      = 50; /* ms */
                break;
        case BTTV_BOARD_KOZUMI_KTV_01C:
-               ir_codes         = ir_codes_pctv_sedna;
+               ir_codes         = &ir_codes_pctv_sedna_table;
                ir->mask_keycode = 0x001f00;
                ir->mask_keyup   = 0x006000;
                ir->polling      = 50; /* ms */
                break;
        case BTTV_BOARD_ENLTV_FM_2:
-               ir_codes         = ir_codes_encore_enltv2;
+               ir_codes         = &ir_codes_encore_enltv2_table;
                ir->mask_keycode = 0x00fd00;
                ir->mask_keyup   = 0x000080;
                ir->polling      = 1; /* ms */
index c4d181dde1cafb17ebf6ec80d2b20f9125b5cae9..9c149a78129444732f96a8b1c1117fb9812ea6ca 100644 (file)
@@ -490,7 +490,6 @@ static int cafe_smbus_setup(struct cafe_camera *cam)
        int ret;
 
        cafe_smbus_enable_irq(cam);
-       adap->id = I2C_HW_SMBUS_CAFE;
        adap->owner = THIS_MODULE;
        adap->algo = &cafe_smbus_algo;
        strcpy(adap->name, "cafe_ccic");
index 36f2d76006fd419243472a206b5a78f27489e119..f11e47a58286ae1b87901f60f6033d7e6a70878f 100644 (file)
@@ -56,7 +56,8 @@ static const struct cx18_card cx18_card_hvr1600_esmt = {
        .hw_audio_ctrl = CX18_HW_418_AV,
        .hw_muxer = CX18_HW_CS5345,
        .hw_all = CX18_HW_TVEEPROM | CX18_HW_418_AV | CX18_HW_TUNER |
-                 CX18_HW_CS5345 | CX18_HW_DVB | CX18_HW_GPIO_RESET_CTRL,
+                 CX18_HW_CS5345 | CX18_HW_DVB | CX18_HW_GPIO_RESET_CTRL |
+                 CX18_HW_Z8F0811_IR_HAUP,
        .video_inputs = {
                { CX18_CARD_INPUT_VID_TUNER,  0, CX18_AV_COMPOSITE7 },
                { CX18_CARD_INPUT_SVIDEO1,    1, CX18_AV_SVIDEO1    },
@@ -102,7 +103,8 @@ static const struct cx18_card cx18_card_hvr1600_samsung = {
        .hw_audio_ctrl = CX18_HW_418_AV,
        .hw_muxer = CX18_HW_CS5345,
        .hw_all = CX18_HW_TVEEPROM | CX18_HW_418_AV | CX18_HW_TUNER |
-                 CX18_HW_CS5345 | CX18_HW_DVB | CX18_HW_GPIO_RESET_CTRL,
+                 CX18_HW_CS5345 | CX18_HW_DVB | CX18_HW_GPIO_RESET_CTRL |
+                 CX18_HW_Z8F0811_IR_HAUP,
        .video_inputs = {
                { CX18_CARD_INPUT_VID_TUNER,  0, CX18_AV_COMPOSITE7 },
                { CX18_CARD_INPUT_SVIDEO1,    1, CX18_AV_SVIDEO1    },
@@ -204,7 +206,7 @@ static const struct cx18_card cx18_card_mpc718 = {
        .v4l2_capabilities = CX18_CAP_ENCODER,
        .hw_audio_ctrl = CX18_HW_418_AV,
        .hw_muxer = CX18_HW_GPIO_MUX,
-       .hw_all = CX18_HW_418_AV | CX18_HW_TUNER |
+       .hw_all = CX18_HW_TVEEPROM | CX18_HW_418_AV | CX18_HW_TUNER |
                  CX18_HW_GPIO_MUX | CX18_HW_DVB | CX18_HW_GPIO_RESET_CTRL,
        .video_inputs = {
                { CX18_CARD_INPUT_VID_TUNER,  0, CX18_AV_COMPOSITE2 },
index 3c552b6b7c4d3baa43d7ae4850eea92fab72d396..444e3c7c563e855159940ee70d747f3064effb30 100644 (file)
  */
 
 /* hardware flags */
-#define CX18_HW_TUNER          (1 << 0)
-#define CX18_HW_TVEEPROM       (1 << 1)
-#define CX18_HW_CS5345         (1 << 2)
-#define CX18_HW_DVB            (1 << 3)
-#define CX18_HW_418_AV         (1 << 4)
-#define CX18_HW_GPIO_MUX       (1 << 5)
-#define CX18_HW_GPIO_RESET_CTRL        (1 << 6)
+#define CX18_HW_TUNER                  (1 << 0)
+#define CX18_HW_TVEEPROM               (1 << 1)
+#define CX18_HW_CS5345                 (1 << 2)
+#define CX18_HW_DVB                    (1 << 3)
+#define CX18_HW_418_AV                 (1 << 4)
+#define CX18_HW_GPIO_MUX               (1 << 5)
+#define CX18_HW_GPIO_RESET_CTRL                (1 << 6)
+#define CX18_HW_Z8F0811_IR_TX_HAUP     (1 << 7)
+#define CX18_HW_Z8F0811_IR_RX_HAUP     (1 << 8)
+#define CX18_HW_Z8F0811_IR_HAUP        (CX18_HW_Z8F0811_IR_RX_HAUP | \
+                                CX18_HW_Z8F0811_IR_TX_HAUP)
 
 /* video inputs */
 #define        CX18_CARD_INPUT_VID_TUNER       1
index 92026e82e10ef0349b8ac2bdbdf88d4c9aad30f8..dd0224f328ad780f96f08be1441fdbe451f11950 100644 (file)
@@ -268,6 +268,20 @@ static void cx18_iounmap(struct cx18 *cx)
        }
 }
 
+static void cx18_eeprom_dump(struct cx18 *cx, unsigned char *eedata, int len)
+{
+       int i;
+
+       CX18_INFO("eeprom dump:\n");
+       for (i = 0; i < len; i++) {
+               if (0 == (i % 16))
+                       CX18_INFO("eeprom %02x:", i);
+               printk(KERN_CONT " %02x", eedata[i]);
+               if (15 == (i % 16))
+                       printk(KERN_CONT "\n");
+       }
+}
+
 /* Hauppauge card? get values from tveeprom */
 void cx18_read_eeprom(struct cx18 *cx, struct tveeprom *tv)
 {
@@ -279,8 +293,26 @@ void cx18_read_eeprom(struct cx18 *cx, struct tveeprom *tv)
        c.adapter = &cx->i2c_adap[0];
        c.addr = 0xA0 >> 1;
 
-       tveeprom_read(&c, eedata, sizeof(eedata));
-       tveeprom_hauppauge_analog(&c, tv, eedata);
+       memset(tv, 0, sizeof(*tv));
+       if (tveeprom_read(&c, eedata, sizeof(eedata)))
+               return;
+
+       switch (cx->card->type) {
+       case CX18_CARD_HVR_1600_ESMT:
+       case CX18_CARD_HVR_1600_SAMSUNG:
+               tveeprom_hauppauge_analog(&c, tv, eedata);
+               break;
+       case CX18_CARD_YUAN_MPC718:
+               tv->model = 0x718;
+               cx18_eeprom_dump(cx, eedata, sizeof(eedata));
+               CX18_INFO("eeprom PCI ID: %02x%02x:%02x%02x\n",
+                         eedata[2], eedata[1], eedata[4], eedata[3]);
+               break;
+       default:
+               tv->model = 0xffffffff;
+               cx18_eeprom_dump(cx, eedata, sizeof(eedata));
+               break;
+       }
 }
 
 static void cx18_process_eeprom(struct cx18 *cx)
@@ -298,6 +330,11 @@ static void cx18_process_eeprom(struct cx18 *cx)
        case 74000 ... 74999:
                cx->card = cx18_get_card(CX18_CARD_HVR_1600_ESMT);
                break;
+       case 0x718:
+               return;
+       case 0xffffffff:
+               CX18_INFO("Unknown EEPROM encoding\n");
+               return;
        case 0:
                CX18_ERR("Invalid EEPROM\n");
                return;
index 29969c18949c707eb336b18badea0437ff04d54b..04d9c2508b8663ad895c67482ab0a241a0eb039d 100644 (file)
@@ -690,7 +690,7 @@ int cx18_v4l2_open(struct file *filp)
        int res;
        struct video_device *video_dev = video_devdata(filp);
        struct cx18_stream *s = video_get_drvdata(video_dev);
-       struct cx18 *cx = s->cx;;
+       struct cx18 *cx = s->cx;
 
        mutex_lock(&cx->serialize_lock);
        if (cx18_init_on_first_open(cx)) {
index 8591e4fc359f64081cfa7a3b60420cd39be728f3..da395fef50dfd93b364ac9633a398351f9099c35 100644 (file)
@@ -28,6 +28,7 @@
 #include "cx18-gpio.h"
 #include "cx18-i2c.h"
 #include "cx18-irq.h"
+#include <media/ir-kbd-i2c.h>
 
 #define CX18_REG_I2C_1_WR   0xf15000
 #define CX18_REG_I2C_1_RD   0xf15008
 #define GETSDL_BIT      0x0008
 
 #define CX18_CS5345_I2C_ADDR           0x4c
+#define CX18_Z8F0811_IR_TX_I2C_ADDR    0x70
+#define CX18_Z8F0811_IR_RX_I2C_ADDR    0x71
 
 /* This array should match the CX18_HW_ defines */
 static const u8 hw_addrs[] = {
-       0,                      /* CX18_HW_TUNER */
-       0,                      /* CX18_HW_TVEEPROM */
-       CX18_CS5345_I2C_ADDR,   /* CX18_HW_CS5345 */
-       0,                      /* CX18_HW_DVB */
-       0,                      /* CX18_HW_418_AV */
-       0,                      /* CX18_HW_GPIO_MUX */
-       0,                      /* CX18_HW_GPIO_RESET_CTRL */
+       0,                              /* CX18_HW_TUNER */
+       0,                              /* CX18_HW_TVEEPROM */
+       CX18_CS5345_I2C_ADDR,           /* CX18_HW_CS5345 */
+       0,                              /* CX18_HW_DVB */
+       0,                              /* CX18_HW_418_AV */
+       0,                              /* CX18_HW_GPIO_MUX */
+       0,                              /* CX18_HW_GPIO_RESET_CTRL */
+       CX18_Z8F0811_IR_TX_I2C_ADDR,    /* CX18_HW_Z8F0811_IR_TX_HAUP */
+       CX18_Z8F0811_IR_RX_I2C_ADDR,    /* CX18_HW_Z8F0811_IR_RX_HAUP */
 };
 
 /* This array should match the CX18_HW_ defines */
@@ -62,6 +67,8 @@ static const u8 hw_bus[] = {
        0,      /* CX18_HW_418_AV */
        0,      /* CX18_HW_GPIO_MUX */
        0,      /* CX18_HW_GPIO_RESET_CTRL */
+       0,      /* CX18_HW_Z8F0811_IR_TX_HAUP */
+       0,      /* CX18_HW_Z8F0811_IR_RX_HAUP */
 };
 
 /* This array should match the CX18_HW_ defines */
@@ -73,6 +80,8 @@ static const char * const hw_modules[] = {
        NULL,           /* CX18_HW_418_AV */
        NULL,           /* CX18_HW_GPIO_MUX */
        NULL,           /* CX18_HW_GPIO_RESET_CTRL */
+       NULL,           /* CX18_HW_Z8F0811_IR_TX_HAUP */
+       NULL,           /* CX18_HW_Z8F0811_IR_RX_HAUP */
 };
 
 /* This array should match the CX18_HW_ defines */
@@ -84,8 +93,38 @@ static const char * const hw_devicenames[] = {
        "cx23418_AV",
        "gpio_mux",
        "gpio_reset_ctrl",
+       "ir_tx_z8f0811_haup",
+       "ir_rx_z8f0811_haup",
 };
 
+static const struct IR_i2c_init_data z8f0811_ir_init_data = {
+       .ir_codes = &ir_codes_hauppauge_new_table,
+       .internal_get_key_func = IR_KBD_GET_KEY_HAUP_XVR,
+       .type = IR_TYPE_RC5,
+       .name = "CX23418 Z8F0811 Hauppauge",
+};
+
+static int cx18_i2c_new_ir(struct i2c_adapter *adap, u32 hw, const char *type,
+                          u8 addr)
+{
+       struct i2c_board_info info;
+       unsigned short addr_list[2] = { addr, I2C_CLIENT_END };
+
+       memset(&info, 0, sizeof(struct i2c_board_info));
+       strlcpy(info.type, type, I2C_NAME_SIZE);
+
+       /* Our default information for ir-kbd-i2c.c to use */
+       switch (hw) {
+       case CX18_HW_Z8F0811_IR_RX_HAUP:
+               info.platform_data = &z8f0811_ir_init_data;
+               break;
+       default:
+               break;
+       }
+
+       return i2c_new_probed_device(adap, &info, addr_list) == NULL ? -1 : 0;
+}
+
 int cx18_i2c_register(struct cx18 *cx, unsigned idx)
 {
        struct v4l2_subdev *sd;
@@ -115,11 +154,14 @@ int cx18_i2c_register(struct cx18 *cx, unsigned idx)
                return sd != NULL ? 0 : -1;
        }
 
+       if (hw & CX18_HW_Z8F0811_IR_HAUP)
+               return cx18_i2c_new_ir(adap, hw, type, hw_addrs[idx]);
+
        /* Is it not an I2C device or one we do not wish to register? */
        if (!hw_addrs[idx])
                return -1;
 
-       /* It's an I2C device other than an analog tuner */
+       /* It's an I2C device other than an analog tuner or IR chip */
        sd = v4l2_i2c_new_subdev(&cx->v4l2_dev, adap, mod, type, hw_addrs[idx]);
        if (sd != NULL)
                sd->grp_id = hw;
@@ -190,7 +232,6 @@ static int cx18_getsda(void *data)
 /* template for i2c-bit-algo */
 static struct i2c_adapter cx18_i2c_adap_template = {
        .name = "cx18 i2c driver",
-       .id = I2C_HW_B_CX2341X,
        .algo = NULL,                   /* set by i2c-algo-bit */
        .algo_data = NULL,              /* filled from template */
        .owner = THIS_MODULE,
index d7b1921e6666006f327c54b3e18ce8b3ac649886..fc76e4d6ffa72d3d6c48e9bc169d2465a5f03a25 100644 (file)
@@ -605,7 +605,7 @@ int cx18_s_input(struct file *file, void *fh, unsigned int inp)
        if (ret)
                return ret;
 
-       if (inp < 0 || inp >= cx->nof_inputs)
+       if (inp >= cx->nof_inputs)
                return -EINVAL;
 
        if (inp == cx->active_input) {
index a6f398a175c53e01b6f8bd3bc0349cfd385a8cee..31a8759f6e54e63dd37adc79bb491edb31afe397 100644 (file)
 #define PWR_RESETOUT_EN         0x100  /* bit8 */
 
 enum AV_MODE{
-       POLARIS_AVMODE_DEFAULT = 0,
-       POLARIS_AVMODE_DIGITAL = 0x10,
-       POLARIS_AVMODE_ANALOGT_TV = 0x20,
-       POLARIS_AVMODE_ENXTERNAL_AV = 0x30,
+       POLARIS_AVMODE_DEFAULT = 0,
+       POLARIS_AVMODE_DIGITAL = 0x10,
+       POLARIS_AVMODE_ANALOGT_TV = 0x20,
+       POLARIS_AVMODE_ENXTERNAL_AV = 0x30,
 
 };
 
index 33219dc4d64987e640f109f853ec6a8b30159cc7..58d9cc0867b9a43bcc7240e8e578041cadbe87e0 100644 (file)
@@ -432,7 +432,6 @@ static struct i2c_algorithm cx231xx_algo = {
 static struct i2c_adapter cx231xx_adap_template = {
        .owner = THIS_MODULE,
        .name = "cx231xx",
-       .id = I2C_HW_B_CX231XX,
        .algo = &cx231xx_algo,
 };
 
index 609bae6098d395b6aaee1f81fe683ca3f2771512..36503725d9735b064399ba25e5aa0bddab04b994 100644 (file)
@@ -923,8 +923,8 @@ static int vidioc_g_fmt_vid_cap(struct file *file, void *priv,
 
        f->fmt.pix.width = dev->width;
        f->fmt.pix.height = dev->height;
-       f->fmt.pix.pixelformat = dev->format->fourcc;;
-       f->fmt.pix.bytesperline = (dev->width * dev->format->depth + 7) >> 3;;
+       f->fmt.pix.pixelformat = dev->format->fourcc;
+       f->fmt.pix.bytesperline = (dev->width * dev->format->depth + 7) >> 3;
        f->fmt.pix.sizeimage = f->fmt.pix.bytesperline * dev->height;
        f->fmt.pix.colorspace = V4L2_COLORSPACE_SMPTE170M;
 
index a0f823ac6b8d4db3c3c30fe99f7acde86cdff356..64e2ddd3c4018358e073da2ce5e0af094dd337ff 100644 (file)
@@ -282,7 +282,7 @@ struct cx231xx_board {
 
        struct cx231xx_input input[MAX_CX231XX_INPUT];
        struct cx231xx_input radio;
-       IR_KEYTAB_TYPE *ir_codes;
+       struct ir_scancode_table *ir_codes;
 };
 
 /* device states */
index 08582e58bdbf368529099eb249fb77eaab9038cb..0316257b73456dba041e4f88ab6b18eed066b583 100644 (file)
@@ -443,6 +443,7 @@ int netup_ci_init(struct cx23885_tsport *port)
                goto err;
 
        INIT_WORK(&state->work, netup_read_ci_status);
+       schedule_work(&state->work);
 
        ci_dbg_print("%s: CI initialized!\n", __func__);
 
index 1a1048b18f7027c67eed1eac69b30fd1ad0b055d..6c3b51ce3372f1eed9c0b93c29a79c88074464ee 100644 (file)
@@ -630,6 +630,39 @@ int mc417_memory_read(struct cx23885_dev *dev, u32 address, u32 *value)
        return retval;
 }
 
+void mc417_gpio_set(struct cx23885_dev *dev, u32 mask)
+{
+       u32 val;
+
+       /* Set the gpio value */
+       mc417_register_read(dev, 0x900C, &val);
+       val |= (mask & 0x000ffff);
+       mc417_register_write(dev, 0x900C, val);
+}
+
+void mc417_gpio_clear(struct cx23885_dev *dev, u32 mask)
+{
+       u32 val;
+
+       /* Clear the gpio value */
+       mc417_register_read(dev, 0x900C, &val);
+       val &= ~(mask & 0x0000ffff);
+       mc417_register_write(dev, 0x900C, val);
+}
+
+void mc417_gpio_enable(struct cx23885_dev *dev, u32 mask, int asoutput)
+{
+       u32 val;
+
+       /* Enable GPIO direction bits */
+       mc417_register_read(dev, 0x9020, &val);
+       if (asoutput)
+               val |= (mask & 0x0000ffff);
+       else
+               val &= ~(mask & 0x0000ffff);
+
+       mc417_register_write(dev, 0x9020, val);
+}
 /* ------------------------------------------------------------------ */
 
 /* MPEG encoder API */
@@ -955,25 +988,8 @@ static int cx23885_load_firmware(struct cx23885_dev *dev)
        retval |= mc417_register_write(dev, IVTV_REG_HW_BLOCKS,
                IVTV_CMD_HW_BLOCKS_RST);
 
-       /* Restore GPIO settings, make sure EIO14 is enabled as an output. */
-       dprintk(2, "%s: GPIO output EIO 0-15 was = 0x%x\n",
-               __func__, gpio_output);
-       /* Power-up seems to have GPIOs AFU. This was causing digital side
-        * to fail at power-up. Seems GPIOs should be set to 0x10ff0411 at
-        * power-up.
-        * gpio_output |= (1<<14);
-        */
-       /* Note: GPIO14 is specific to the HVR1800 here */
-       gpio_output = 0x10ff0411 | (1<<14);
-       retval |= mc417_register_write(dev, 0x9020, gpio_output | (1<<14));
-       dprintk(2, "%s: GPIO output EIO 0-15 now = 0x%x\n",
-               __func__, gpio_output);
-
-       dprintk(1, "%s: GPIO value  EIO 0-15 was = 0x%x\n",
-               __func__, value);
-       value |= (1<<14);
-       dprintk(1, "%s: GPIO value  EIO 0-15 now = 0x%x\n",
-               __func__, value);
+       /* F/W power up disturbs the GPIOs, restore state */
+       retval |= mc417_register_write(dev, 0x9020, gpio_output);
        retval |= mc417_register_write(dev, 0x900C, value);
 
        retval |= mc417_register_read(dev, IVTV_REG_VPU, &value);
@@ -1788,9 +1804,6 @@ int cx23885_417_register(struct cx23885_dev *dev)
                return err;
        }
 
-       /* Initialize MC417 registers */
-       cx23885_mc417_init(dev);
-
        printk(KERN_INFO "%s: registered device video%d [mpeg]\n",
               dev->name, dev->v4l_device->num);
 
index ce29b5e34a11329f58e5fca573205d8316876ff7..3143d85ef31d03236345fd4ec7a7c9391942404a 100644 (file)
@@ -201,6 +201,15 @@ struct cx23885_board cx23885_boards[] = {
                .name           = "Mygica X8506 DMB-TH",
                .portb          = CX23885_MPEG_DVB,
        },
+       [CX23885_BOARD_MAGICPRO_PROHDTVE2] = {
+               .name           = "Magic-Pro ProHDTV Extreme 2",
+               .portb          = CX23885_MPEG_DVB,
+       },
+       [CX23885_BOARD_HAUPPAUGE_HVR1850] = {
+               .name           = "Hauppauge WinTV-HVR1850",
+               .portb          = CX23885_MPEG_ENCODER,
+               .portc          = CX23885_MPEG_DVB,
+       },
 };
 const unsigned int cx23885_bcount = ARRAY_SIZE(cx23885_boards);
 
@@ -324,6 +333,14 @@ struct cx23885_subid cx23885_subids[] = {
                .subvendor = 0x14f1,
                .subdevice = 0x8651,
                .card      = CX23885_BOARD_MYGICA_X8506,
+       }, {
+               .subvendor = 0x14f1,
+               .subdevice = 0x8657,
+               .card      = CX23885_BOARD_MAGICPRO_PROHDTVE2,
+       }, {
+               .subvendor = 0x0070,
+               .subdevice = 0x8541,
+               .card      = CX23885_BOARD_HAUPPAUGE_HVR1850,
        },
 };
 const unsigned int cx23885_idcount = ARRAY_SIZE(cx23885_subids);
@@ -483,8 +500,13 @@ static void hauppauge_eeprom(struct cx23885_dev *dev, u8 *eeprom_data)
                /* WinTV-HVR1700 (PCIe, OEM, No IR, full height)
                 * DVB-T and MPEG2 HW Encoder */
                break;
+       case 85021:
+               /* WinTV-HVR1850 (PCIe, OEM, RCA in, IR, FM,
+                       Dual channel ATSC and MPEG2 HW Encoder */
+               break;
        default:
-               printk(KERN_WARNING "%s: warning: unknown hauppauge model #%d\n",
+               printk(KERN_WARNING "%s: warning: "
+                       "unknown hauppauge model #%d\n",
                        dev->name, tv.model);
                break;
        }
@@ -574,13 +596,23 @@ void cx23885_gpio_setup(struct cx23885_dev *dev)
                /* CX23417 GPIO's */
                /* EIO15 Zilog Reset */
                /* EIO14 S5H1409/CX24227 Reset */
+               mc417_gpio_enable(dev, GPIO_15 | GPIO_14, 1);
+
+               /* Put the demod into reset and protect the eeprom */
+               mc417_gpio_clear(dev, GPIO_15 | GPIO_14);
+               mdelay(100);
+
+               /* Bring the demod and blaster out of reset */
+               mc417_gpio_set(dev, GPIO_15 | GPIO_14);
+               mdelay(100);
 
                /* Force the TDA8295A into reset and back */
-               cx_set(GP0_IO, 0x00040004);
+               cx23885_gpio_enable(dev, GPIO_2, 1);
+               cx23885_gpio_set(dev, GPIO_2);
                mdelay(20);
-               cx_clear(GP0_IO, 0x00000004);
+               cx23885_gpio_clear(dev, GPIO_2);
                mdelay(20);
-               cx_set(GP0_IO, 0x00040004);
+               cx23885_gpio_set(dev, GPIO_2);
                mdelay(20);
                break;
        case CX23885_BOARD_HAUPPAUGE_HVR1200:
@@ -715,14 +747,45 @@ void cx23885_gpio_setup(struct cx23885_dev *dev)
                cx23885_gpio_set(dev, GPIO_9);
                break;
        case CX23885_BOARD_MYGICA_X8506:
+       case CX23885_BOARD_MAGICPRO_PROHDTVE2:
                /* GPIO-1 reset XC5000 */
-               /* GPIO-2 reset LGS8GL5 */
+               /* GPIO-2 reset LGS8GL5 / LGS8G75 */
                cx_set(GP0_IO, 0x00060000);
                cx_clear(GP0_IO, 0x00000006);
                mdelay(100);
                cx_set(GP0_IO, 0x00060006);
                mdelay(100);
                break;
+       case CX23885_BOARD_HAUPPAUGE_HVR1850:
+               /* GPIO-0 656_CLK */
+               /* GPIO-1 656_D0 */
+               /* GPIO-2 Wake# */
+               /* GPIO-3-10 cx23417 data0-7 */
+               /* GPIO-11-14 cx23417 addr0-3 */
+               /* GPIO-15-18 cx23417 READY, CS, RD, WR */
+               /* GPIO-19 IR_RX */
+               /* GPIO-20 C_IR_TX */
+               /* GPIO-21 I2S DAT */
+               /* GPIO-22 I2S WCLK */
+               /* GPIO-23 I2S BCLK */
+               /* ALT GPIO: EXP GPIO LATCH */
+
+               /* CX23417 GPIO's */
+               /* GPIO-14 S5H1411/CX24228 Reset */
+               /* GPIO-13 EEPROM write protect */
+               mc417_gpio_enable(dev, GPIO_14 | GPIO_13, 1);
+
+               /* Put the demod into reset and protect the eeprom */
+               mc417_gpio_clear(dev, GPIO_14 | GPIO_13);
+               mdelay(100);
+
+               /* Bring the demod out of reset */
+               mc417_gpio_set(dev, GPIO_14);
+               mdelay(100);
+
+               /* CX24228 GPIO */
+               /* Connected to IF / Mux */
+               break;
        }
 }
 
@@ -739,6 +802,7 @@ int cx23885_ir_init(struct cx23885_dev *dev)
        case CX23885_BOARD_HAUPPAUGE_HVR1275:
        case CX23885_BOARD_HAUPPAUGE_HVR1255:
        case CX23885_BOARD_HAUPPAUGE_HVR1210:
+       case CX23885_BOARD_HAUPPAUGE_HVR1850:
                /* FIXME: Implement me */
                break;
        case CX23885_BOARD_DVICO_FUSIONHDTV_DVB_T_DUAL_EXP:
@@ -778,6 +842,7 @@ void cx23885_card_setup(struct cx23885_dev *dev)
        case CX23885_BOARD_HAUPPAUGE_HVR1275:
        case CX23885_BOARD_HAUPPAUGE_HVR1255:
        case CX23885_BOARD_HAUPPAUGE_HVR1210:
+       case CX23885_BOARD_HAUPPAUGE_HVR1850:
                if (dev->i2c_bus[0].i2c_rc == 0)
                        hauppauge_eeprom(dev, eeprom+0xc0);
                break;
@@ -827,6 +892,7 @@ void cx23885_card_setup(struct cx23885_dev *dev)
                ts2->src_sel_val   = CX23885_SRC_SEL_PARALLEL_MPEG_VIDEO;
                break;
        case CX23885_BOARD_MYGICA_X8506:
+       case CX23885_BOARD_MAGICPRO_PROHDTVE2:
                ts1->gen_ctrl_val  = 0x5; /* Parallel */
                ts1->ts_clk_en_val = 0x1; /* Enable TS_CLK */
                ts1->src_sel_val   = CX23885_SRC_SEL_PARALLEL_MPEG_VIDEO;
@@ -844,6 +910,7 @@ void cx23885_card_setup(struct cx23885_dev *dev)
        case CX23885_BOARD_HAUPPAUGE_HVR1275:
        case CX23885_BOARD_HAUPPAUGE_HVR1255:
        case CX23885_BOARD_HAUPPAUGE_HVR1210:
+       case CX23885_BOARD_HAUPPAUGE_HVR1850:
        default:
                ts2->gen_ctrl_val  = 0xc; /* Serial bus + punctured clock */
                ts2->ts_clk_en_val = 0x1; /* Enable TS_CLK */
index bf7bb1c412fb6e3735daf7dee875fa1b1a705ac0..40d438d7234dda326ed9fd2ea7b2c5db1d698a4e 100644 (file)
@@ -713,12 +713,26 @@ static void cx23885_dev_checkrevision(struct cx23885_dev *dev)
                dev->hwrevision = 0xa1;
                break;
        case 0x02:
-               /* CX23885-13Z */
+               /* CX23885-13Z/14Z */
                dev->hwrevision = 0xb0;
                break;
        case 0x03:
-               /* CX23888-22Z */
-               dev->hwrevision = 0xc0;
+               if (dev->pci->device == 0x8880) {
+                       /* CX23888-21Z/22Z */
+                       dev->hwrevision = 0xc0;
+               } else {
+                       /* CX23885-14Z */
+                       dev->hwrevision = 0xa4;
+               }
+               break;
+       case 0x04:
+               if (dev->pci->device == 0x8880) {
+                       /* CX23888-31Z */
+                       dev->hwrevision = 0xd0;
+               } else {
+                       /* CX23885-15Z, CX23888-31Z */
+                       dev->hwrevision = 0xa5;
+               }
                break;
        case 0x0e:
                /* CX23887-15Z */
@@ -756,6 +770,7 @@ static int cx23885_dev_setup(struct cx23885_dev *dev)
 
        /* Configure the internal memory */
        if (dev->pci->device == 0x8880) {
+               /* Could be 887 or 888, assume a default */
                dev->bridge = CX23885_BRIDGE_887;
                /* Apply a sensible clock frequency for the PCIe bridge */
                dev->clk_freq = 25000000;
@@ -868,6 +883,14 @@ static int cx23885_dev_setup(struct cx23885_dev *dev)
        dprintk(1, "%s() radio_type = 0x%x radio_addr = 0x%x\n",
                __func__, dev->radio_type, dev->radio_addr);
 
+       /* The cx23417 encoder has GPIO's that need to be initialised
+        * before DVB, so that demodulators and tuners are out of
+        * reset before DVB uses them.
+        */
+       if ((cx23885_boards[dev->board].portb == CX23885_MPEG_ENCODER) ||
+               (cx23885_boards[dev->board].portc == CX23885_MPEG_ENCODER))
+                       cx23885_mc417_init(dev);
+
        /* init hardware */
        cx23885_reset(dev);
 
@@ -1250,6 +1273,7 @@ static int cx23885_start_dma(struct cx23885_tsport *port,
        switch (dev->bridge) {
        case CX23885_BRIDGE_885:
        case CX23885_BRIDGE_887:
+       case CX23885_BRIDGE_888:
                /* enable irqs */
                dprintk(1, "%s() enabling TS int's and DMA\n", __func__);
                cx_set(port->reg_ts_int_msk,  port->ts_int_msk_val);
index 86ac529e62be0be042ea6912225ddf9d7d1d89bc..022fad798fc2aaea239cb08959dc65d2deebe580 100644 (file)
@@ -396,7 +396,7 @@ static struct stv0900_reg stv0900_ts_regs[] = {
 
 static struct stv0900_config netup_stv0900_config = {
        .demod_address = 0x68,
-       .xtal = 27000000,
+       .xtal = 8000000,
        .clkmode = 3,/* 0-CLKI, 2-XTALI, else AUTO */
        .diseqc_mode = 2,/* 2/3 PWM */
        .ts_config_regs = stv0900_ts_regs,
@@ -408,14 +408,14 @@ static struct stv0900_config netup_stv0900_config = {
 
 static struct stv6110_config netup_stv6110_tunerconfig_a = {
        .i2c_address = 0x60,
-       .mclk = 27000000,
-       .iq_wiring = 0,
+       .mclk = 16000000,
+       .clk_div = 1,
 };
 
 static struct stv6110_config netup_stv6110_tunerconfig_b = {
        .i2c_address = 0x63,
-       .mclk = 27000000,
-       .iq_wiring = 1,
+       .mclk = 16000000,
+       .clk_div = 1,
 };
 
 static int tbs_set_voltage(struct dvb_frontend *fe, fe_sec_voltage_t voltage)
@@ -487,6 +487,26 @@ static int cx23885_dvb_set_frontend(struct dvb_frontend *fe,
                port->set_frontend_save(fe, param) : -ENODEV;
 }
 
+static struct lgs8gxx_config magicpro_prohdtve2_lgs8g75_config = {
+       .prod = LGS8GXX_PROD_LGS8G75,
+       .demod_address = 0x19,
+       .serial_ts = 0,
+       .ts_clk_pol = 1,
+       .ts_clk_gated = 1,
+       .if_clk_freq = 30400, /* 30.4 MHz */
+       .if_freq = 6500, /* 6.50 MHz */
+       .if_neg_center = 1,
+       .ext_adc = 0,
+       .adc_signed = 1,
+       .adc_vpp = 2, /* 1.6 Vpp */
+       .if_neg_edge = 1,
+};
+
+static struct xc5000_config magicpro_prohdtve2_xc5000_config = {
+       .i2c_address = 0x61,
+       .if_khz = 6500,
+};
+
 static int dvb_register(struct cx23885_tsport *port)
 {
        struct cx23885_dev *dev = port->dev;
@@ -833,6 +853,30 @@ static int dvb_register(struct cx23885_tsport *port)
                                &mygica_x8506_xc5000_config);
                }
                break;
+       case CX23885_BOARD_MAGICPRO_PROHDTVE2:
+               i2c_bus = &dev->i2c_bus[0];
+               i2c_bus2 = &dev->i2c_bus[1];
+               fe0->dvb.frontend = dvb_attach(lgs8gxx_attach,
+                       &magicpro_prohdtve2_lgs8g75_config,
+                       &i2c_bus->i2c_adap);
+               if (fe0->dvb.frontend != NULL) {
+                       dvb_attach(xc5000_attach,
+                               fe0->dvb.frontend,
+                               &i2c_bus2->i2c_adap,
+                               &magicpro_prohdtve2_xc5000_config);
+               }
+               break;
+       case CX23885_BOARD_HAUPPAUGE_HVR1850:
+               i2c_bus = &dev->i2c_bus[0];
+               fe0->dvb.frontend = dvb_attach(s5h1411_attach,
+                       &hcw_s5h1411_config,
+                       &i2c_bus->i2c_adap);
+               if (fe0->dvb.frontend != NULL)
+                       dvb_attach(tda18271_attach, fe0->dvb.frontend,
+                               0x60, &dev->i2c_bus[0].i2c_adap,
+                               &hauppauge_tda18271_config);
+               break;
+
        default:
                printk(KERN_INFO "%s: The frontend of your DVB/ATSC card "
                        " isn't supported yet\n",
index 384dec34134fe56ef6298909fa6a633a0c9bec4b..4172cb3874207428556d5d75e99d46e1d5f6a38f 100644 (file)
@@ -283,7 +283,6 @@ static struct i2c_algorithm cx23885_i2c_algo_template = {
 static struct i2c_adapter cx23885_i2c_adap_template = {
        .name              = "cx23885",
        .owner             = THIS_MODULE,
-       .id                = I2C_HW_B_CX23885,
        .algo              = &cx23885_i2c_algo_template,
 };
 
index 214a55e943b783dc7a6cfaab95bb25f4fe504ee1..86f26947bb78ca5bce6fa8cc63c6b9b429c2e01f 100644 (file)
@@ -76,6 +76,8 @@
 #define CX23885_BOARD_HAUPPAUGE_HVR1255        20
 #define CX23885_BOARD_HAUPPAUGE_HVR1210        21
 #define CX23885_BOARD_MYGICA_X8506             22
+#define CX23885_BOARD_MAGICPRO_PROHDTVE2       23
+#define CX23885_BOARD_HAUPPAUGE_HVR1850        24
 
 #define GPIO_0 0x00000001
 #define GPIO_1 0x00000002
 #define GPIO_7 0x00000080
 #define GPIO_8 0x00000100
 #define GPIO_9 0x00000200
+#define GPIO_10 0x00000400
+#define GPIO_11 0x00000800
+#define GPIO_12 0x00001000
+#define GPIO_13 0x00002000
+#define GPIO_14 0x00004000
+#define GPIO_15 0x00008000
 
 /* Currently unsupported by the driver: PAL/H, NTSC/Kr, SECAM B/G/H/LC */
 #define CX23885_NORMS (\
@@ -331,6 +339,7 @@ struct cx23885_dev {
                CX23885_BRIDGE_UNDEFINED = 0,
                CX23885_BRIDGE_885 = 885,
                CX23885_BRIDGE_887 = 887,
+               CX23885_BRIDGE_888 = 888,
        } bridge;
 
        /* Analog video */
@@ -395,7 +404,7 @@ struct sram_channel {
        u32  cmds_start;
        u32  ctrl_start;
        u32  cdt;
-       u32  fifo_start;;
+       u32  fifo_start;
        u32  fifo_size;
        u32  ptr1_reg;
        u32  ptr2_reg;
@@ -504,6 +513,9 @@ extern void cx23885_417_check_encoder(struct cx23885_dev *dev);
 extern void cx23885_mc417_init(struct cx23885_dev *dev);
 extern int mc417_memory_read(struct cx23885_dev *dev, u32 address, u32 *value);
 extern int mc417_memory_write(struct cx23885_dev *dev, u32 address, u32 value);
+extern void mc417_gpio_set(struct cx23885_dev *dev, u32 mask);
+extern void mc417_gpio_clear(struct cx23885_dev *dev, u32 mask);
+extern void mc417_gpio_enable(struct cx23885_dev *dev, u32 mask, int asoutput);
 
 
 /* ----------------------------------------------------------- */
index 0be51b65f0981c2387f2b9b9872e29e6d29f2f93..1aeaf18a9bea3010c2889380e22cd81d344d6f08 100644 (file)
@@ -321,6 +321,15 @@ static void cx23885_initialize(struct i2c_client *client)
        /* Select AFE clock pad output source */
        cx25840_write(client, 0x144, 0x05);
 
+       /* Drive GPIO2 direction and values for HVR1700
+        * where an onboard mux selects the output of demodulator
+        * vs the 417. Failure to set this results in no DTV.
+        * It's safe to set this across all Hauppauge boards
+        * currently, regardless of the board type.
+        */
+       cx25840_write(client, 0x160, 0x1d);
+       cx25840_write(client, 0x164, 0x00);
+
        /* Do the firmware load in a work handler to prevent.
           Otherwise the kernel is blocked waiting for the
           bit-banging i2c interface to finish uploading the
@@ -1578,12 +1587,6 @@ static int cx25840_probe(struct i2c_client *client,
        state->id = id;
        state->rev = device_id;
 
-       if (state->is_cx23885) {
-               /* Drive GPIO2 direction and values */
-               cx25840_write(client, 0x160, 0x1d);
-               cx25840_write(client, 0x164, 0x00);
-       }
-
        return 0;
 }
 
index 0df53b0d75d9ab07a6377eae4437a36e613bbf01..1f483c1d0dbe8b6808768d8b9fe1ff95e6da1c0f 100644 (file)
 
 #include "cx25840-core.h"
 
-#define FWFILE "v4l-cx25840.fw"
-#define FWFILE_CX23885 "v4l-cx23885-avcore-01.fw"
-#define FWFILE_CX231XX "v4l-cx231xx-avcore-01.fw"
-
 /*
  * Mike Isely <isely@pobox.com> - The FWSEND parameter controls the
  * size of the firmware chunks sent down the I2C bus to the chip.
 
 #define FWDEV(x) &((x)->dev)
 
-static char *firmware = FWFILE;
+static char *firmware = "";
 
 module_param(firmware, charp, 0444);
 
-MODULE_PARM_DESC(firmware, "Firmware image [default: " FWFILE "]");
+MODULE_PARM_DESC(firmware, "Firmware image to load");
 
 static void start_fw_load(struct i2c_client *client)
 {
@@ -65,6 +61,19 @@ static void end_fw_load(struct i2c_client *client)
        cx25840_write(client, 0x803, 0x03);
 }
 
+static const char *get_fw_name(struct i2c_client *client)
+{
+       struct cx25840_state *state = to_state(i2c_get_clientdata(client));
+
+       if (firmware[0])
+               return firmware;
+       if (state->is_cx23885)
+               return "v4l-cx23885-avcore-01.fw";
+       if (state->is_cx231xx)
+               return "v4l-cx231xx-avcore-01.fw";
+       return "v4l-cx25840.fw";
+}
+
 static int check_fw_load(struct i2c_client *client, int size)
 {
        /* DL_ADDR_HB DL_ADDR_LB */
@@ -72,11 +81,13 @@ static int check_fw_load(struct i2c_client *client, int size)
        s |= cx25840_read(client, 0x800);
 
        if (size != s) {
-               v4l_err(client, "firmware %s load failed\n", firmware);
+               v4l_err(client, "firmware %s load failed\n",
+                               get_fw_name(client));
                return -EINVAL;
        }
 
-       v4l_info(client, "loaded %s firmware (%d bytes)\n", firmware, size);
+       v4l_info(client, "loaded %s firmware (%d bytes)\n",
+                       get_fw_name(client), size);
        return 0;
 }
 
@@ -96,21 +107,24 @@ int cx25840_loadfw(struct i2c_client *client)
        const struct firmware *fw = NULL;
        u8 buffer[FWSEND];
        const u8 *ptr;
+       const char *fwname = get_fw_name(client);
        int size, retval;
        int MAX_BUF_SIZE = FWSEND;
+       u32 gpio_oe = 0, gpio_da = 0;
 
-       if (state->is_cx23885)
-               firmware = FWFILE_CX23885;
-       else if (state->is_cx231xx)
-               firmware = FWFILE_CX231XX;
+       if (state->is_cx23885) {
+               /* Preserve the GPIO OE and output bits */
+               gpio_oe = cx25840_read(client, 0x160);
+               gpio_da = cx25840_read(client, 0x164);
+       }
 
        if ((state->is_cx231xx) && MAX_BUF_SIZE > 16) {
                v4l_err(client, " Firmware download size changed to 16 bytes max length\n");
                MAX_BUF_SIZE = 16;  /* cx231xx cannot accept more than 16 bytes at a time */
        }
 
-       if (request_firmware(&fw, firmware, FWDEV(client)) != 0) {
-               v4l_err(client, "unable to open firmware %s\n", firmware);
+       if (request_firmware(&fw, fwname, FWDEV(client)) != 0) {
+               v4l_err(client, "unable to open firmware %s\n", fwname);
                return -EINVAL;
        }
 
@@ -142,5 +156,11 @@ int cx25840_loadfw(struct i2c_client *client)
        size = fw->size;
        release_firmware(fw);
 
+       if (state->is_cx23885) {
+               /* Restore GPIO configuration after f/w load */
+               cx25840_write(client, 0x160, gpio_oe);
+               cx25840_write(client, 0x164, gpio_da);
+       }
+
        return check_fw_load(client, size);
 }
index 39465301ec94ea78fa6d6f54ae467f0b9fc3e119..e5f07fbd5a35a79da1240cb70adffa03981f5a43 100644 (file)
@@ -1283,6 +1283,51 @@ static const struct cx88_board cx88_boards[] = {
                },
                .mpeg           = CX88_MPEG_DVB,
        },
+       [CX88_BOARD_WINFAST_DTV2000H_J] = {
+               .name           = "WinFast DTV2000 H rev. J",
+               .tuner_type     = TUNER_PHILIPS_FMD1216ME_MK3,
+               .radio_type     = UNSET,
+               .tuner_addr     = ADDR_UNSET,
+               .radio_addr     = ADDR_UNSET,
+               .tda9887_conf   = TDA9887_PRESENT,
+               .input          = {{
+                       .type   = CX88_VMUX_TELEVISION,
+                       .vmux   = 0,
+                       .gpio0  = 0x00017300,
+                       .gpio1  = 0x00008207,
+                       .gpio2  = 0x00000000,
+                       .gpio3  = 0x02000000,
+               },{
+                       .type   = CX88_VMUX_TELEVISION,
+                       .vmux   = 0,
+                       .gpio0  = 0x00018300,
+                       .gpio1  = 0x0000f207,
+                       .gpio2  = 0x00017304,
+                       .gpio3  = 0x02000000,
+               },{
+                       .type   = CX88_VMUX_COMPOSITE1,
+                       .vmux   = 1,
+                       .gpio0  = 0x00018301,
+                       .gpio1  = 0x0000f207,
+                       .gpio2  = 0x00017304,
+                       .gpio3  = 0x02000000,
+               },{
+                       .type   = CX88_VMUX_SVIDEO,
+                       .vmux   = 2,
+                       .gpio0  = 0x00018301,
+                       .gpio1  = 0x0000f207,
+                       .gpio2  = 0x00017304,
+                       .gpio3  = 0x02000000,
+               }},
+               .radio = {
+                        .type  = CX88_RADIO,
+                        .gpio0 = 0x00015702,
+                        .gpio1 = 0x0000f207,
+                        .gpio2 = 0x00015702,
+                        .gpio3 = 0x02000000,
+               },
+               .mpeg           = CX88_MPEG_DVB,
+       },
        [CX88_BOARD_GENIATECH_DVBS] = {
                .name          = "Geniatech DVB-S",
                .tuner_type    = TUNER_ABSENT,
@@ -1908,7 +1953,8 @@ static const struct cx88_board cx88_boards[] = {
                .radio_addr     = ADDR_UNSET,
                .input          = {{
                        .type   = CX88_VMUX_DVB,
-                       .vmux   = 1,
+                       .vmux   = 0,
+                       .gpio0  = 0x8080,
                } },
                .mpeg           = CX88_MPEG_DVB,
        },
@@ -2281,6 +2327,10 @@ static const struct cx88_subid cx88_subids[] = {
                .subvendor = 0x107d,
                .subdevice = 0x665e,
                .card      = CX88_BOARD_WINFAST_DTV2000H,
+       },{
+               .subvendor = 0x107d,
+               .subdevice = 0x6f2b,
+               .card      = CX88_BOARD_WINFAST_DTV2000H_J,
        },{
                .subvendor = 0x18ac,
                .subdevice = 0xd800, /* FusionHDTV 3 Gold (original revision) */
@@ -3162,7 +3212,11 @@ static void cx88_card_setup(struct cx88_core *core)
        case  CX88_BOARD_PROF_6200:
        case  CX88_BOARD_PROF_7300:
        case  CX88_BOARD_SATTRADE_ST4200:
+               cx_write(MO_GP0_IO, 0x8000);
+               msleep(100);
                cx_write(MO_SRST_IO, 0);
+               msleep(10);
+               cx_write(MO_GP0_IO, 0x8080);
                msleep(100);
                cx_write(MO_SRST_IO, 1);
                msleep(100);
index e237b507659ba82bc45a03022245118ef41fce2b..6e5d142b5b000f1f0369e38779ce6aef4c258cf1 100644 (file)
@@ -424,17 +424,16 @@ static int tevii_dvbs_set_voltage(struct dvb_frontend *fe,
        struct cx8802_dev *dev= fe->dvb->priv;
        struct cx88_core *core = dev->core;
 
+       cx_set(MO_GP0_IO, 0x6040);
        switch (voltage) {
                case SEC_VOLTAGE_13:
-                       printk("LNB Voltage SEC_VOLTAGE_13\n");
-                       cx_write(MO_GP0_IO, 0x00006040);
+                       cx_clear(MO_GP0_IO, 0x20);
                        break;
                case SEC_VOLTAGE_18:
-                       printk("LNB Voltage SEC_VOLTAGE_18\n");
-                       cx_write(MO_GP0_IO, 0x00006060);
+                       cx_set(MO_GP0_IO, 0x20);
                        break;
                case SEC_VOLTAGE_OFF:
-                       printk("LNB Voltage SEC_VOLTAGE_off\n");
+                       cx_clear(MO_GP0_IO, 0x20);
                        break;
        }
 
@@ -499,9 +498,9 @@ static struct zl10353_config cx88_pinnacle_hybrid_pctv = {
 };
 
 static struct zl10353_config cx88_geniatech_x8000_mt = {
-       .demod_address = (0x1e >> 1),
-       .no_tuner = 1,
-       .disable_i2c_gate_ctrl = 1,
+       .demod_address = (0x1e >> 1),
+       .no_tuner = 1,
+       .disable_i2c_gate_ctrl = 1,
 };
 
 static struct s5h1411_config dvico_fusionhdtv7_config = {
@@ -696,6 +695,7 @@ static int dvb_register(struct cx8802_dev *dev)
                }
                break;
        case CX88_BOARD_WINFAST_DTV2000H:
+       case CX88_BOARD_WINFAST_DTV2000H_J:
        case CX88_BOARD_HAUPPAUGE_HVR1100:
        case CX88_BOARD_HAUPPAUGE_HVR1100LP:
        case CX88_BOARD_HAUPPAUGE_HVR1300:
index d91f5c51206d0cdcacdae124b96ad5eca50de199..78b3635178afe33584256e516211acbf60555a30 100644 (file)
@@ -23,7 +23,7 @@
  */
 
 #include <linux/init.h>
-#include <linux/delay.h>
+#include <linux/hrtimer.h>
 #include <linux/input.h>
 #include <linux/pci.h>
 #include <linux/module.h>
@@ -48,7 +48,7 @@ struct cx88_IR {
 
        /* poll external decoder */
        int polling;
-       struct delayed_work work;
+       struct hrtimer timer;
        u32 gpio_addr;
        u32 last_gpio;
        u32 mask_keycode;
@@ -144,19 +144,28 @@ static void cx88_ir_handle_key(struct cx88_IR *ir)
        }
 }
 
-static void cx88_ir_work(struct work_struct *work)
+static enum hrtimer_restart cx88_ir_work(struct hrtimer *timer)
 {
-       struct cx88_IR *ir = container_of(work, struct cx88_IR, work.work);
+       unsigned long missed;
+       struct cx88_IR *ir = container_of(timer, struct cx88_IR, timer);
 
        cx88_ir_handle_key(ir);
-       schedule_delayed_work(&ir->work, msecs_to_jiffies(ir->polling));
+       missed = hrtimer_forward_now(&ir->timer,
+                                    ktime_set(0, ir->polling * 1000000));
+       if (missed > 1)
+               ir_dprintk("Missed ticks %ld\n", missed - 1);
+
+       return HRTIMER_RESTART;
 }
 
 void cx88_ir_start(struct cx88_core *core, struct cx88_IR *ir)
 {
        if (ir->polling) {
-               INIT_DELAYED_WORK(&ir->work, cx88_ir_work);
-               schedule_delayed_work(&ir->work, 0);
+               hrtimer_init(&ir->timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL);
+               ir->timer.function = cx88_ir_work;
+               hrtimer_start(&ir->timer,
+                             ktime_set(0, ir->polling * 1000000),
+                             HRTIMER_MODE_REL);
        }
        if (ir->sampling) {
                core->pci_irqmask |= PCI_INT_IR_SMPINT;
@@ -173,7 +182,7 @@ void cx88_ir_stop(struct cx88_core *core, struct cx88_IR *ir)
        }
 
        if (ir->polling)
-               cancel_delayed_work_sync(&ir->work);
+               hrtimer_cancel(&ir->timer);
 }
 
 /* ---------------------------------------------------------------------- */
@@ -182,7 +191,7 @@ int cx88_ir_init(struct cx88_core *core, struct pci_dev *pci)
 {
        struct cx88_IR *ir;
        struct input_dev *input_dev;
-       IR_KEYTAB_TYPE *ir_codes = NULL;
+       struct ir_scancode_table *ir_codes = NULL;
        int ir_type = IR_TYPE_OTHER;
        int err = -ENOMEM;
 
@@ -198,14 +207,14 @@ int cx88_ir_init(struct cx88_core *core, struct pci_dev *pci)
        case CX88_BOARD_DNTV_LIVE_DVB_T:
        case CX88_BOARD_KWORLD_DVB_T:
        case CX88_BOARD_KWORLD_DVB_T_CX22702:
-               ir_codes = ir_codes_dntv_live_dvb_t;
+               ir_codes = &ir_codes_dntv_live_dvb_t_table;
                ir->gpio_addr = MO_GP1_IO;
                ir->mask_keycode = 0x1f;
                ir->mask_keyup = 0x60;
                ir->polling = 50; /* ms */
                break;
        case CX88_BOARD_TERRATEC_CINERGY_1400_DVB_T1:
-               ir_codes = ir_codes_cinergy_1400;
+               ir_codes = &ir_codes_cinergy_1400_table;
                ir_type = IR_TYPE_PD;
                ir->sampling = 0xeb04; /* address */
                break;
@@ -220,13 +229,14 @@ int cx88_ir_init(struct cx88_core *core, struct pci_dev *pci)
        case CX88_BOARD_PCHDTV_HD3000:
        case CX88_BOARD_PCHDTV_HD5500:
        case CX88_BOARD_HAUPPAUGE_IRONLY:
-               ir_codes = ir_codes_hauppauge_new;
+               ir_codes = &ir_codes_hauppauge_new_table;
                ir_type = IR_TYPE_RC5;
                ir->sampling = 1;
                break;
        case CX88_BOARD_WINFAST_DTV2000H:
+       case CX88_BOARD_WINFAST_DTV2000H_J:
        case CX88_BOARD_WINFAST_DTV1800H:
-               ir_codes = ir_codes_winfast;
+               ir_codes = &ir_codes_winfast_table;
                ir->gpio_addr = MO_GP0_IO;
                ir->mask_keycode = 0x8f8;
                ir->mask_keyup = 0x100;
@@ -235,14 +245,14 @@ int cx88_ir_init(struct cx88_core *core, struct pci_dev *pci)
        case CX88_BOARD_WINFAST2000XP_EXPERT:
        case CX88_BOARD_WINFAST_DTV1000:
        case CX88_BOARD_WINFAST_TV2000_XP_GLOBAL:
-               ir_codes = ir_codes_winfast;
+               ir_codes = &ir_codes_winfast_table;
                ir->gpio_addr = MO_GP0_IO;
                ir->mask_keycode = 0x8f8;
                ir->mask_keyup = 0x100;
                ir->polling = 1; /* ms */
                break;
        case CX88_BOARD_IODATA_GVBCTV7E:
-               ir_codes = ir_codes_iodata_bctv7e;
+               ir_codes = &ir_codes_iodata_bctv7e_table;
                ir->gpio_addr = MO_GP0_IO;
                ir->mask_keycode = 0xfd;
                ir->mask_keydown = 0x02;
@@ -250,7 +260,7 @@ int cx88_ir_init(struct cx88_core *core, struct pci_dev *pci)
                break;
        case CX88_BOARD_PROLINK_PLAYTVPVR:
        case CX88_BOARD_PIXELVIEW_PLAYTV_ULTRA_PRO:
-               ir_codes = ir_codes_pixelview;
+               ir_codes = &ir_codes_pixelview_table;
                ir->gpio_addr = MO_GP1_IO;
                ir->mask_keycode = 0x1f;
                ir->mask_keyup = 0x80;
@@ -258,28 +268,28 @@ int cx88_ir_init(struct cx88_core *core, struct pci_dev *pci)
                break;
        case CX88_BOARD_PROLINK_PV_8000GT:
        case CX88_BOARD_PROLINK_PV_GLOBAL_XTREME:
-               ir_codes = ir_codes_pixelview_new;
+               ir_codes = &ir_codes_pixelview_new_table;
                ir->gpio_addr = MO_GP1_IO;
                ir->mask_keycode = 0x3f;
                ir->mask_keyup = 0x80;
                ir->polling = 1; /* ms */
                break;
        case CX88_BOARD_KWORLD_LTV883:
-               ir_codes = ir_codes_pixelview;
+               ir_codes = &ir_codes_pixelview_table;
                ir->gpio_addr = MO_GP1_IO;
                ir->mask_keycode = 0x1f;
                ir->mask_keyup = 0x60;
                ir->polling = 1; /* ms */
                break;
        case CX88_BOARD_ADSTECH_DVB_T_PCI:
-               ir_codes = ir_codes_adstech_dvb_t_pci;
+               ir_codes = &ir_codes_adstech_dvb_t_pci_table;
                ir->gpio_addr = MO_GP1_IO;
                ir->mask_keycode = 0xbf;
                ir->mask_keyup = 0x40;
                ir->polling = 50; /* ms */
                break;
        case CX88_BOARD_MSI_TVANYWHERE_MASTER:
-               ir_codes = ir_codes_msi_tvanywhere;
+               ir_codes = &ir_codes_msi_tvanywhere_table;
                ir->gpio_addr = MO_GP1_IO;
                ir->mask_keycode = 0x1f;
                ir->mask_keyup = 0x40;
@@ -287,40 +297,40 @@ int cx88_ir_init(struct cx88_core *core, struct pci_dev *pci)
                break;
        case CX88_BOARD_AVERTV_303:
        case CX88_BOARD_AVERTV_STUDIO_303:
-               ir_codes         = ir_codes_avertv_303;
+               ir_codes         = &ir_codes_avertv_303_table;
                ir->gpio_addr    = MO_GP2_IO;
                ir->mask_keycode = 0xfb;
                ir->mask_keydown = 0x02;
                ir->polling      = 50; /* ms */
                break;
        case CX88_BOARD_DNTV_LIVE_DVB_T_PRO:
-               ir_codes = ir_codes_dntv_live_dvbt_pro;
-               ir_type = IR_TYPE_PD;
-               ir->sampling = 0xff00; /* address */
+               ir_codes         = &ir_codes_dntv_live_dvbt_pro_table;
+               ir_type          = IR_TYPE_PD;
+               ir->sampling     = 0xff00; /* address */
                break;
        case CX88_BOARD_NORWOOD_MICRO:
-               ir_codes         = ir_codes_norwood;
+               ir_codes         = &ir_codes_norwood_table;
                ir->gpio_addr    = MO_GP1_IO;
                ir->mask_keycode = 0x0e;
                ir->mask_keyup   = 0x80;
                ir->polling      = 50; /* ms */
                break;
        case CX88_BOARD_NPGTECH_REALTV_TOP10FM:
-               ir_codes = ir_codes_npgtech;
-               ir->gpio_addr = MO_GP0_IO;
+               ir_codes         = &ir_codes_npgtech_table;
+               ir->gpio_addr    = MO_GP0_IO;
                ir->mask_keycode = 0xfa;
-               ir->polling = 50; /* ms */
+               ir->polling      = 50; /* ms */
                break;
        case CX88_BOARD_PINNACLE_PCTV_HD_800i:
-               ir_codes = ir_codes_pinnacle_pctv_hd;
-               ir_type = IR_TYPE_RC5;
-               ir->sampling = 1;
+               ir_codes         = &ir_codes_pinnacle_pctv_hd_table;
+               ir_type          = IR_TYPE_RC5;
+               ir->sampling     = 1;
                break;
        case CX88_BOARD_POWERCOLOR_REAL_ANGEL:
-               ir_codes = ir_codes_powercolor_real_angel;
-               ir->gpio_addr = MO_GP2_IO;
+               ir_codes         = &ir_codes_powercolor_real_angel_table;
+               ir->gpio_addr    = MO_GP2_IO;
                ir->mask_keycode = 0x7e;
-               ir->polling = 100; /* ms */
+               ir->polling      = 100; /* ms */
                break;
        }
 
index 9d83762163f5fe8f2c0b307dc1e0bd99fcadcc14..d5cea41f42078dd67c3f72b5c8601979f8b38b6d 100644 (file)
@@ -237,6 +237,7 @@ extern struct sram_channel cx88_sram_channels[];
 #define CX88_BOARD_TERRATEC_CINERGY_HT_PCI_MKII 79
 #define CX88_BOARD_HAUPPAUGE_IRONLY        80
 #define CX88_BOARD_WINFAST_DTV1800H        81
+#define CX88_BOARD_WINFAST_DTV2000H_J      82
 
 enum cx88_itype {
        CX88_VMUX_COMPOSITE1 = 1,
index 1c2e544eda73594cb362e1afbea1451b4ae94927..7e3c78239fa9bbd92839e82082eefb611d7f28d8 100644 (file)
@@ -299,6 +299,7 @@ struct em28xx_board em28xx_boards[] = {
        [EM2820_BOARD_TERRATEC_CINERGY_250] = {
                .name         = "Terratec Cinergy 250 USB",
                .tuner_type   = TUNER_LG_PAL_NEW_TAPC,
+               .has_ir_i2c   = 1,
                .tda9887_conf = TDA9887_PRESENT,
                .decoder      = EM28XX_SAA711X,
                .input        = { {
@@ -318,6 +319,7 @@ struct em28xx_board em28xx_boards[] = {
        [EM2820_BOARD_PINNACLE_USB_2] = {
                .name         = "Pinnacle PCTV USB 2",
                .tuner_type   = TUNER_LG_PAL_NEW_TAPC,
+               .has_ir_i2c   = 1,
                .tda9887_conf = TDA9887_PRESENT,
                .decoder      = EM28XX_SAA711X,
                .input        = { {
@@ -342,6 +344,7 @@ struct em28xx_board em28xx_boards[] = {
                                TDA9887_PORT2_ACTIVE,
                .decoder      = EM28XX_TVP5150,
                .has_msp34xx  = 1,
+               .has_ir_i2c   = 1,
                .input        = { {
                        .type     = EM28XX_VMUX_TELEVISION,
                        .vmux     = TVP5150_COMPOSITE0,
@@ -558,6 +561,27 @@ struct em28xx_board em28xx_boards[] = {
                        .amux     = EM28XX_AMUX_LINE_IN,
                } },
        },
+       [EM2861_BOARD_GADMEI_UTV330PLUS] = {
+               .name         = "Gadmei UTV330+",
+               .tuner_type   = TUNER_TNF_5335MF,
+               .tda9887_conf = TDA9887_PRESENT,
+               .ir_codes     = &ir_codes_gadmei_rm008z_table,
+               .decoder      = EM28XX_SAA711X,
+               .xclk         = EM28XX_XCLK_FREQUENCY_12MHZ,
+               .input        = { {
+                       .type     = EM28XX_VMUX_TELEVISION,
+                       .vmux     = SAA7115_COMPOSITE2,
+                       .amux     = EM28XX_AMUX_VIDEO,
+               }, {
+                       .type     = EM28XX_VMUX_COMPOSITE1,
+                       .vmux     = SAA7115_COMPOSITE0,
+                       .amux     = EM28XX_AMUX_LINE_IN,
+               }, {
+                       .type     = EM28XX_VMUX_SVIDEO,
+                       .vmux     = SAA7115_SVIDEO3,
+                       .amux     = EM28XX_AMUX_LINE_IN,
+               } },
+       },
        [EM2860_BOARD_TERRATEC_HYBRID_XS] = {
                .name         = "Terratec Cinergy A Hybrid XS",
                .valid        = EM28XX_BOARD_NOT_VALIDATED,
@@ -715,7 +739,7 @@ struct em28xx_board em28xx_boards[] = {
                .mts_firmware = 1,
                .has_dvb      = 1,
                .dvb_gpio     = hauppauge_wintv_hvr_900_digital,
-               .ir_codes     = ir_codes_hauppauge_new,
+               .ir_codes     = &ir_codes_hauppauge_new_table,
                .decoder      = EM28XX_TVP5150,
                .input        = { {
                        .type     = EM28XX_VMUX_TELEVISION,
@@ -740,7 +764,7 @@ struct em28xx_board em28xx_boards[] = {
                .tuner_type   = TUNER_XC2028,
                .tuner_gpio   = default_tuner_gpio,
                .mts_firmware = 1,
-               .ir_codes     = ir_codes_hauppauge_new,
+               .ir_codes     = &ir_codes_hauppauge_new_table,
                .decoder      = EM28XX_TVP5150,
                .input        = { {
                        .type     = EM28XX_VMUX_TELEVISION,
@@ -766,7 +790,7 @@ struct em28xx_board em28xx_boards[] = {
                .mts_firmware   = 1,
                .has_dvb        = 1,
                .dvb_gpio       = hauppauge_wintv_hvr_900_digital,
-               .ir_codes       = ir_codes_hauppauge_new,
+               .ir_codes       = &ir_codes_hauppauge_new_table,
                .decoder        = EM28XX_TVP5150,
                .input          = { {
                        .type     = EM28XX_VMUX_TELEVISION,
@@ -792,7 +816,7 @@ struct em28xx_board em28xx_boards[] = {
                .mts_firmware   = 1,
                .has_dvb        = 1,
                .dvb_gpio       = hauppauge_wintv_hvr_900_digital,
-               .ir_codes       = ir_codes_hauppauge_new,
+               .ir_codes       = &ir_codes_hauppauge_new_table,
                .decoder        = EM28XX_TVP5150,
                .input          = { {
                        .type     = EM28XX_VMUX_TELEVISION,
@@ -818,7 +842,7 @@ struct em28xx_board em28xx_boards[] = {
                .mts_firmware   = 1,
                .has_dvb        = 1,
                .dvb_gpio       = hauppauge_wintv_hvr_900_digital,
-               .ir_codes       = ir_codes_pinnacle_pctv_hd,
+               .ir_codes       = &ir_codes_pinnacle_pctv_hd_table,
                .decoder        = EM28XX_TVP5150,
                .input          = { {
                        .type     = EM28XX_VMUX_TELEVISION,
@@ -844,7 +868,7 @@ struct em28xx_board em28xx_boards[] = {
                .mts_firmware   = 1,
                .has_dvb        = 1,
                .dvb_gpio       = hauppauge_wintv_hvr_900_digital,
-               .ir_codes       = ir_codes_ati_tv_wonder_hd_600,
+               .ir_codes       = &ir_codes_ati_tv_wonder_hd_600_table,
                .decoder        = EM28XX_TVP5150,
                .input          = { {
                        .type     = EM28XX_VMUX_TELEVISION,
@@ -870,6 +894,8 @@ struct em28xx_board em28xx_boards[] = {
                .decoder        = EM28XX_TVP5150,
                .has_dvb        = 1,
                .dvb_gpio       = default_digital,
+               .ir_codes       = &ir_codes_terratec_cinergy_xs_table,
+               .xclk           = EM28XX_XCLK_FREQUENCY_12MHZ, /* NEC IR */
                .input          = { {
                        .type     = EM28XX_VMUX_TELEVISION,
                        .vmux     = TVP5150_COMPOSITE0,
@@ -937,6 +963,7 @@ struct em28xx_board em28xx_boards[] = {
        [EM2800_BOARD_TERRATEC_CINERGY_200] = {
                .name         = "Terratec Cinergy 200 USB",
                .is_em2800    = 1,
+               .has_ir_i2c   = 1,
                .tuner_type   = TUNER_LG_PAL_NEW_TAPC,
                .tda9887_conf = TDA9887_PRESENT,
                .decoder      = EM28XX_SAA711X,
@@ -1010,7 +1037,8 @@ struct em28xx_board em28xx_boards[] = {
                } },
        },
        [EM2820_BOARD_PINNACLE_DVC_90] = {
-               .name         = "Pinnacle Dazzle DVC 90/100/101/107 / Kaiser Baas Video to DVD maker",
+               .name         = "Pinnacle Dazzle DVC 90/100/101/107 / Kaiser Baas Video to DVD maker "
+                               "/ Kworld DVD Maker 2",
                .tuner_type   = TUNER_ABSENT, /* capture only board */
                .decoder      = EM28XX_SAA711X,
                .input        = { {
@@ -1420,7 +1448,7 @@ struct em28xx_board em28xx_boards[] = {
                .mts_firmware = 1,
                .decoder      = EM28XX_TVP5150,
                .tuner_gpio   = default_tuner_gpio,
-               .ir_codes     = ir_codes_kaiomy,
+               .ir_codes     = &ir_codes_kaiomy_table,
                .input          = { {
                        .type     = EM28XX_VMUX_TELEVISION,
                        .vmux     = TVP5150_COMPOSITE0,
@@ -1520,7 +1548,7 @@ struct em28xx_board em28xx_boards[] = {
                .mts_firmware = 1,
                .has_dvb      = 1,
                .dvb_gpio     = evga_indtube_digital,
-               .ir_codes     = ir_codes_evga_indtube,
+               .ir_codes     = &ir_codes_evga_indtube_table,
                .input        = { {
                        .type     = EM28XX_VMUX_TELEVISION,
                        .vmux     = TVP5150_COMPOSITE0,
@@ -1591,6 +1619,8 @@ struct usb_device_id em28xx_id_table[] = {
                        .driver_info = EM2870_BOARD_KWORLD_355U },
        { USB_DEVICE(0x1b80, 0xe302),
                        .driver_info = EM2820_BOARD_PINNACLE_DVC_90 }, /* Kaiser Baas Video to DVD maker */
+       { USB_DEVICE(0x1b80, 0xe304),
+                       .driver_info = EM2820_BOARD_PINNACLE_DVC_90 }, /* Kworld DVD Maker 2 */
        { USB_DEVICE(0x0ccd, 0x0036),
                        .driver_info = EM2820_BOARD_TERRATEC_CINERGY_250 },
        { USB_DEVICE(0x0ccd, 0x004c),
@@ -1649,6 +1679,8 @@ struct usb_device_id em28xx_id_table[] = {
                        .driver_info = EM2861_BOARD_PLEXTOR_PX_TV100U },
        { USB_DEVICE(0x04bb, 0x0515),
                        .driver_info = EM2820_BOARD_IODATA_GVMVP_SZ },
+       { USB_DEVICE(0xeb1a, 0x50a6),
+                       .driver_info = EM2860_BOARD_GADMEI_UTV330 },
        { },
 };
 MODULE_DEVICE_TABLE(usb, em28xx_id_table);
@@ -1661,7 +1693,7 @@ static struct em28xx_hash_table em28xx_eeprom_hash[] = {
        {0x6ce05a8f, EM2820_BOARD_PROLINK_PLAYTV_USB2, TUNER_YMEC_TVF_5533MF},
        {0x72cc5a8b, EM2820_BOARD_PROLINK_PLAYTV_BOX4_USB2, TUNER_YMEC_TVF_5533MF},
        {0x966a0441, EM2880_BOARD_KWORLD_DVB_310U, TUNER_XC2028},
-       {0x9567eb1a, EM2880_BOARD_EMPIRE_DUAL_TV, TUNER_XC2028},
+       {0x166a0441, EM2880_BOARD_EMPIRE_DUAL_TV, TUNER_XC2028},
        {0xcee44a99, EM2882_BOARD_EVGA_INDTUBE, TUNER_XC2028},
        {0xb8846b20, EM2881_BOARD_PINNACLE_HYBRID_PRO, TUNER_XC2028},
 };
@@ -1672,6 +1704,7 @@ static struct em28xx_hash_table em28xx_i2c_hash[] = {
        {0xf51200e3, EM2800_BOARD_VGEAR_POCKETTV, TUNER_LG_PAL_NEW_TAPC},
        {0x1ba50080, EM2860_BOARD_SAA711X_REFERENCE_DESIGN, TUNER_ABSENT},
        {0xc51200e3, EM2820_BOARD_GADMEI_TVR200, TUNER_LG_PAL_NEW_TAPC},
+       {0x4ba50080, EM2861_BOARD_GADMEI_UTV330PLUS, TUNER_TNF_5335MF},
 };
 
 /* I2C possible address to saa7115, tvp5150, msp3400, tvaudio */
@@ -2170,8 +2203,6 @@ static int em28xx_hint_board(struct em28xx *dev)
 /* ----------------------------------------------------------------------- */
 void em28xx_register_i2c_ir(struct em28xx *dev)
 {
-       struct i2c_board_info info;
-       struct IR_i2c_init_data init_data;
        const unsigned short addr_list[] = {
                 0x30, 0x47, I2C_CLIENT_END
        };
@@ -2179,45 +2210,33 @@ void em28xx_register_i2c_ir(struct em28xx *dev)
        if (disable_ir)
                return;
 
-       memset(&info, 0, sizeof(struct i2c_board_info));
-       memset(&init_data, 0, sizeof(struct IR_i2c_init_data));
-       strlcpy(info.type, "ir_video", I2C_NAME_SIZE);
+       memset(&dev->info, 0, sizeof(&dev->info));
+       memset(&dev->init_data, 0, sizeof(dev->init_data));
+       strlcpy(dev->info.type, "ir_video", I2C_NAME_SIZE);
 
        /* 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):
-               init_data.ir_codes = ir_codes_em_terratec;
-               init_data.get_key = em28xx_get_key_terratec;
-               init_data.name = "i2c IR (EM28XX Terratec)";
-               break;
-       case (EM2820_BOARD_PINNACLE_USB_2):
-               init_data.ir_codes = ir_codes_pinnacle_grey;
-               init_data.get_key = em28xx_get_key_pinnacle_usb_grey;
-               init_data.name = "i2c IR (EM28XX Pinnacle PCTV)";
-               break;
-       case (EM2820_BOARD_HAUPPAUGE_WINTV_USB_2):
-               init_data.ir_codes = ir_codes_hauppauge_new;
-               init_data.get_key = em28xx_get_key_em_haup;
-               init_data.name = "i2c IR (EM2840 Hauppauge)";
+       case EM2800_BOARD_TERRATEC_CINERGY_200:
+       case EM2820_BOARD_TERRATEC_CINERGY_250:
+               dev->init_data.ir_codes = &ir_codes_em_terratec_table;
+               dev->init_data.get_key = em28xx_get_key_terratec;
+               dev->init_data.name = "i2c IR (EM28XX Terratec)";
                break;
-       case (EM2820_BOARD_MSI_VOX_USB_2):
+       case EM2820_BOARD_PINNACLE_USB_2:
+               dev->init_data.ir_codes = &ir_codes_pinnacle_grey_table;
+               dev->init_data.get_key = em28xx_get_key_pinnacle_usb_grey;
+               dev->init_data.name = "i2c IR (EM28XX Pinnacle PCTV)";
                break;
-       case (EM2800_BOARD_LEADTEK_WINFAST_USBII):
-               break;
-       case (EM2800_BOARD_KWORLD_USB2800):
-               break;
-       case (EM2800_BOARD_GRABBEEX_USB2800):
+       case EM2820_BOARD_HAUPPAUGE_WINTV_USB_2:
+               dev->init_data.ir_codes = &ir_codes_hauppauge_new_table;
+               dev->init_data.get_key = em28xx_get_key_em_haup;
+               dev->init_data.name = "i2c IR (EM2840 Hauppauge)";
                break;
        }
 
-       if (init_data.name)
-               info.platform_data = &init_data;
-       i2c_new_probed_device(&dev->i2c_adap, &info, addr_list);
+       if (dev->init_data.name)
+               dev->info.platform_data = &dev->init_data;
+       i2c_new_probed_device(&dev->i2c_adap, &dev->info, addr_list);
 }
 
 void em28xx_card_setup(struct em28xx *dev)
@@ -2253,7 +2272,7 @@ void em28xx_card_setup(struct em28xx *dev)
        case EM2883_BOARD_HAUPPAUGE_WINTV_HVR_950:
        {
                struct tveeprom tv;
-#ifdef CONFIG_MODULES
+#if defined(CONFIG_MODULES) && defined(MODULE)
                request_module("tveeprom");
 #endif
                /* Call first TVeeprom */
@@ -2267,10 +2286,6 @@ void em28xx_card_setup(struct em28xx *dev)
                        dev->i2s_speed = 2048000;
                        dev->board.has_msp34xx = 1;
                }
-#ifdef CONFIG_MODULES
-               if (tv.has_ir)
-                       request_module("ir-kbd-i2c");
-#endif
                break;
        }
        case EM2882_BOARD_KWORLD_ATSC_315U:
@@ -2311,6 +2326,10 @@ void em28xx_card_setup(struct em28xx *dev)
                break;
        }
 
+#if defined(CONFIG_MODULES) && defined(MODULE)
+       if (dev->board.has_ir_i2c && !disable_ir)
+               request_module("ir-kbd-i2c");
+#endif
        if (dev->board.has_snapshot_button)
                em28xx_register_snapshot_button(dev);
 
index 27e33a287dfc8a53da271359aef3c08ac5283517..71474d31e155a8ed311c187cc60ff9cd32a36f75 100644 (file)
@@ -459,7 +459,6 @@ static struct i2c_algorithm em28xx_algo = {
 static struct i2c_adapter em28xx_adap_template = {
        .owner = THIS_MODULE,
        .name = "em28xx",
-       .id = I2C_HW_B_EM28XX,
        .algo = &em28xx_algo,
 };
 
index ab079d9256c463a0c9889841ed3e0946969f1929..a6bdbc21410e7764cc67eee1cd0543079f8c5b36 100644 (file)
@@ -124,7 +124,7 @@ static struct em28xx_fmt format[] = {
 
 /* supported controls */
 /* Common to all boards */
-static struct v4l2_queryctrl em28xx_qctrl[] = {
+static struct v4l2_queryctrl ac97_qctrl[] = {
        {
                .id = V4L2_CID_AUDIO_VOLUME,
                .type = V4L2_CTRL_TYPE_INTEGER,
@@ -133,7 +133,7 @@ static struct v4l2_queryctrl em28xx_qctrl[] = {
                .maximum = 0x1f,
                .step = 0x1,
                .default_value = 0x1f,
-               .flags = 0,
+               .flags = V4L2_CTRL_FLAG_SLIDER,
        }, {
                .id = V4L2_CID_AUDIO_MUTE,
                .type = V4L2_CTRL_TYPE_BOOLEAN,
@@ -609,10 +609,29 @@ static void res_free(struct em28xx_fh *fh)
 }
 
 /*
- * em28xx_get_ctrl()
- * return the current saturation, brightness or contrast, mute state
+ * ac97_queryctrl()
+ * return the ac97 supported controls
  */
-static int em28xx_get_ctrl(struct em28xx *dev, struct v4l2_control *ctrl)
+static int ac97_queryctrl(struct v4l2_queryctrl *qc)
+{
+       int i;
+
+       for (i = 0; i < ARRAY_SIZE(ac97_qctrl); i++) {
+               if (qc->id && qc->id == ac97_qctrl[i].id) {
+                       memcpy(qc, &(ac97_qctrl[i]), sizeof(*qc));
+                       return 0;
+               }
+       }
+
+       /* Control is not ac97 related */
+       return 1;
+}
+
+/*
+ * ac97_get_ctrl()
+ * return the current values for ac97 mute and volume
+ */
+static int ac97_get_ctrl(struct em28xx *dev, struct v4l2_control *ctrl)
 {
        switch (ctrl->id) {
        case V4L2_CID_AUDIO_MUTE:
@@ -622,29 +641,41 @@ static int em28xx_get_ctrl(struct em28xx *dev, struct v4l2_control *ctrl)
                ctrl->value = dev->volume;
                return 0;
        default:
-               return -EINVAL;
+               /* Control is not ac97 related */
+               return 1;
        }
 }
 
 /*
- * em28xx_set_ctrl()
- * mute or set new saturation, brightness or contrast
+ * ac97_set_ctrl()
+ * set values for ac97 mute and volume
  */
-static int em28xx_set_ctrl(struct em28xx *dev, const struct v4l2_control *ctrl)
+static int ac97_set_ctrl(struct em28xx *dev, const struct v4l2_control *ctrl)
 {
+       int i;
+
+       for (i = 0; i < ARRAY_SIZE(ac97_qctrl); i++)
+               if (ctrl->id == ac97_qctrl[i].id)
+                       goto handle;
+
+       /* Announce that hasn't handle it */
+       return 1;
+
+handle:
+       if (ctrl->value < ac97_qctrl[i].minimum ||
+           ctrl->value > ac97_qctrl[i].maximum)
+               return -ERANGE;
+
        switch (ctrl->id) {
        case V4L2_CID_AUDIO_MUTE:
-               if (ctrl->value != dev->mute) {
-                       dev->mute = ctrl->value;
-                       return em28xx_audio_analog_set(dev);
-               }
-               return 0;
+               dev->mute = ctrl->value;
+               break;
        case V4L2_CID_AUDIO_VOLUME:
                dev->volume = ctrl->value;
-               return em28xx_audio_analog_set(dev);
-       default:
-               return -EINVAL;
+               break;
        }
+
+       return em28xx_audio_analog_set(dev);
 }
 
 static int check_dev(struct em28xx *dev)
@@ -974,6 +1005,9 @@ static int vidioc_g_audio(struct file *file, void *priv, struct v4l2_audio *a)
        struct em28xx_fh   *fh    = priv;
        struct em28xx      *dev   = fh->dev;
 
+       if (!dev->audio_mode.has_audio)
+               return -EINVAL;
+
        switch (a->index) {
        case EM28XX_AMUX_VIDEO:
                strcpy(a->name, "Television");
@@ -1015,6 +1049,9 @@ static int vidioc_s_audio(struct file *file, void *priv, struct v4l2_audio *a)
        struct em28xx      *dev = fh->dev;
 
 
+       if (!dev->audio_mode.has_audio)
+               return -EINVAL;
+
        if (a->index >= MAX_EM28XX_INPUT)
                return -EINVAL;
        if (0 == INPUT(a->index)->type)
@@ -1038,7 +1075,6 @@ static int vidioc_queryctrl(struct file *file, void *priv,
        struct em28xx_fh      *fh  = priv;
        struct em28xx         *dev = fh->dev;
        int                   id  = qc->id;
-       int                   i;
        int                   rc;
 
        rc = check_dev(dev);
@@ -1049,15 +1085,14 @@ static int vidioc_queryctrl(struct file *file, void *priv,
 
        qc->id = id;
 
-       if (!dev->board.has_msp34xx) {
-               for (i = 0; i < ARRAY_SIZE(em28xx_qctrl); i++) {
-                       if (qc->id && qc->id == em28xx_qctrl[i].id) {
-                               memcpy(qc, &(em28xx_qctrl[i]), sizeof(*qc));
-                               return 0;
-                       }
-               }
+       /* enumberate AC97 controls */
+       if (dev->audio_mode.ac97 != EM28XX_NO_AC97) {
+               rc = ac97_queryctrl(qc);
+               if (!rc)
+                       return 0;
        }
 
+       /* enumberate V4L2 device controls */
        mutex_lock(&dev->lock);
        v4l2_device_call_all(&dev->v4l2_dev, 0, core, queryctrl, qc);
        mutex_unlock(&dev->lock);
@@ -1082,14 +1117,16 @@ static int vidioc_g_ctrl(struct file *file, void *priv,
 
        mutex_lock(&dev->lock);
 
-       if (dev->board.has_msp34xx)
+       /* Set an AC97 control */
+       if (dev->audio_mode.ac97 != EM28XX_NO_AC97)
+               rc = ac97_get_ctrl(dev, ctrl);
+       else
+               rc = 1;
+
+       /* It were not an AC97 control. Sends it to the v4l2 dev interface */
+       if (rc == 1) {
                v4l2_device_call_all(&dev->v4l2_dev, 0, core, g_ctrl, ctrl);
-       else {
-               rc = em28xx_get_ctrl(dev, ctrl);
-               if (rc < 0) {
-                       v4l2_device_call_all(&dev->v4l2_dev, 0, core, g_ctrl, ctrl);
-                       rc = 0;
-               }
+               rc = 0;
        }
 
        mutex_unlock(&dev->lock);
@@ -1101,7 +1138,6 @@ static int vidioc_s_ctrl(struct file *file, void *priv,
 {
        struct em28xx_fh      *fh  = priv;
        struct em28xx         *dev = fh->dev;
-       u8                    i;
        int                   rc;
 
        rc = check_dev(dev);
@@ -1110,28 +1146,31 @@ static int vidioc_s_ctrl(struct file *file, void *priv,
 
        mutex_lock(&dev->lock);
 
-       if (dev->board.has_msp34xx)
-               v4l2_device_call_all(&dev->v4l2_dev, 0, core, s_ctrl, ctrl);
-       else {
+       /* Set an AC97 control */
+       if (dev->audio_mode.ac97 != EM28XX_NO_AC97)
+               rc = ac97_set_ctrl(dev, ctrl);
+       else
                rc = 1;
-               for (i = 0; i < ARRAY_SIZE(em28xx_qctrl); i++) {
-                       if (ctrl->id == em28xx_qctrl[i].id) {
-                               if (ctrl->value < em28xx_qctrl[i].minimum ||
-                                   ctrl->value > em28xx_qctrl[i].maximum) {
-                                       rc = -ERANGE;
-                                       break;
-                               }
-
-                               rc = em28xx_set_ctrl(dev, ctrl);
-                               break;
-                       }
-               }
-       }
 
-       /* Control not found - try to send it to the attached devices */
+       /* It isn't an AC97 control. Sends it to the v4l2 dev interface */
        if (rc == 1) {
                v4l2_device_call_all(&dev->v4l2_dev, 0, core, s_ctrl, ctrl);
-               rc = 0;
+
+               /*
+                * In the case of non-AC97 volume controls, we still need
+                * to do some setups at em28xx, in order to mute/unmute
+                * and to adjust audio volume. However, the value ranges
+                * should be checked by the corresponding V4L subdriver.
+                */
+               switch (ctrl->id) {
+               case V4L2_CID_AUDIO_MUTE:
+                       dev->mute = ctrl->value;
+                       rc = em28xx_audio_analog_set(dev);
+                       break;
+               case V4L2_CID_AUDIO_VOLUME:
+                       dev->volume = ctrl->value;
+                       rc = em28xx_audio_analog_set(dev);
+               }
        }
 
        mutex_unlock(&dev->lock);
@@ -1275,8 +1314,9 @@ static int vidioc_g_register(struct file *file, void *priv,
                v4l2_device_call_all(&dev->v4l2_dev, 0, core, g_register, reg);
                return 0;
        case V4L2_CHIP_MATCH_I2C_ADDR:
-               /* Not supported yet */
-               return -EINVAL;
+               /* TODO: is this correct? */
+               v4l2_device_call_all(&dev->v4l2_dev, 0, core, g_register, reg);
+               return 0;
        default:
                if (!v4l2_chip_match_host(&reg->match))
                        return -EINVAL;
@@ -1327,8 +1367,9 @@ static int vidioc_s_register(struct file *file, void *priv,
                v4l2_device_call_all(&dev->v4l2_dev, 0, core, s_register, reg);
                return 0;
        case V4L2_CHIP_MATCH_I2C_ADDR:
-               /* Not supported yet */
-               return -EINVAL;
+               /* TODO: is this correct? */
+               v4l2_device_call_all(&dev->v4l2_dev, 0, core, s_register, reg);
+               return 0;
        default:
                if (!v4l2_chip_match_host(&reg->match))
                        return -EINVAL;
@@ -1431,9 +1472,11 @@ static int vidioc_querycap(struct file *file, void  *priv,
        cap->capabilities =
                        V4L2_CAP_SLICED_VBI_CAPTURE |
                        V4L2_CAP_VIDEO_CAPTURE |
-                       V4L2_CAP_AUDIO |
                        V4L2_CAP_READWRITE | V4L2_CAP_STREAMING;
 
+       if (dev->audio_mode.has_audio)
+               cap->capabilities |= V4L2_CAP_AUDIO;
+
        if (dev->tuner_type != TUNER_ABSENT)
                cap->capabilities |= V4L2_CAP_TUNER;
 
@@ -1654,9 +1697,9 @@ static int radio_queryctrl(struct file *file, void *priv,
                qc->id >= V4L2_CID_LASTP1)
                return -EINVAL;
 
-       for (i = 0; i < ARRAY_SIZE(em28xx_qctrl); i++) {
-               if (qc->id && qc->id == em28xx_qctrl[i].id) {
-                       memcpy(qc, &(em28xx_qctrl[i]), sizeof(*qc));
+       for (i = 0; i < ARRAY_SIZE(ac97_qctrl); i++) {
+               if (qc->id && qc->id == ac97_qctrl[i].id) {
+                       memcpy(qc, &(ac97_qctrl[i]), sizeof(*qc));
                        return 0;
                }
        }
index a2add61f7d59dd4555b48b95b81197f337b85951..0f2ba9a40d1726664498c6616c47bcba7ed1d3ab 100644 (file)
 #define EM2882_BOARD_KWORLD_ATSC_315U            69
 #define EM2882_BOARD_EVGA_INDTUBE                70
 #define EM2820_BOARD_SILVERCREST_WEBCAM           71
+#define EM2861_BOARD_GADMEI_UTV330PLUS           72
 
 /* Limits minimum and default number of buffers */
 #define EM28XX_MIN_BUF 4
@@ -398,6 +399,7 @@ struct em28xx_board {
        unsigned int has_snapshot_button:1;
        unsigned int is_webcam:1;
        unsigned int valid:1;
+       unsigned int has_ir_i2c:1;
 
        unsigned char xclk, i2c_speed;
        unsigned char radio_addr;
@@ -408,7 +410,7 @@ struct em28xx_board {
 
        struct em28xx_input       input[MAX_EM28XX_INPUT];
        struct em28xx_input       radio;
-       IR_KEYTAB_TYPE            *ir_codes;
+       struct ir_scancode_table  *ir_codes;
 };
 
 struct em28xx_eeprom {
@@ -595,6 +597,10 @@ struct em28xx {
        struct delayed_work sbutton_query_work;
 
        struct em28xx_dvb *dvb;
+
+       /* I2C keyboard data */
+       struct i2c_board_info info;
+       struct IR_i2c_init_data init_data;
 };
 
 struct em28xx_ops {
index e994dcac43ffb6cfa2481ed4ff9df7aa86235a4b..8897283b0bb4fdd1c4ad82581c315443e1fcc233 100644 (file)
@@ -47,6 +47,15 @@ config USB_GSPCA_FINEPIX
          To compile this driver as a module, choose M here: the
          module will be called gspca_finepix.
 
+config USB_GSPCA_JEILINJ
+       tristate "Jeilin JPEG USB V4L2 driver"
+       depends on VIDEO_V4L2 && USB_GSPCA
+       help
+         Say Y here if you want support for cameras based on this Jeilin chip.
+
+         To compile this driver as a module, choose M here: the
+         module will be called gspca_jeilinj.
+
 config USB_GSPCA_MARS
        tristate "Mars USB Camera Driver"
        depends on VIDEO_V4L2 && USB_GSPCA
@@ -103,9 +112,9 @@ config USB_GSPCA_PAC7311
          module will be called gspca_pac7311.
 
 config USB_GSPCA_SN9C20X
-       tristate "SN9C20X USB Camera Driver"
-       depends on VIDEO_V4L2 && USB_GSPCA
-       help
+       tristate "SN9C20X USB Camera Driver"
+       depends on VIDEO_V4L2 && USB_GSPCA
+       help
         Say Y here if you want support for cameras based on the
         sn9c20x chips (SN9C201 and SN9C202).
 
@@ -113,10 +122,10 @@ config USB_GSPCA_SN9C20X
         module will be called gspca_sn9c20x.
 
 config USB_GSPCA_SN9C20X_EVDEV
-       bool "Enable evdev support"
+       bool "Enable evdev support"
        depends on USB_GSPCA_SN9C20X && INPUT
-       ---help---
-        Say Y here in order to enable evdev support for sn9c20x webcam button.
+       ---help---
+         Say Y here in order to enable evdev support for sn9c20x webcam button.
 
 config USB_GSPCA_SONIXB
        tristate "SONIX Bayer USB Camera Driver"
index f6d3b86e9ad566952840305362b61f5ca1781997..035616b5e867be3d45f1f7793007aa674bf88f32 100644 (file)
@@ -2,6 +2,7 @@ obj-$(CONFIG_USB_GSPCA)          += gspca_main.o
 obj-$(CONFIG_USB_GSPCA_CONEX)    += gspca_conex.o
 obj-$(CONFIG_USB_GSPCA_ETOMS)    += gspca_etoms.o
 obj-$(CONFIG_USB_GSPCA_FINEPIX)  += gspca_finepix.o
+obj-$(CONFIG_USB_GSPCA_JEILINJ)  += gspca_jeilinj.o
 obj-$(CONFIG_USB_GSPCA_MARS)     += gspca_mars.o
 obj-$(CONFIG_USB_GSPCA_MR97310A) += gspca_mr97310a.o
 obj-$(CONFIG_USB_GSPCA_OV519)    += gspca_ov519.o
@@ -30,6 +31,7 @@ gspca_main-objs     := gspca.o
 gspca_conex-objs    := conex.o
 gspca_etoms-objs    := etoms.o
 gspca_finepix-objs  := finepix.o
+gspca_jeilinj-objs  := jeilinj.o
 gspca_mars-objs     := mars.o
 gspca_mr97310a-objs := mr97310a.o
 gspca_ov519-objs    := ov519.o
index 8d48ea1742c2f7ac808c6b9033d7eba69366ffaa..eca003566ae3c9b586799c17a673a35b906e6e43 100644 (file)
@@ -820,7 +820,7 @@ static int sd_config(struct gspca_dev *gspca_dev,
 
        cam = &gspca_dev->cam;
        cam->cam_mode = vga_mode;
-       cam->nmodes = sizeof vga_mode / sizeof vga_mode[0];
+       cam->nmodes = ARRAY_SIZE(vga_mode);
 
        sd->brightness = BRIGHTNESS_DEF;
        sd->contrast = CONTRAST_DEF;
index 2c20d06a03e8b7b009e0588cb20fe41d5e1e01c7..c1461e63647f26fc698be301f49039966e840925 100644 (file)
@@ -635,10 +635,10 @@ static int sd_config(struct gspca_dev *gspca_dev,
        sd->sensor = id->driver_info;
        if (sd->sensor == SENSOR_PAS106) {
                cam->cam_mode = sif_mode;
-               cam->nmodes = sizeof sif_mode / sizeof sif_mode[0];
+               cam->nmodes = ARRAY_SIZE(sif_mode);
        } else {
                cam->cam_mode = vga_mode;
-               cam->nmodes = sizeof vga_mode / sizeof vga_mode[0];
+               cam->nmodes = ARRAY_SIZE(vga_mode);
                gspca_dev->ctrl_dis = (1 << COLOR_IDX);
        }
        sd->brightness = BRIGHTNESS_DEF;
index b8561dfb6c8c7bc08880a9057239f6854c582a5f..cf6540da1e429ac0e9856ba9b3785c556e2197d8 100644 (file)
@@ -47,7 +47,7 @@ MODULE_AUTHOR("Jean-Francois Moine <http://moinejf.free.fr>");
 MODULE_DESCRIPTION("GSPCA USB Camera Driver");
 MODULE_LICENSE("GPL");
 
-#define DRIVER_VERSION_NUMBER  KERNEL_VERSION(2, 6, 0)
+#define DRIVER_VERSION_NUMBER  KERNEL_VERSION(2, 7, 0)
 
 #ifdef GSPCA_DEBUG
 int gspca_debug = D_ERR | D_PROBE;
@@ -486,6 +486,7 @@ static struct usb_host_endpoint *get_ep(struct gspca_dev *gspca_dev)
        }
        PDEBUG(D_STREAM, "use alt %d ep 0x%02x",
                        i, ep->desc.bEndpointAddress);
+       gspca_dev->alt = i;             /* memorize the current alt setting */
        if (gspca_dev->nbalt > 1) {
                ret = usb_set_interface(gspca_dev->dev, gspca_dev->iface, i);
                if (ret < 0) {
@@ -493,7 +494,6 @@ static struct usb_host_endpoint *get_ep(struct gspca_dev *gspca_dev)
                        return NULL;
                }
        }
-       gspca_dev->alt = i;             /* memorize the current alt setting */
        return ep;
 }
 
@@ -512,7 +512,10 @@ static int create_urbs(struct gspca_dev *gspca_dev,
        if (!gspca_dev->cam.bulk) {             /* isoc */
 
                /* See paragraph 5.9 / table 5-11 of the usb 2.0 spec. */
-               psize = (psize & 0x07ff) * (1 + ((psize >> 11) & 3));
+               if (gspca_dev->pkt_size == 0)
+                       psize = (psize & 0x07ff) * (1 + ((psize >> 11) & 3));
+               else
+                       psize = gspca_dev->pkt_size;
                npkt = gspca_dev->cam.npkt;
                if (npkt == 0)
                        npkt = 32;              /* default value */
@@ -597,13 +600,18 @@ static int gspca_init_transfer(struct gspca_dev *gspca_dev)
        /* set the higher alternate setting and
         * loop until urb submit succeeds */
        gspca_dev->alt = gspca_dev->nbalt;
+       if (gspca_dev->sd_desc->isoc_init) {
+               ret = gspca_dev->sd_desc->isoc_init(gspca_dev);
+               if (ret < 0)
+                       goto out;
+       }
+       ep = get_ep(gspca_dev);
+       if (ep == NULL) {
+               ret = -EIO;
+               goto out;
+       }
        for (;;) {
                PDEBUG(D_STREAM, "init transfer alt %d", gspca_dev->alt);
-               ep = get_ep(gspca_dev);
-               if (ep == NULL) {
-                       ret = -EIO;
-                       goto out;
-               }
                ret = create_urbs(gspca_dev, ep);
                if (ret < 0)
                        goto out;
@@ -628,21 +636,32 @@ static int gspca_init_transfer(struct gspca_dev *gspca_dev)
                /* submit the URBs */
                for (n = 0; n < gspca_dev->nurbs; n++) {
                        ret = usb_submit_urb(gspca_dev->urb[n], GFP_KERNEL);
-                       if (ret < 0) {
-                               PDEBUG(D_ERR|D_STREAM,
-                                       "usb_submit_urb [%d] err %d", n, ret);
-                               gspca_dev->streaming = 0;
-                               destroy_urbs(gspca_dev);
-                               if (ret == -ENOSPC) {
-                                       msleep(20);     /* wait for kill
-                                                        * complete */
-                                       break;  /* try the previous alt */
-                               }
-                               goto out;
-                       }
+                       if (ret < 0)
+                               break;
                }
                if (ret >= 0)
                        break;
+               PDEBUG(D_ERR|D_STREAM,
+                       "usb_submit_urb alt %d err %d", gspca_dev->alt, ret);
+               gspca_dev->streaming = 0;
+               destroy_urbs(gspca_dev);
+               if (ret != -ENOSPC)
+                       goto out;
+
+               /* the bandwidth is not wide enough
+                * negociate or try a lower alternate setting */
+               msleep(20);     /* wait for kill complete */
+               if (gspca_dev->sd_desc->isoc_nego) {
+                       ret = gspca_dev->sd_desc->isoc_nego(gspca_dev);
+                       if (ret < 0)
+                               goto out;
+               } else {
+                       ep = get_ep(gspca_dev);
+                       if (ep == NULL) {
+                               ret = -EIO;
+                               goto out;
+                       }
+               }
        }
 out:
        mutex_unlock(&gspca_dev->usb_lock);
@@ -1473,12 +1492,6 @@ static int vidioc_s_parm(struct file *filp, void *priv,
        return 0;
 }
 
-static int vidioc_s_std(struct file *filp, void *priv,
-                       v4l2_std_id *parm)
-{
-       return 0;
-}
-
 #ifdef CONFIG_VIDEO_V4L1_COMPAT
 static int vidiocgmbuf(struct file *file, void *priv,
                        struct video_mbuf *mbuf)
@@ -1949,7 +1962,6 @@ static const struct v4l2_ioctl_ops dev_ioctl_ops = {
        .vidioc_s_jpegcomp      = vidioc_s_jpegcomp,
        .vidioc_g_parm          = vidioc_g_parm,
        .vidioc_s_parm          = vidioc_s_parm,
-       .vidioc_s_std           = vidioc_s_std,
        .vidioc_enum_framesizes = vidioc_enum_framesizes,
 #ifdef CONFIG_VIDEO_ADV_DEBUG
        .vidioc_g_register      = vidioc_g_register,
index 46c4effdfcd5b03776f6798eaafb58aebe9a78fa..70b1fd830876af2bee2a5c2d6f85c562ab2c1112 100644 (file)
@@ -98,9 +98,11 @@ struct sd_desc {
 /* mandatory operations */
        cam_cf_op config;       /* called on probe */
        cam_op init;            /* called on probe and resume */
-       cam_op start;           /* called on stream on */
+       cam_op start;           /* called on stream on after URBs creation */
        cam_pkt_op pkt_scan;
 /* optional operations */
+       cam_op isoc_init;       /* called on stream on before getting the EP */
+       cam_op isoc_nego;       /* called when URB submit failed with NOSPC */
        cam_v_op stopN;         /* called on stream off - main alt */
        cam_v_op stop0;         /* called on stream off & disconnect - alt 0 */
        cam_v_op dq_callback;   /* called when a frame has been dequeued */
@@ -178,6 +180,7 @@ struct gspca_dev {
        __u8 iface;                     /* USB interface number */
        __u8 alt;                       /* USB alternate setting */
        __u8 nbalt;                     /* number of USB alternate settings */
+       u16 pkt_size;                   /* ISOC packet size */
 };
 
 int gspca_dev_probe(struct usb_interface *intf,
diff --git a/drivers/media/video/gspca/jeilinj.c b/drivers/media/video/gspca/jeilinj.c
new file mode 100644 (file)
index 0000000..dbfa3ed
--- /dev/null
@@ -0,0 +1,388 @@
+/*
+ * Jeilinj subdriver
+ *
+ * Supports some Jeilin dual-mode cameras which use bulk transport and
+ * download raw JPEG data.
+ *
+ * Copyright (C) 2009 Theodore Kilgore
+ *
+ * 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
+ * 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
+ */
+
+#define MODULE_NAME "jeilinj"
+
+#include <linux/workqueue.h>
+#include "gspca.h"
+#include "jpeg.h"
+
+MODULE_AUTHOR("Theodore Kilgore <kilgota@auburn.edu>");
+MODULE_DESCRIPTION("GSPCA/JEILINJ USB Camera Driver");
+MODULE_LICENSE("GPL");
+
+/* Default timeouts, in ms */
+#define JEILINJ_CMD_TIMEOUT 500
+#define JEILINJ_DATA_TIMEOUT 1000
+
+/* Maximum transfer size to use. */
+#define JEILINJ_MAX_TRANSFER 0x200
+
+#define FRAME_HEADER_LEN 0x10
+
+/* Structure to hold all of our device specific stuff */
+struct sd {
+       struct gspca_dev gspca_dev;     /* !! must be the first item */
+       const struct v4l2_pix_format *cap_mode;
+       /* Driver stuff */
+       struct work_struct work_struct;
+       struct workqueue_struct *work_thread;
+       u8 quality;                              /* image quality */
+       u8 jpegqual;                            /* webcam quality */
+       u8 *jpeg_hdr;
+};
+
+       struct jlj_command {
+               unsigned char instruction[2];
+               unsigned char ack_wanted;
+       };
+
+/* AFAICT these cameras will only do 320x240. */
+static struct v4l2_pix_format jlj_mode[] = {
+       { 320, 240, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE,
+               .bytesperline = 320,
+               .sizeimage = 320 * 240,
+               .colorspace = V4L2_COLORSPACE_JPEG,
+               .priv = 0}
+};
+
+/*
+ * cam uses endpoint 0x03 to send commands, 0x84 for read commands,
+ * and 0x82 for bulk transfer.
+ */
+
+/* All commands are two bytes only */
+static int jlj_write2(struct gspca_dev *gspca_dev, unsigned char *command)
+{
+       int retval;
+
+       memcpy(gspca_dev->usb_buf, command, 2);
+       retval = usb_bulk_msg(gspca_dev->dev,
+                       usb_sndbulkpipe(gspca_dev->dev, 3),
+                       gspca_dev->usb_buf, 2, NULL, 500);
+       if (retval < 0)
+               PDEBUG(D_ERR, "command write [%02x] error %d",
+                               gspca_dev->usb_buf[0], retval);
+       return retval;
+}
+
+/* Responses are one byte only */
+static int jlj_read1(struct gspca_dev *gspca_dev, unsigned char response)
+{
+       int retval;
+
+       retval = usb_bulk_msg(gspca_dev->dev,
+       usb_rcvbulkpipe(gspca_dev->dev, 0x84),
+                               gspca_dev->usb_buf, 1, NULL, 500);
+       response = gspca_dev->usb_buf[0];
+       if (retval < 0)
+               PDEBUG(D_ERR, "read command [%02x] error %d",
+                               gspca_dev->usb_buf[0], retval);
+       return retval;
+}
+
+static int jlj_start(struct gspca_dev *gspca_dev)
+{
+       int i;
+       int retval = -1;
+       u8 response = 0xff;
+       struct jlj_command start_commands[] = {
+               {{0x71, 0x81}, 0},
+               {{0x70, 0x05}, 0},
+               {{0x95, 0x70}, 1},
+               {{0x71, 0x81}, 0},
+               {{0x70, 0x04}, 0},
+               {{0x95, 0x70}, 1},
+               {{0x71, 0x00}, 0},
+               {{0x70, 0x08}, 0},
+               {{0x95, 0x70}, 1},
+               {{0x94, 0x02}, 0},
+               {{0xde, 0x24}, 0},
+               {{0x94, 0x02}, 0},
+               {{0xdd, 0xf0}, 0},
+               {{0x94, 0x02}, 0},
+               {{0xe3, 0x2c}, 0},
+               {{0x94, 0x02}, 0},
+               {{0xe4, 0x00}, 0},
+               {{0x94, 0x02}, 0},
+               {{0xe5, 0x00}, 0},
+               {{0x94, 0x02}, 0},
+               {{0xe6, 0x2c}, 0},
+               {{0x94, 0x03}, 0},
+               {{0xaa, 0x00}, 0},
+               {{0x71, 0x1e}, 0},
+               {{0x70, 0x06}, 0},
+               {{0x71, 0x80}, 0},
+               {{0x70, 0x07}, 0}
+       };
+       for (i = 0; i < ARRAY_SIZE(start_commands); i++) {
+               retval = jlj_write2(gspca_dev, start_commands[i].instruction);
+               if (retval < 0)
+                       return retval;
+               if (start_commands[i].ack_wanted)
+                       retval = jlj_read1(gspca_dev, response);
+               if (retval < 0)
+                       return retval;
+       }
+       PDEBUG(D_ERR, "jlj_start retval is %d", retval);
+       return retval;
+}
+
+static int jlj_stop(struct gspca_dev *gspca_dev)
+{
+       int i;
+       int retval;
+       struct jlj_command stop_commands[] = {
+               {{0x71, 0x00}, 0},
+               {{0x70, 0x09}, 0},
+               {{0x71, 0x80}, 0},
+               {{0x70, 0x05}, 0}
+       };
+       for (i = 0; i < ARRAY_SIZE(stop_commands); i++) {
+               retval = jlj_write2(gspca_dev, stop_commands[i].instruction);
+               if (retval < 0)
+                       return retval;
+       }
+       return retval;
+}
+
+/* This function is called as a workqueue function and runs whenever the camera
+ * is streaming data. Because it is a workqueue function it is allowed to sleep
+ * so we can use synchronous USB calls. To avoid possible collisions with other
+ * threads attempting to use the camera's USB interface the gspca usb_lock is
+ * used when performing the one USB control operation inside the workqueue,
+ * which tells the camera to close the stream. In practice the only thing
+ * which needs to be protected against is the usb_set_interface call that
+ * gspca makes during stream_off. Otherwise the camera doesn't provide any
+ * controls that the user could try to change.
+ */
+
+static void jlj_dostream(struct work_struct *work)
+{
+       struct sd *dev = container_of(work, struct sd, work_struct);
+       struct gspca_dev *gspca_dev = &dev->gspca_dev;
+       struct gspca_frame *frame;
+       int blocks_left; /* 0x200-sized blocks remaining in current frame. */
+       int size_in_blocks;
+       int act_len;
+       int discarding = 0; /* true if we failed to get space for frame. */
+       int packet_type;
+       int ret;
+       u8 *buffer;
+
+       buffer = kmalloc(JEILINJ_MAX_TRANSFER, GFP_KERNEL | GFP_DMA);
+       if (!buffer) {
+               PDEBUG(D_ERR, "Couldn't allocate USB buffer");
+               goto quit_stream;
+       }
+       while (gspca_dev->present && gspca_dev->streaming) {
+               if (!gspca_dev->present)
+                       goto quit_stream;
+               /* Start a new frame, and add the JPEG header, first thing */
+               frame = gspca_get_i_frame(gspca_dev);
+               if (frame && !discarding)
+                       gspca_frame_add(gspca_dev, FIRST_PACKET, frame,
+                                       dev->jpeg_hdr, JPEG_HDR_SZ);
+                else
+                       discarding = 1;
+               /*
+                * Now request data block 0. Line 0 reports the size
+                * to download, in blocks of size 0x200, and also tells the
+                * "actual" data size, in bytes, which seems best to ignore.
+                */
+               ret = usb_bulk_msg(gspca_dev->dev,
+                               usb_rcvbulkpipe(gspca_dev->dev, 0x82),
+                               buffer, JEILINJ_MAX_TRANSFER, &act_len,
+                               JEILINJ_DATA_TIMEOUT);
+               PDEBUG(D_STREAM,
+                       "Got %d bytes out of %d for Block 0",
+                       act_len, JEILINJ_MAX_TRANSFER);
+               if (ret < 0 || act_len < FRAME_HEADER_LEN)
+                       goto quit_stream;
+               size_in_blocks = buffer[0x0a];
+               blocks_left = buffer[0x0a] - 1;
+               PDEBUG(D_STREAM, "blocks_left = 0x%x", blocks_left);
+               packet_type = INTER_PACKET;
+               if (frame && !discarding)
+                       /* Toss line 0 of data block 0, keep the rest. */
+                       gspca_frame_add(gspca_dev, packet_type,
+                               frame, buffer + FRAME_HEADER_LEN,
+                               JEILINJ_MAX_TRANSFER - FRAME_HEADER_LEN);
+                       else
+                               discarding = 1;
+               while (blocks_left > 0) {
+                       if (!gspca_dev->present)
+                               goto quit_stream;
+                       ret = usb_bulk_msg(gspca_dev->dev,
+                               usb_rcvbulkpipe(gspca_dev->dev, 0x82),
+                               buffer, JEILINJ_MAX_TRANSFER, &act_len,
+                               JEILINJ_DATA_TIMEOUT);
+                       if (ret < 0 || act_len < JEILINJ_MAX_TRANSFER)
+                               goto quit_stream;
+                       PDEBUG(D_STREAM,
+                               "%d blocks remaining for frame", blocks_left);
+                       blocks_left -= 1;
+                       if (blocks_left == 0)
+                               packet_type = LAST_PACKET;
+                       else
+                               packet_type = INTER_PACKET;
+                       if (frame && !discarding)
+                               gspca_frame_add(gspca_dev, packet_type,
+                                               frame, buffer,
+                                               JEILINJ_MAX_TRANSFER);
+                       else
+                               discarding = 1;
+               }
+       }
+quit_stream:
+       mutex_lock(&gspca_dev->usb_lock);
+       if (gspca_dev->present)
+               jlj_stop(gspca_dev);
+       mutex_unlock(&gspca_dev->usb_lock);
+       kfree(buffer);
+}
+
+/* This function is called at probe time just before sd_init */
+static int sd_config(struct gspca_dev *gspca_dev,
+               const struct usb_device_id *id)
+{
+       struct cam *cam = &gspca_dev->cam;
+       struct sd *dev  = (struct sd *) gspca_dev;
+
+       dev->quality  = 85;
+       dev->jpegqual = 85;
+       PDEBUG(D_PROBE,
+               "JEILINJ camera detected"
+               " (vid/pid 0x%04X:0x%04X)", id->idVendor, id->idProduct);
+       cam->cam_mode = jlj_mode;
+       cam->nmodes = 1;
+       cam->bulk = 1;
+       /* We don't use the buffer gspca allocates so make it small. */
+       cam->bulk_size = 32;
+       INIT_WORK(&dev->work_struct, jlj_dostream);
+       return 0;
+}
+
+/* called on streamoff with alt==0 and on disconnect */
+/* the usb_lock is held at entry - restore on exit */
+static void sd_stop0(struct gspca_dev *gspca_dev)
+{
+       struct sd *dev = (struct sd *) gspca_dev;
+
+       /* wait for the work queue to terminate */
+       mutex_unlock(&gspca_dev->usb_lock);
+       /* This waits for jlj_dostream to finish */
+       destroy_workqueue(dev->work_thread);
+       dev->work_thread = NULL;
+       mutex_lock(&gspca_dev->usb_lock);
+       kfree(dev->jpeg_hdr);
+}
+
+/* this function is called at probe and resume time */
+static int sd_init(struct gspca_dev *gspca_dev)
+{
+       return 0;
+}
+
+/* Set up for getting frames. */
+static int sd_start(struct gspca_dev *gspca_dev)
+{
+       struct sd *dev = (struct sd *) gspca_dev;
+       int ret;
+
+       /* create the JPEG header */
+       dev->jpeg_hdr = kmalloc(JPEG_HDR_SZ, GFP_KERNEL);
+       jpeg_define(dev->jpeg_hdr, gspca_dev->height, gspca_dev->width,
+                       0x21);          /* JPEG 422 */
+       jpeg_set_qual(dev->jpeg_hdr, dev->quality);
+       PDEBUG(D_STREAM, "Start streaming at 320x240");
+       ret = jlj_start(gspca_dev);
+       if (ret < 0) {
+               PDEBUG(D_ERR, "Start streaming command failed");
+               return ret;
+       }
+       /* Start the workqueue function to do the streaming */
+       dev->work_thread = create_singlethread_workqueue(MODULE_NAME);
+       queue_work(dev->work_thread, &dev->work_struct);
+
+       return 0;
+}
+
+/* Table of supported USB devices */
+static const __devinitdata struct usb_device_id device_table[] = {
+       {USB_DEVICE(0x0979, 0x0280)},
+       {}
+};
+
+MODULE_DEVICE_TABLE(usb, device_table);
+
+/* sub-driver description */
+static const struct sd_desc sd_desc = {
+       .name   = MODULE_NAME,
+       .config = sd_config,
+       .init   = sd_init,
+       .start  = sd_start,
+       .stop0  = sd_stop0,
+};
+
+/* -- device connect -- */
+static int sd_probe(struct usb_interface *intf,
+               const struct usb_device_id *id)
+{
+       return gspca_dev_probe(intf, id,
+                       &sd_desc,
+                       sizeof(struct sd),
+                       THIS_MODULE);
+}
+
+static struct usb_driver sd_driver = {
+       .name       = MODULE_NAME,
+       .id_table   = device_table,
+       .probe      = sd_probe,
+       .disconnect = gspca_disconnect,
+#ifdef CONFIG_PM
+       .suspend = gspca_suspend,
+       .resume  = gspca_resume,
+#endif
+};
+
+/* -- module insert / remove -- */
+static int __init sd_mod_init(void)
+{
+       int ret;
+
+       ret = usb_register(&sd_driver);
+       if (ret < 0)
+               return ret;
+       PDEBUG(D_PROBE, "registered");
+       return 0;
+}
+
+static void __exit sd_mod_exit(void)
+{
+       usb_deregister(&sd_driver);
+       PDEBUG(D_PROBE, "deregistered");
+}
+
+module_init(sd_mod_init);
+module_exit(sd_mod_exit);
index 7127321ace8cbe35e893dd40025bbb901e60ee51..6b89f33a4ce015c0b6e0b9c9f69872dba1fd77e2 100644 (file)
@@ -178,8 +178,10 @@ sensor_found:
 
        sens_priv->settings =
        kmalloc(sizeof(s32)*ARRAY_SIZE(s5k83a_ctrls), GFP_KERNEL);
-       if (!sens_priv->settings)
+       if (!sens_priv->settings) {
+               kfree(sens_priv);
                return -ENOMEM;
+       }
 
        sd->gspca_dev.cam.cam_mode = s5k83a_modes;
        sd->gspca_dev.cam.nmodes = ARRAY_SIZE(s5k83a_modes);
index 30132513400cbc266209320e2c915252b6e1af8b..140c8f320e4782b83b39342b064c877d26eb85d6 100644 (file)
@@ -3,6 +3,21 @@
  *
  * Copyright (C) 2009 Kyle Guinn <elyk03@gmail.com>
  *
+ * Support for the MR97310A cameras in addition to the Aiptek Pencam VGA+
+ * and for the routines for detecting and classifying these various cameras,
+ *
+ * Copyright (C) 2009 Theodore Kilgore <kilgota@auburn.edu>
+ *
+ * Acknowledgements:
+ *
+ * The MR97311A support in gspca/mars.c has been helpful in understanding some
+ * of the registers in these cameras.
+ *
+ * Hans de Goede <hdgoede@redhat.com> and
+ * Thomas Kaiser <thomas@kaiser-linux.li>
+ * have assisted with their experience. Each of them has also helped by
+ * testing a previously unsupported camera.
+ *
  * 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
 
 #include "gspca.h"
 
-MODULE_AUTHOR("Kyle Guinn <elyk03@gmail.com>");
+#define CAM_TYPE_CIF                   0
+#define CAM_TYPE_VGA                   1
+
+#define MR97310A_BRIGHTNESS_MIN                -254
+#define MR97310A_BRIGHTNESS_MAX                255
+#define MR97310A_BRIGHTNESS_DEFAULT    0
+
+#define MR97310A_EXPOSURE_MIN          300
+#define MR97310A_EXPOSURE_MAX          4095
+#define MR97310A_EXPOSURE_DEFAULT      1000
+
+#define MR97310A_GAIN_MIN              0
+#define MR97310A_GAIN_MAX              31
+#define MR97310A_GAIN_DEFAULT          25
+
+MODULE_AUTHOR("Kyle Guinn <elyk03@gmail.com>,"
+             "Theodore Kilgore <kilgota@auburn.edu>");
 MODULE_DESCRIPTION("GSPCA/Mars-Semi MR97310A USB Camera Driver");
 MODULE_LICENSE("GPL");
 
+/* global parameters */
+int force_sensor_type = -1;
+module_param(force_sensor_type, int, 0644);
+MODULE_PARM_DESC(force_sensor_type, "Force sensor type (-1 (auto), 0 or 1)");
+
 /* specific webcam descriptor */
 struct sd {
        struct gspca_dev gspca_dev;  /* !! must be the first item */
        u8 sof_read;
+       u8 cam_type;    /* 0 is CIF and 1 is VGA */
+       u8 sensor_type; /* We use 0 and 1 here, too. */
+       u8 do_lcd_stop;
+
+       int brightness;
+       u16 exposure;
+       u8 gain;
+};
+
+struct sensor_w_data {
+       u8 reg;
+       u8 flags;
+       u8 data[16];
+       int len;
 };
 
+static int sd_setbrightness(struct gspca_dev *gspca_dev, __s32 val);
+static int sd_getbrightness(struct gspca_dev *gspca_dev, __s32 *val);
+static int sd_setexposure(struct gspca_dev *gspca_dev, __s32 val);
+static int sd_getexposure(struct gspca_dev *gspca_dev, __s32 *val);
+static int sd_setgain(struct gspca_dev *gspca_dev, __s32 val);
+static int sd_getgain(struct gspca_dev *gspca_dev, __s32 *val);
+static void setbrightness(struct gspca_dev *gspca_dev);
+static void setexposure(struct gspca_dev *gspca_dev);
+static void setgain(struct gspca_dev *gspca_dev);
+
 /* V4L2 controls supported by the driver */
 static struct ctrl sd_ctrls[] = {
+       {
+#define BRIGHTNESS_IDX 0
+               {
+                       .id = V4L2_CID_BRIGHTNESS,
+                       .type = V4L2_CTRL_TYPE_INTEGER,
+                       .name = "Brightness",
+                       .minimum = MR97310A_BRIGHTNESS_MIN,
+                       .maximum = MR97310A_BRIGHTNESS_MAX,
+                       .step = 1,
+                       .default_value = MR97310A_BRIGHTNESS_DEFAULT,
+                       .flags = 0,
+               },
+               .set = sd_setbrightness,
+               .get = sd_getbrightness,
+       },
+       {
+#define EXPOSURE_IDX 1
+               {
+                       .id = V4L2_CID_EXPOSURE,
+                       .type = V4L2_CTRL_TYPE_INTEGER,
+                       .name = "Exposure",
+                       .minimum = MR97310A_EXPOSURE_MIN,
+                       .maximum = MR97310A_EXPOSURE_MAX,
+                       .step = 1,
+                       .default_value = MR97310A_EXPOSURE_DEFAULT,
+                       .flags = 0,
+               },
+               .set = sd_setexposure,
+               .get = sd_getexposure,
+       },
+       {
+#define GAIN_IDX 2
+               {
+                       .id = V4L2_CID_GAIN,
+                       .type = V4L2_CTRL_TYPE_INTEGER,
+                       .name = "Gain",
+                       .minimum = MR97310A_GAIN_MIN,
+                       .maximum = MR97310A_GAIN_MAX,
+                       .step = 1,
+                       .default_value = MR97310A_GAIN_DEFAULT,
+                       .flags = 0,
+               },
+               .set = sd_setgain,
+               .get = sd_getgain,
+       },
 };
 
 static const struct v4l2_pix_format vga_mode[] = {
@@ -65,7 +170,7 @@ static const struct v4l2_pix_format vga_mode[] = {
 };
 
 /* the bytes to write are in gspca_dev->usb_buf */
-static int reg_w(struct gspca_dev *gspca_dev, int len)
+static int mr_write(struct gspca_dev *gspca_dev, int len)
 {
        int rc;
 
@@ -78,15 +183,249 @@ static int reg_w(struct gspca_dev *gspca_dev, int len)
        return rc;
 }
 
+/* the bytes are read into gspca_dev->usb_buf */
+static int mr_read(struct gspca_dev *gspca_dev, int len)
+{
+       int rc;
+
+       rc = usb_bulk_msg(gspca_dev->dev,
+                         usb_rcvbulkpipe(gspca_dev->dev, 3),
+                         gspca_dev->usb_buf, len, NULL, 500);
+       if (rc < 0)
+               PDEBUG(D_ERR, "reg read [%02x] error %d",
+                      gspca_dev->usb_buf[0], rc);
+       return rc;
+}
+
+static int sensor_write_reg(struct gspca_dev *gspca_dev, u8 reg, u8 flags,
+       const u8 *data, int len)
+{
+       gspca_dev->usb_buf[0] = 0x1f;
+       gspca_dev->usb_buf[1] = flags;
+       gspca_dev->usb_buf[2] = reg;
+       memcpy(gspca_dev->usb_buf + 3, data, len);
+
+       return mr_write(gspca_dev, len + 3);
+}
+
+static int sensor_write_regs(struct gspca_dev *gspca_dev,
+       const struct sensor_w_data *data, int len)
+{
+       int i, rc;
+
+       for (i = 0; i < len; i++) {
+               rc = sensor_write_reg(gspca_dev, data[i].reg, data[i].flags,
+                                         data[i].data, data[i].len);
+               if (rc < 0)
+                       return rc;
+       }
+
+       return 0;
+}
+
+static int sensor_write1(struct gspca_dev *gspca_dev, u8 reg, u8 data)
+{
+       struct sd *sd = (struct sd *) gspca_dev;
+       u8 buf, confirm_reg;
+       int rc;
+
+       buf = data;
+       rc = sensor_write_reg(gspca_dev, reg, 0x01, &buf, 1);
+       if (rc < 0)
+               return rc;
+
+       buf = 0x01;
+       confirm_reg = sd->sensor_type ? 0x13 : 0x11;
+       rc = sensor_write_reg(gspca_dev, confirm_reg, 0x00, &buf, 1);
+       if (rc < 0)
+               return rc;
+
+       return 0;
+}
+
+static int cam_get_response16(struct gspca_dev *gspca_dev)
+{
+       __u8 *data = gspca_dev->usb_buf;
+       int err_code;
+
+       data[0] = 0x21;
+       err_code = mr_write(gspca_dev, 1);
+       if (err_code < 0)
+               return err_code;
+
+       err_code = mr_read(gspca_dev, 16);
+       return err_code;
+}
+
+static int zero_the_pointer(struct gspca_dev *gspca_dev)
+{
+       __u8 *data = gspca_dev->usb_buf;
+       int err_code;
+       u8 status = 0;
+       int tries = 0;
+
+       err_code = cam_get_response16(gspca_dev);
+       if (err_code < 0)
+               return err_code;
+
+       err_code = mr_write(gspca_dev, 1);
+       data[0] = 0x19;
+       data[1] = 0x51;
+       err_code = mr_write(gspca_dev, 2);
+       if (err_code < 0)
+               return err_code;
+
+       err_code = cam_get_response16(gspca_dev);
+       if (err_code < 0)
+               return err_code;
+
+       data[0] = 0x19;
+       data[1] = 0xba;
+       err_code = mr_write(gspca_dev, 2);
+       if (err_code < 0)
+               return err_code;
+
+       err_code = cam_get_response16(gspca_dev);
+       if (err_code < 0)
+               return err_code;
+
+       data[0] = 0x19;
+       data[1] = 0x00;
+       err_code = mr_write(gspca_dev, 2);
+       if (err_code < 0)
+               return err_code;
+
+       err_code = cam_get_response16(gspca_dev);
+       if (err_code < 0)
+               return err_code;
+
+       data[0] = 0x19;
+       data[1] = 0x00;
+       err_code = mr_write(gspca_dev, 2);
+       if (err_code < 0)
+               return err_code;
+
+       while (status != 0x0a && tries < 256) {
+               err_code = cam_get_response16(gspca_dev);
+               status = data[0];
+               tries++;
+               if (err_code < 0)
+                       return err_code;
+       }
+       if (status != 0x0a)
+               PDEBUG(D_ERR, "status is %02x", status);
+
+       tries = 0;
+       while (tries < 4) {
+               data[0] = 0x19;
+               data[1] = 0x00;
+               err_code = mr_write(gspca_dev, 2);
+               if (err_code < 0)
+                       return err_code;
+
+               err_code = cam_get_response16(gspca_dev);
+               status = data[0];
+               tries++;
+               if (err_code < 0)
+                       return err_code;
+       }
+
+       data[0] = 0x19;
+       err_code = mr_write(gspca_dev, 1);
+       if (err_code < 0)
+               return err_code;
+
+       err_code = mr_read(gspca_dev, 16);
+       if (err_code < 0)
+               return err_code;
+
+       return 0;
+}
+
+static u8 get_sensor_id(struct gspca_dev *gspca_dev)
+{
+       int err_code;
+
+       gspca_dev->usb_buf[0] = 0x1e;
+       err_code = mr_write(gspca_dev, 1);
+       if (err_code < 0)
+               return err_code;
+
+       err_code = mr_read(gspca_dev, 16);
+       if (err_code < 0)
+               return err_code;
+
+       PDEBUG(D_PROBE, "Byte zero reported is %01x", gspca_dev->usb_buf[0]);
+
+       return gspca_dev->usb_buf[0];
+}
+
 /* this function is called at probe time */
 static int sd_config(struct gspca_dev *gspca_dev,
                     const struct usb_device_id *id)
 {
+       struct sd *sd = (struct sd *) gspca_dev;
        struct cam *cam;
+       __u8 *data = gspca_dev->usb_buf;
+       int err_code;
 
        cam = &gspca_dev->cam;
        cam->cam_mode = vga_mode;
        cam->nmodes = ARRAY_SIZE(vga_mode);
+
+       if (id->idProduct == 0x010e) {
+               sd->cam_type = CAM_TYPE_CIF;
+               cam->nmodes--;
+
+               data[0] = 0x01;
+               data[1] = 0x01;
+               err_code = mr_write(gspca_dev, 2);
+               if (err_code < 0)
+                       return err_code;
+
+               msleep(200);
+               data[0] = get_sensor_id(gspca_dev);
+               /*
+                * Known CIF cameras. If you have another to report, please do
+                *
+                * Name                 byte just read          sd->sensor_type
+                *                                      reported by
+                * Sakar Spy-shot       0x28            T. Kilgore      0
+                * Innovage             0xf5 (unstable) T. Kilgore      0
+                * Vivitar Mini         0x53            H. De Goede     0
+                * Vivitar Mini         0x04 / 0x24     E. Rodriguez    0
+                * Vivitar Mini         0x08            T. Kilgore      1
+                * Elta-Media 8212dc    0x23            T. Kaiser       1
+                * Philips dig. keych.  0x37            T. Kilgore      1
+                */
+               if ((data[0] & 0x78) == 8 ||
+                   ((data[0] & 0x2) == 0x2 && data[0] != 0x53))
+                       sd->sensor_type = 1;
+               else
+                       sd->sensor_type = 0;
+
+               PDEBUG(D_PROBE, "MR97310A CIF camera detected, sensor: %d",
+                      sd->sensor_type);
+
+               if (force_sensor_type != -1) {
+                       sd->sensor_type = !! force_sensor_type;
+                       PDEBUG(D_PROBE, "Forcing sensor type to: %d",
+                              sd->sensor_type);
+               }
+
+               if (sd->sensor_type == 0)
+                       gspca_dev->ctrl_dis = (1 << BRIGHTNESS_IDX);
+       } else {
+               sd->cam_type = CAM_TYPE_VGA;
+               PDEBUG(D_PROBE, "MR97310A VGA camera detected");
+               gspca_dev->ctrl_dis = (1 << BRIGHTNESS_IDX) |
+                                     (1 << EXPOSURE_IDX) | (1 << GAIN_IDX);
+       }
+
+       sd->brightness = MR97310A_BRIGHTNESS_DEFAULT;
+       sd->exposure = MR97310A_EXPOSURE_DEFAULT;
+       sd->gain = MR97310A_GAIN_DEFAULT;
+
        return 0;
 }
 
@@ -96,183 +435,462 @@ static int sd_init(struct gspca_dev *gspca_dev)
        return 0;
 }
 
-static int sd_start(struct gspca_dev *gspca_dev)
+static int start_cif_cam(struct gspca_dev *gspca_dev)
 {
        struct sd *sd = (struct sd *) gspca_dev;
        __u8 *data = gspca_dev->usb_buf;
        int err_code;
-
-       sd->sof_read = 0;
-
-       /* Note:  register descriptions guessed from MR97113A driver */
-
+       const __u8 startup_string[] = {
+               0x00,
+               0x0d,
+               0x01,
+               0x00, /* Hsize/8 for 352 or 320 */
+               0x00, /* Vsize/4 for 288 or 240 */
+               0x13, /* or 0xbb, depends on sensor */
+               0x00, /* Hstart, depends on res. */
+               0x00, /* reserved ? */
+               0x00, /* Vstart, depends on res. and sensor */
+               0x50, /* 0x54 to get 176 or 160 */
+               0xc0
+       };
+
+       /* Note: Some of the above descriptions guessed from MR97113A driver */
        data[0] = 0x01;
        data[1] = 0x01;
-       err_code = reg_w(gspca_dev, 2);
+       err_code = mr_write(gspca_dev, 2);
        if (err_code < 0)
                return err_code;
 
-       data[0] = 0x00;
-       data[1] = 0x0d;
-       data[2] = 0x01;
-       data[5] = 0x2b;
-       data[7] = 0x00;
-       data[9] = 0x50;  /* reg 8, no scale down */
-       data[10] = 0xc0;
+       memcpy(data, startup_string, 11);
+       if (sd->sensor_type)
+               data[5] = 0xbb;
 
        switch (gspca_dev->width) {
        case 160:
-               data[9] |= 0x0c;  /* reg 8, 4:1 scale down */
+               data[9] |= 0x04;  /* reg 8, 2:1 scale down from 320 */
                /* fall thru */
        case 320:
-               data[9] |= 0x04;  /* reg 8, 2:1 scale down */
-               /* fall thru */
-       case 640:
        default:
-               data[3] = 0x50;  /* reg 2, H size */
-               data[4] = 0x78;  /* reg 3, V size */
-               data[6] = 0x04;  /* reg 5, H start */
-               data[8] = 0x03;  /* reg 7, V start */
+               data[3] = 0x28;                    /* reg 2, H size/8 */
+               data[4] = 0x3c;                    /* reg 3, V size/4 */
+               data[6] = 0x14;                    /* reg 5, H start  */
+               data[8] = 0x1a + sd->sensor_type;  /* reg 7, V start  */
                break;
-
        case 176:
-               data[9] |= 0x04;  /* reg 8, 2:1 scale down */
+               data[9] |= 0x04;  /* reg 8, 2:1 scale down from 352 */
                /* fall thru */
        case 352:
-               data[3] = 0x2c;  /* reg 2, H size */
-               data[4] = 0x48;  /* reg 3, V size */
-               data[6] = 0x94;  /* reg 5, H start */
-               data[8] = 0x63;  /* reg 7, V start */
+               data[3] = 0x2c;                    /* reg 2, H size/8 */
+               data[4] = 0x48;                    /* reg 3, V size/4 */
+               data[6] = 0x06;                    /* reg 5, H start  */
+               data[8] = 0x06 + sd->sensor_type;  /* reg 7, V start  */
                break;
        }
-
-       err_code = reg_w(gspca_dev, 11);
+       err_code = mr_write(gspca_dev, 11);
        if (err_code < 0)
                return err_code;
 
-       data[0] = 0x0a;
-       data[1] = 0x80;
-       err_code = reg_w(gspca_dev, 2);
+       if (!sd->sensor_type) {
+               const struct sensor_w_data cif_sensor0_init_data[] = {
+                       {0x02, 0x00, {0x03, 0x5a, 0xb5, 0x01,
+                                     0x0f, 0x14, 0x0f, 0x10}, 8},
+                       {0x0c, 0x00, {0x04, 0x01, 0x01, 0x00, 0x1f}, 5},
+                       {0x12, 0x00, {0x07}, 1},
+                       {0x1f, 0x00, {0x06}, 1},
+                       {0x27, 0x00, {0x04}, 1},
+                       {0x29, 0x00, {0x0c}, 1},
+                       {0x40, 0x00, {0x40, 0x00, 0x04}, 3},
+                       {0x50, 0x00, {0x60}, 1},
+                       {0x60, 0x00, {0x06}, 1},
+                       {0x6b, 0x00, {0x85, 0x85, 0xc8, 0xc8, 0xc8, 0xc8}, 6},
+                       {0x72, 0x00, {0x1e, 0x56}, 2},
+                       {0x75, 0x00, {0x58, 0x40, 0xa2, 0x02, 0x31, 0x02,
+                                     0x31, 0x80, 0x00}, 9},
+                       {0x11, 0x00, {0x01}, 1},
+                       {0, 0, {0}, 0}
+               };
+               err_code = sensor_write_regs(gspca_dev, cif_sensor0_init_data,
+                                        ARRAY_SIZE(cif_sensor0_init_data));
+       } else {        /* sd->sensor_type = 1 */
+               const struct sensor_w_data cif_sensor1_init_data[] = {
+                       /* Reg 3,4, 7,8 get set by the controls */
+                       {0x02, 0x00, {0x10}, 1},
+                       {0x05, 0x01, {0x22}, 1}, /* 5/6 also seen as 65h/32h */
+                       {0x06, 0x01, {0x00}, 1},
+                       {0x09, 0x02, {0x0e}, 1},
+                       {0x0a, 0x02, {0x05}, 1},
+                       {0x0b, 0x02, {0x05}, 1},
+                       {0x0c, 0x02, {0x0f}, 1},
+                       {0x0d, 0x02, {0x07}, 1},
+                       {0x0e, 0x02, {0x0c}, 1},
+                       {0x0f, 0x00, {0x00}, 1},
+                       {0x10, 0x00, {0x06}, 1},
+                       {0x11, 0x00, {0x07}, 1},
+                       {0x12, 0x00, {0x00}, 1},
+                       {0x13, 0x00, {0x01}, 1},
+                       {0, 0, {0}, 0}
+               };
+               err_code = sensor_write_regs(gspca_dev, cif_sensor1_init_data,
+                                        ARRAY_SIZE(cif_sensor1_init_data));
+       }
        if (err_code < 0)
                return err_code;
 
-       data[0] = 0x14;
-       data[1] = 0x0a;
-       err_code = reg_w(gspca_dev, 2);
-       if (err_code < 0)
-               return err_code;
+       setbrightness(gspca_dev);
+       setexposure(gspca_dev);
+       setgain(gspca_dev);
 
-       data[0] = 0x1b;
-       data[1] = 0x00;
-       err_code = reg_w(gspca_dev, 2);
-       if (err_code < 0)
-               return err_code;
+       msleep(200);
 
-       data[0] = 0x15;
-       data[1] = 0x16;
-       err_code = reg_w(gspca_dev, 2);
+       data[0] = 0x00;
+       data[1] = 0x4d;  /* ISOC transfering enable... */
+       err_code = mr_write(gspca_dev, 2);
        if (err_code < 0)
                return err_code;
 
-       data[0] = 0x16;
-       data[1] = 0x10;
-       err_code = reg_w(gspca_dev, 2);
-       if (err_code < 0)
-               return err_code;
+       return 0;
+}
 
-       data[0] = 0x17;
-       data[1] = 0x3a;
-       err_code = reg_w(gspca_dev, 2);
-       if (err_code < 0)
-               return err_code;
+static int start_vga_cam(struct gspca_dev *gspca_dev)
+{
+       struct sd *sd = (struct sd *) gspca_dev;
+       __u8 *data = gspca_dev->usb_buf;
+       int err_code;
+       const __u8 startup_string[] = {0x00, 0x0d, 0x01, 0x00, 0x00, 0x2b,
+                                      0x00, 0x00, 0x00, 0x50, 0xc0};
 
-       data[0] = 0x18;
-       data[1] = 0x68;
-       err_code = reg_w(gspca_dev, 2);
-       if (err_code < 0)
-               return err_code;
+       /* What some of these mean is explained in start_cif_cam(), above */
+       sd->sof_read = 0;
 
-       data[0] = 0x1f;
-       data[1] = 0x00;
-       data[2] = 0x02;
-       data[3] = 0x06;
-       data[4] = 0x59;
-       data[5] = 0x0c;
-       data[6] = 0x16;
-       data[7] = 0x00;
-       data[8] = 0x07;
-       data[9] = 0x00;
-       data[10] = 0x01;
-       err_code = reg_w(gspca_dev, 11);
+       /*
+        * We have to know which camera we have, because the register writes
+        * depend upon the camera. This test, run before we actually enter
+        * the initialization routine, distinguishes most of the cameras, If
+        * needed, another routine is done later, too.
+        */
+       memset(data, 0, 16);
+       data[0] = 0x20;
+       err_code = mr_write(gspca_dev, 1);
        if (err_code < 0)
                return err_code;
 
-       data[0] = 0x1f;
-       data[1] = 0x04;
-       data[2] = 0x11;
-       data[3] = 0x01;
-       err_code = reg_w(gspca_dev, 4);
+       err_code = mr_read(gspca_dev, 16);
        if (err_code < 0)
                return err_code;
 
-       data[0] = 0x1f;
-       data[1] = 0x00;
-       data[2] = 0x0a;
-       data[3] = 0x00;
-       data[4] = 0x01;
-       data[5] = 0x00;
-       data[6] = 0x00;
-       data[7] = 0x01;
-       data[8] = 0x00;
-       data[9] = 0x0a;
-       err_code = reg_w(gspca_dev, 10);
-       if (err_code < 0)
-               return err_code;
+       PDEBUG(D_PROBE, "Byte reported is %02x", data[0]);
+
+       msleep(200);
+       /*
+        * Known VGA cameras. If you have another to report, please do
+        *
+        * Name                 byte just read          sd->sensor_type
+        *                              sd->do_lcd_stop
+        * Aiptek Pencam VGA+   0x31            0       1
+        * ION digital          0x31            0       1
+        * Argus DC-1620        0x30            1       0
+        * Argus QuickClix      0x30            1       1 (not caught here)
+        */
+       sd->sensor_type = data[0] & 1;
+       sd->do_lcd_stop = (~data[0]) & 1;
+
+
 
-       data[0] = 0x1f;
-       data[1] = 0x04;
-       data[2] = 0x11;
-       data[3] = 0x01;
-       err_code = reg_w(gspca_dev, 4);
+       /* Streaming setup begins here. */
+
+
+       data[0] = 0x01;
+       data[1] = 0x01;
+       err_code = mr_write(gspca_dev, 2);
        if (err_code < 0)
                return err_code;
 
-       data[0] = 0x1f;
-       data[1] = 0x00;
-       data[2] = 0x12;
-       data[3] = 0x00;
-       data[4] = 0x63;
-       data[5] = 0x00;
-       data[6] = 0x70;
-       data[7] = 0x00;
-       data[8] = 0x00;
-       err_code = reg_w(gspca_dev, 9);
+       /*
+        * A second test can now resolve any remaining ambiguity in the
+        * identification of the camera type,
+        */
+       if (!sd->sensor_type) {
+               data[0] = get_sensor_id(gspca_dev);
+               if (data[0] == 0x7f) {
+                       sd->sensor_type = 1;
+                       PDEBUG(D_PROBE, "sensor_type corrected to 1");
+               }
+               msleep(200);
+       }
+
+       if (force_sensor_type != -1) {
+               sd->sensor_type = !! force_sensor_type;
+               PDEBUG(D_PROBE, "Forcing sensor type to: %d",
+                      sd->sensor_type);
+       }
+
+       /*
+        * Known VGA cameras.
+        * This test is only run if the previous test returned 0x30, but
+        * here is the information for all others, too, just for reference.
+        *
+        * Name                 byte just read          sd->sensor_type
+        *
+        * Aiptek Pencam VGA+   0xfb    (this test not run)     1
+        * ION digital          0xbd    (this test not run)     1
+        * Argus DC-1620        0xe5    (no change)             0
+        * Argus QuickClix      0x7f    (reclassified)          1
+        */
+       memcpy(data, startup_string, 11);
+       if (!sd->sensor_type) {
+               data[5]  = 0x00;
+               data[10] = 0x91;
+       }
+
+       switch (gspca_dev->width) {
+       case 160:
+               data[9] |= 0x0c;  /* reg 8, 4:1 scale down */
+               /* fall thru */
+       case 320:
+               data[9] |= 0x04;  /* reg 8, 2:1 scale down */
+               /* fall thru */
+       case 640:
+       default:
+               data[3] = 0x50;  /* reg 2, H size/8 */
+               data[4] = 0x78;  /* reg 3, V size/4 */
+               data[6] = 0x04;  /* reg 5, H start */
+               data[8] = 0x03;  /* reg 7, V start */
+               if (sd->do_lcd_stop)
+                       data[8] = 0x04;  /* Bayer tile shifted */
+               break;
+
+       case 176:
+               data[9] |= 0x04;  /* reg 8, 2:1 scale down */
+               /* fall thru */
+       case 352:
+               data[3] = 0x2c;  /* reg 2, H size */
+               data[4] = 0x48;  /* reg 3, V size */
+               data[6] = 0x94;  /* reg 5, H start */
+               data[8] = 0x63;  /* reg 7, V start */
+               if (sd->do_lcd_stop)
+                       data[8] = 0x64;  /* Bayer tile shifted */
+               break;
+       }
+
+       err_code = mr_write(gspca_dev, 11);
        if (err_code < 0)
                return err_code;
 
-       data[0] = 0x1f;
-       data[1] = 0x04;
-       data[2] = 0x11;
-       data[3] = 0x01;
-       err_code = reg_w(gspca_dev, 4);
+       if (!sd->sensor_type) {
+               /* The only known sensor_type 0 cam is the Argus DC-1620 */
+               const struct sensor_w_data vga_sensor0_init_data[] = {
+                       {0x01, 0x00, {0x0c, 0x00, 0x04}, 3},
+                       {0x14, 0x00, {0x01, 0xe4, 0x02, 0x84}, 4},
+                       {0x20, 0x00, {0x00, 0x80, 0x00, 0x08}, 4},
+                       {0x25, 0x00, {0x03, 0xa9, 0x80}, 3},
+                       {0x30, 0x00, {0x30, 0x18, 0x10, 0x18}, 4},
+                       {0, 0, {0}, 0}
+               };
+               err_code = sensor_write_regs(gspca_dev, vga_sensor0_init_data,
+                                        ARRAY_SIZE(vga_sensor0_init_data));
+       } else {        /* sd->sensor_type = 1 */
+               const struct sensor_w_data vga_sensor1_init_data[] = {
+                       {0x02, 0x00, {0x06, 0x59, 0x0c, 0x16, 0x00,
+                               0x07, 0x00, 0x01}, 8},
+                       {0x11, 0x04, {0x01}, 1},
+                       /*{0x0a, 0x00, {0x00, 0x01, 0x00, 0x00, 0x01, */
+                       {0x0a, 0x00, {0x01, 0x06, 0x00, 0x00, 0x01,
+                               0x00, 0x0a}, 7},
+                       {0x11, 0x04, {0x01}, 1},
+                       {0x12, 0x00, {0x00, 0x63, 0x00, 0x70, 0x00, 0x00}, 6},
+                       {0x11, 0x04, {0x01}, 1},
+                       {0, 0, {0}, 0}
+               };
+               err_code = sensor_write_regs(gspca_dev, vga_sensor1_init_data,
+                                        ARRAY_SIZE(vga_sensor1_init_data));
+       }
        if (err_code < 0)
                return err_code;
 
+       msleep(200);
        data[0] = 0x00;
        data[1] = 0x4d;  /* ISOC transfering enable... */
-       err_code = reg_w(gspca_dev, 2);
+       err_code = mr_write(gspca_dev, 2);
+
+       return err_code;
+}
+
+static int sd_start(struct gspca_dev *gspca_dev)
+{
+       struct sd *sd = (struct sd *) gspca_dev;
+       int err_code;
+       struct cam *cam;
+
+       cam = &gspca_dev->cam;
+       sd->sof_read = 0;
+       /*
+        * Some of the supported cameras require the memory pointer to be
+        * set to 0, or else they will not stream.
+        */
+       zero_the_pointer(gspca_dev);
+       msleep(200);
+       if (sd->cam_type == CAM_TYPE_CIF) {
+               err_code = start_cif_cam(gspca_dev);
+       } else {
+               err_code = start_vga_cam(gspca_dev);
+       }
        return err_code;
 }
 
 static void sd_stopN(struct gspca_dev *gspca_dev)
 {
+       struct sd *sd = (struct sd *) gspca_dev;
        int result;
 
        gspca_dev->usb_buf[0] = 1;
        gspca_dev->usb_buf[1] = 0;
-       result = reg_w(gspca_dev, 2);
+       result = mr_write(gspca_dev, 2);
        if (result < 0)
                PDEBUG(D_ERR, "Camera Stop failed");
+
+       /* Not all the cams need this, but even if not, probably a good idea */
+       zero_the_pointer(gspca_dev);
+       if (sd->do_lcd_stop) {
+               gspca_dev->usb_buf[0] = 0x19;
+               gspca_dev->usb_buf[1] = 0x54;
+               result = mr_write(gspca_dev, 2);
+               if (result < 0)
+                       PDEBUG(D_ERR, "Camera Stop failed");
+       }
+}
+
+static void setbrightness(struct gspca_dev *gspca_dev)
+{
+       struct sd *sd = (struct sd *) gspca_dev;
+       u8 val;
+
+       if (gspca_dev->ctrl_dis & (1 << BRIGHTNESS_IDX))
+               return;
+
+       /* Note register 7 is also seen as 0x8x or 0xCx in dumps */
+       if (sd->brightness > 0) {
+               sensor_write1(gspca_dev, 7, 0x00);
+               val = sd->brightness;
+       } else {
+               sensor_write1(gspca_dev, 7, 0x01);
+               val = 257 - sd->brightness;
+       }
+       sensor_write1(gspca_dev, 8, val);
+}
+
+static void setexposure(struct gspca_dev *gspca_dev)
+{
+       struct sd *sd = (struct sd *) gspca_dev;
+       u8 val;
+
+       if (gspca_dev->ctrl_dis & (1 << EXPOSURE_IDX))
+               return;
+
+       if (sd->sensor_type) {
+               val = sd->exposure >> 4;
+               sensor_write1(gspca_dev, 3, val);
+               val = sd->exposure & 0xf;
+               sensor_write1(gspca_dev, 4, val);
+       } else {
+               u8 clockdiv;
+               int exposure;
+
+               /* We have both a clock divider and an exposure register.
+                  We first calculate the clock divider, as that determines
+                  the maximum exposure and then we calculayte the exposure
+                  register setting (which goes from 0 - 511).
+
+                  Note our 0 - 4095 exposure is mapped to 0 - 511
+                  milliseconds exposure time */
+               clockdiv = (60 * sd->exposure + 7999) / 8000;
+
+               /* Limit framerate to not exceed usb bandwidth */
+               if (clockdiv < 3 && gspca_dev->width >= 320)
+                       clockdiv = 3;
+               else if (clockdiv < 2)
+                       clockdiv = 2;
+
+               /* Frame exposure time in ms = 1000 * clockdiv / 60 ->
+               exposure = (sd->exposure / 8) * 511 / (1000 * clockdiv / 60) */
+               exposure = (60 * 511 * sd->exposure) / (8000 * clockdiv);
+               if (exposure > 511)
+                       exposure = 511;
+
+               /* exposure register value is reversed! */
+               exposure = 511 - exposure;
+
+               sensor_write1(gspca_dev, 0x02, clockdiv);
+               sensor_write1(gspca_dev, 0x0e, exposure & 0xff);
+               sensor_write1(gspca_dev, 0x0f, exposure >> 8);
+       }
+}
+
+static void setgain(struct gspca_dev *gspca_dev)
+{
+       struct sd *sd = (struct sd *) gspca_dev;
+
+       if (gspca_dev->ctrl_dis & (1 << GAIN_IDX))
+               return;
+
+       if (sd->sensor_type) {
+               sensor_write1(gspca_dev, 0x0e, sd->gain);
+       } else {
+               sensor_write1(gspca_dev, 0x10, sd->gain);
+       }
+}
+
+static int sd_setbrightness(struct gspca_dev *gspca_dev, __s32 val)
+{
+       struct sd *sd = (struct sd *) gspca_dev;
+
+       sd->brightness = val;
+       if (gspca_dev->streaming)
+               setbrightness(gspca_dev);
+       return 0;
+}
+
+static int sd_getbrightness(struct gspca_dev *gspca_dev, __s32 *val)
+{
+       struct sd *sd = (struct sd *) gspca_dev;
+
+       *val = sd->brightness;
+       return 0;
+}
+
+static int sd_setexposure(struct gspca_dev *gspca_dev, __s32 val)
+{
+       struct sd *sd = (struct sd *) gspca_dev;
+
+       sd->exposure = val;
+       if (gspca_dev->streaming)
+               setexposure(gspca_dev);
+       return 0;
+}
+
+static int sd_getexposure(struct gspca_dev *gspca_dev, __s32 *val)
+{
+       struct sd *sd = (struct sd *) gspca_dev;
+
+       *val = sd->exposure;
+       return 0;
+}
+
+static int sd_setgain(struct gspca_dev *gspca_dev, __s32 val)
+{
+       struct sd *sd = (struct sd *) gspca_dev;
+
+       sd->gain = val;
+       if (gspca_dev->streaming)
+               setgain(gspca_dev);
+       return 0;
+}
+
+static int sd_getgain(struct gspca_dev *gspca_dev, __s32 *val)
+{
+       struct sd *sd = (struct sd *) gspca_dev;
+
+       *val = sd->gain;
+       return 0;
 }
 
 /* Include pac common sof detection functions */
@@ -320,8 +938,9 @@ static const struct sd_desc sd_desc = {
 
 /* -- module initialisation -- */
 static const __devinitdata struct usb_device_id device_table[] = {
-       {USB_DEVICE(0x08ca, 0x0111)},
-       {USB_DEVICE(0x093a, 0x010f)},
+       {USB_DEVICE(0x08ca, 0x0111)},   /* Aiptek Pencam VGA+ */
+       {USB_DEVICE(0x093a, 0x010f)},   /* All other known MR97310A VGA cams */
+       {USB_DEVICE(0x093a, 0x010e)},   /* All known MR97310A CIF cams */
        {}
 };
 MODULE_DEVICE_TABLE(usb, device_table);
index 95a97ab684cd3fdba219f7d54b6ef03fe55588ca..96659433d2488d901b112bc56ef015f763f58871 100644 (file)
@@ -35,25 +35,17 @@ MODULE_LICENSE("GPL");
 
 #define PAC207_BRIGHTNESS_MIN          0
 #define PAC207_BRIGHTNESS_MAX          255
-#define PAC207_BRIGHTNESS_DEFAULT      4 /* power on default: 4 */
-
-/* An exposure value of 4 also works (3 does not) but then we need to lower
-   the compression balance setting when in 352x288 mode, otherwise the usb
-   bandwidth is not enough and packets get dropped resulting in corrupt
-   frames. The problem with this is that when the compression balance gets
-   lowered below 0x80, the pac207 starts using a different compression
-   algorithm for some lines, these lines get prefixed with a 0x2dd2 prefix
-   and currently we do not know how to decompress these lines, so for now
-   we use a minimum exposure value of 5 */
-#define PAC207_EXPOSURE_MIN            5
+#define PAC207_BRIGHTNESS_DEFAULT      46
+
+#define PAC207_EXPOSURE_MIN            3
 #define PAC207_EXPOSURE_MAX            26
-#define PAC207_EXPOSURE_DEFAULT                5 /* power on default: 3 ?? */
-#define PAC207_EXPOSURE_KNEE           11 /* 4 = 30 fps, 11 = 8, 15 = 6 */
+#define PAC207_EXPOSURE_DEFAULT                5 /* power on default: 3 */
+#define PAC207_EXPOSURE_KNEE           8 /* 4 = 30 fps, 11 = 8, 15 = 6 */
 
 #define PAC207_GAIN_MIN                        0
 #define PAC207_GAIN_MAX                        31
 #define PAC207_GAIN_DEFAULT            9 /* power on default: 9 */
-#define PAC207_GAIN_KNEE               20
+#define PAC207_GAIN_KNEE               31
 
 #define PAC207_AUTOGAIN_DEADZONE       30
 
@@ -166,16 +158,12 @@ static const struct v4l2_pix_format sif_mode[] = {
 };
 
 static const __u8 pac207_sensor_init[][8] = {
-       {0x10, 0x12, 0x0d, 0x12, 0x0c, 0x01, 0x29, 0xf0},
-       {0x00, 0x64, 0x64, 0x64, 0x04, 0x10, 0xf0, 0x30},
+       {0x10, 0x12, 0x0d, 0x12, 0x0c, 0x01, 0x29, 0x84},
+       {0x49, 0x64, 0x64, 0x64, 0x04, 0x10, 0xf0, 0x30},
        {0x00, 0x00, 0x00, 0x70, 0xa0, 0xf8, 0x00, 0x00},
-       {0x00, 0x00, 0x32, 0x00, 0x96, 0x00, 0xa2, 0x02},
        {0x32, 0x00, 0x96, 0x00, 0xA2, 0x02, 0xaf, 0x00},
 };
 
-                       /* 48 reg_72 Rate Control end BalSize_4a =0x36 */
-static const __u8 PacReg72[] = { 0x00, 0x00, 0x36, 0x00 };
-
 static int pac207_write_regs(struct gspca_dev *gspca_dev, u16 index,
        const u8 *buffer, u16 length)
 {
@@ -274,7 +262,6 @@ static int sd_init(struct gspca_dev *gspca_dev)
                                 * Bit_1=LED,
                                 * Bit_2=Compression test mode enable */
        pac207_write_reg(gspca_dev, 0x0f, 0x00); /* Power Control */
-       pac207_write_reg(gspca_dev, 0x11, 0x30); /* Analog Bias */
 
        return 0;
 }
@@ -289,15 +276,13 @@ static int sd_start(struct gspca_dev *gspca_dev)
        pac207_write_regs(gspca_dev, 0x0002, pac207_sensor_init[0], 8);
        pac207_write_regs(gspca_dev, 0x000a, pac207_sensor_init[1], 8);
        pac207_write_regs(gspca_dev, 0x0012, pac207_sensor_init[2], 8);
-       pac207_write_regs(gspca_dev, 0x0040, pac207_sensor_init[3], 8);
-       pac207_write_regs(gspca_dev, 0x0042, pac207_sensor_init[4], 8);
-       pac207_write_regs(gspca_dev, 0x0048, PacReg72, 4);
+       pac207_write_regs(gspca_dev, 0x0042, pac207_sensor_init[3], 8);
 
        /* Compression Balance */
        if (gspca_dev->width == 176)
                pac207_write_reg(gspca_dev, 0x4a, 0xff);
        else
-               pac207_write_reg(gspca_dev, 0x4a, 0x88);
+               pac207_write_reg(gspca_dev, 0x4a, 0x30);
        pac207_write_reg(gspca_dev, 0x4b, 0x00); /* Sram test value */
        pac207_write_reg(gspca_dev, 0x08, sd->brightness);
 
@@ -346,7 +331,7 @@ static void pac207_do_auto_gain(struct gspca_dev *gspca_dev)
        if (sd->autogain_ignore_frames > 0)
                sd->autogain_ignore_frames--;
        else if (gspca_auto_gain_n_exposure(gspca_dev, avg_lum,
-                       100 + sd->brightness / 2, PAC207_AUTOGAIN_DEADZONE,
+                       100, PAC207_AUTOGAIN_DEADZONE,
                        PAC207_GAIN_KNEE, PAC207_EXPOSURE_KNEE))
                sd->autogain_ignore_frames = PAC_AUTOGAIN_IGNORE_FRAMES;
 }
index e1e3a3a504845b1c3ea5b91ff8c31e2f427b7e41..052714484e83beecdcd398e7745d91ff37c97ca0 100644 (file)
@@ -1057,6 +1057,7 @@ static struct sd_desc sd_desc = {
 
 /* -- module initialisation -- */
 static __devinitdata struct usb_device_id device_table[] = {
+       {USB_DEVICE(0x06f8, 0x3009), .driver_info = SENSOR_PAC7302},
        {USB_DEVICE(0x093a, 0x2600), .driver_info = SENSOR_PAC7311},
        {USB_DEVICE(0x093a, 0x2601), .driver_info = SENSOR_PAC7311},
        {USB_DEVICE(0x093a, 0x2603), .driver_info = SENSOR_PAC7311},
@@ -1068,6 +1069,7 @@ static __devinitdata struct usb_device_id device_table[] = {
        {USB_DEVICE(0x093a, 0x2622), .driver_info = SENSOR_PAC7302},
        {USB_DEVICE(0x093a, 0x2624), .driver_info = SENSOR_PAC7302},
        {USB_DEVICE(0x093a, 0x2626), .driver_info = SENSOR_PAC7302},
+       {USB_DEVICE(0x093a, 0x2629), .driver_info = SENSOR_PAC7302},
        {USB_DEVICE(0x093a, 0x262a), .driver_info = SENSOR_PAC7302},
        {USB_DEVICE(0x093a, 0x262c), .driver_info = SENSOR_PAC7302},
        {}
index fcfbbd329b4c16266c0dcb993a1f401302de7622..cdad3db33367970fface102998fecf79cd2fcf57 100644 (file)
@@ -94,6 +94,16 @@ struct sd {
 #endif
 };
 
+struct i2c_reg_u8 {
+       u8 reg;
+       u8 val;
+};
+
+struct i2c_reg_u16 {
+       u8 reg;
+       u16 val;
+};
+
 static int sd_setbrightness(struct gspca_dev *gspca_dev, s32 val);
 static int sd_getbrightness(struct gspca_dev *gspca_dev, s32 *val);
 static int sd_setcontrast(struct gspca_dev *gspca_dev, s32 val);
@@ -403,7 +413,7 @@ static const struct v4l2_pix_format sxga_mode[] = {
                .priv = 3 | MODE_RAW | MODE_SXGA},
 };
 
-static const int hsv_red_x[] = {
+static const s16 hsv_red_x[] = {
        41,  44,  46,  48,  50,  52,  54,  56,
        58,  60,  62,  64,  66,  68,  70,  72,
        74,  76,  78,  80,  81,  83,  85,  87,
@@ -451,7 +461,7 @@ static const int hsv_red_x[] = {
        24,  26,  28,  30,  33,  35,  37,  39, 41
 };
 
-static const int hsv_red_y[] = {
+static const s16 hsv_red_y[] = {
        82,  80,  78,  76,  74,  73,  71,  69,
        67,  65,  63,  61,  58,  56,  54,  52,
        50,  48,  46,  44,  41,  39,  37,  35,
@@ -499,7 +509,7 @@ static const int hsv_red_y[] = {
        96, 94, 92, 91, 89, 87, 85, 84, 82
 };
 
-static const int hsv_green_x[] = {
+static const s16 hsv_green_x[] = {
        -124, -124, -125, -125, -125, -125, -125, -125,
        -125, -126, -126, -125, -125, -125, -125, -125,
        -125, -124, -124, -124, -123, -123, -122, -122,
@@ -547,7 +557,7 @@ static const int hsv_green_x[] = {
        -120, -120, -121, -122, -122, -123, -123, -124, -124
 };
 
-static const int hsv_green_y[] = {
+static const s16 hsv_green_y[] = {
        -100, -99, -98, -97, -95, -94, -93, -91,
        -90, -89, -87, -86, -84, -83, -81, -80,
        -78, -76, -75, -73, -71, -70, -68, -66,
@@ -595,7 +605,7 @@ static const int hsv_green_y[] = {
        -109, -108, -107, -106, -105, -104, -103, -102, -100
 };
 
-static const int hsv_blue_x[] = {
+static const s16 hsv_blue_x[] = {
        112, 113, 114, 114, 115, 116, 117, 117,
        118, 118, 119, 119, 120, 120, 120, 121,
        121, 121, 122, 122, 122, 122, 122, 122,
@@ -643,7 +653,7 @@ static const int hsv_blue_x[] = {
        104, 105, 106, 107, 108, 109, 110, 111, 112
 };
 
-static const int hsv_blue_y[] = {
+static const s16 hsv_blue_y[] = {
        -11, -13, -15, -17, -19, -21, -23, -25,
        -27, -29, -31, -33, -35, -37, -39, -41,
        -43, -45, -46, -48, -50, -52, -54, -55,
@@ -792,21 +802,21 @@ static u8 hv7131r_gain[] = {
        0x78 /* 8x */
 };
 
-static u8 soi968_init[][2] = {
+static struct i2c_reg_u8 soi968_init[] = {
        {0x12, 0x80}, {0x0c, 0x00}, {0x0f, 0x1f},
        {0x11, 0x80}, {0x38, 0x52}, {0x1e, 0x00},
        {0x33, 0x08}, {0x35, 0x8c}, {0x36, 0x0c},
        {0x37, 0x04}, {0x45, 0x04}, {0x47, 0xff},
        {0x3e, 0x00}, {0x3f, 0x00}, {0x3b, 0x20},
        {0x3a, 0x96}, {0x3d, 0x0a}, {0x14, 0x8e},
-       {0x13, 0x8a}, {0x12, 0x40}, {0x17, 0x13},
+       {0x13, 0x8b}, {0x12, 0x40}, {0x17, 0x13},
        {0x18, 0x63}, {0x19, 0x01}, {0x1a, 0x79},
        {0x32, 0x24}, {0x03, 0x00}, {0x11, 0x40},
        {0x2a, 0x10}, {0x2b, 0xe0}, {0x10, 0x32},
        {0x00, 0x00}, {0x01, 0x80}, {0x02, 0x80},
 };
 
-static u8 ov7660_init[][2] = {
+static struct i2c_reg_u8 ov7660_init[] = {
        {0x0e, 0x80}, {0x0d, 0x08}, {0x0f, 0xc3},
        {0x04, 0xc3}, {0x10, 0x40}, {0x11, 0x40},
        {0x12, 0x05}, {0x13, 0xba}, {0x14, 0x2a},
@@ -815,7 +825,7 @@ static u8 ov7660_init[][2] = {
        {0x2e, 0x0b}, {0x01, 0x78}, {0x02, 0x50},
 };
 
-static u8 ov7670_init[][2] = {
+static struct i2c_reg_u8 ov7670_init[] = {
        {0x12, 0x80}, {0x11, 0x80}, {0x3a, 0x04}, {0x12, 0x01},
        {0x32, 0xb6}, {0x03, 0x0a}, {0x0c, 0x00}, {0x3e, 0x00},
        {0x70, 0x3a}, {0x71, 0x35}, {0x72, 0x11}, {0x73, 0xf0},
@@ -872,7 +882,7 @@ static u8 ov7670_init[][2] = {
        {0x93, 0x00},
 };
 
-static u8 ov9650_init[][2] = {
+static struct i2c_reg_u8 ov9650_init[] = {
        {0x12, 0x80}, {0x00, 0x00}, {0x01, 0x78},
        {0x02, 0x78}, {0x03, 0x36}, {0x04, 0x03},
        {0x05, 0x00}, {0x06, 0x00}, {0x08, 0x00},
@@ -902,7 +912,7 @@ static u8 ov9650_init[][2] = {
        {0xaa, 0x92}, {0xab, 0x0a},
 };
 
-static u8 ov9655_init[][2] = {
+static struct i2c_reg_u8 ov9655_init[] = {
        {0x12, 0x80}, {0x12, 0x01}, {0x0d, 0x00}, {0x0e, 0x61},
        {0x11, 0x80}, {0x13, 0xba}, {0x14, 0x2e}, {0x16, 0x24},
        {0x1e, 0x04}, {0x1e, 0x04}, {0x1e, 0x04}, {0x27, 0x08},
@@ -939,7 +949,7 @@ static u8 ov9655_init[][2] = {
        {0x00, 0x03}, {0x00, 0x0a}, {0x00, 0x10}, {0x00, 0x13},
 };
 
-static u16 mt9v112_init[][2] = {
+static struct i2c_reg_u16 mt9v112_init[] = {
        {0xf0, 0x0000}, {0x0d, 0x0021}, {0x0d, 0x0020},
        {0x34, 0xc019}, {0x0a, 0x0011}, {0x0b, 0x000b},
        {0x20, 0x0703}, {0x35, 0x2022}, {0xf0, 0x0001},
@@ -958,7 +968,7 @@ static u16 mt9v112_init[][2] = {
        {0x2c, 0x00ae}, {0x2d, 0x00ae}, {0x2e, 0x00ae},
 };
 
-static u16 mt9v111_init[][2] = {
+static struct i2c_reg_u16 mt9v111_init[] = {
        {0x01, 0x0004}, {0x0d, 0x0001}, {0x0d, 0x0000},
        {0x01, 0x0001}, {0x02, 0x0016}, {0x03, 0x01e1},
        {0x04, 0x0281}, {0x05, 0x0004}, {0x07, 0x3002},
@@ -985,7 +995,7 @@ static u16 mt9v111_init[][2] = {
        {0x0e, 0x0008}, {0x06, 0x002d}, {0x05, 0x0004},
 };
 
-static u16 mt9v011_init[][2] = {
+static struct i2c_reg_u16 mt9v011_init[] = {
        {0x07, 0x0002}, {0x0d, 0x0001}, {0x0d, 0x0000},
        {0x01, 0x0008}, {0x02, 0x0016}, {0x03, 0x01e1},
        {0x04, 0x0281}, {0x05, 0x0083}, {0x06, 0x0006},
@@ -1012,7 +1022,7 @@ static u16 mt9v011_init[][2] = {
        {0x06, 0x0029}, {0x05, 0x0009},
 };
 
-static u16 mt9m001_init[][2] = {
+static struct i2c_reg_u16 mt9m001_init[] = {
        {0x0d, 0x0001}, {0x0d, 0x0000}, {0x01, 0x000e},
        {0x02, 0x0014}, {0x03, 0x03c1}, {0x04, 0x0501},
        {0x05, 0x0083}, {0x06, 0x0006}, {0x0d, 0x0002},
@@ -1025,14 +1035,14 @@ static u16 mt9m001_init[][2] = {
        {0x2e, 0x0029}, {0x07, 0x0002},
 };
 
-static u16 mt9m111_init[][2] = {
-       {0xf0, 0x0000}, {0x0d, 0x0008}, {0x0d, 0x0009},
-       {0x0d, 0x0008}, {0xf0, 0x0001}, {0x3a, 0x4300},
-       {0x9b, 0x4300}, {0xa1, 0x0280}, {0xa4, 0x0200},
-       {0x06, 0x308e}, {0xf0, 0x0000},
+static struct i2c_reg_u16 mt9m111_init[] = {
+       {0xf0, 0x0000}, {0x0d, 0x0021}, {0x0d, 0x0008},
+       {0xf0, 0x0001}, {0x3a, 0x4300}, {0x9b, 0x4300},
+       {0x06, 0x708e}, {0xf0, 0x0002}, {0x2e, 0x0a1e},
+       {0xf0, 0x0000},
 };
 
-static u8 hv7131r_init[][2] = {
+static struct i2c_reg_u8 hv7131r_init[] = {
        {0x02, 0x08}, {0x02, 0x00}, {0x01, 0x08},
        {0x02, 0x00}, {0x20, 0x00}, {0x21, 0xd0},
        {0x22, 0x00}, {0x23, 0x09}, {0x01, 0x08},
@@ -1043,7 +1053,7 @@ static u8 hv7131r_init[][2] = {
        {0x23, 0x09}, {0x01, 0x08},
 };
 
-int reg_r(struct gspca_dev *gspca_dev, u16 reg, u16 length)
+static int reg_r(struct gspca_dev *gspca_dev, u16 reg, u16 length)
 {
        struct usb_device *dev = gspca_dev->dev;
        int result;
@@ -1062,7 +1072,8 @@ int reg_r(struct gspca_dev *gspca_dev, u16 reg, u16 length)
        return 0;
 }
 
-int reg_w(struct gspca_dev *gspca_dev, u16 reg, const u8 *buffer, int length)
+static int reg_w(struct gspca_dev *gspca_dev, u16 reg,
+                const u8 *buffer, int length)
 {
        struct usb_device *dev = gspca_dev->dev;
        int result;
@@ -1082,13 +1093,13 @@ int reg_w(struct gspca_dev *gspca_dev, u16 reg, const u8 *buffer, int length)
        return 0;
 }
 
-int reg_w1(struct gspca_dev *gspca_dev, u16 reg, const u8 value)
+static int reg_w1(struct gspca_dev *gspca_dev, u16 reg, const u8 value)
 {
        u8 data[1] = {value};
        return reg_w(gspca_dev, reg, data, 1);
 }
 
-int i2c_w(struct gspca_dev *gspca_dev, const u8 *buffer)
+static int i2c_w(struct gspca_dev *gspca_dev, const u8 *buffer)
 {
        int i;
        reg_w(gspca_dev, 0x10c0, buffer, 8);
@@ -1096,15 +1107,15 @@ int i2c_w(struct gspca_dev *gspca_dev, const u8 *buffer)
                reg_r(gspca_dev, 0x10c0, 1);
                if (gspca_dev->usb_buf[0] & 0x04) {
                        if (gspca_dev->usb_buf[0] & 0x08)
-                               return -1;
+                               return -EIO;
                        return 0;
                }
                msleep(1);
        }
-       return -1;
+       return -EIO;
 }
 
-int i2c_w1(struct gspca_dev *gspca_dev, u8 reg, u8 val)
+static int i2c_w1(struct gspca_dev *gspca_dev, u8 reg, u8 val)
 {
        struct sd *sd = (struct sd *) gspca_dev;
 
@@ -1126,7 +1137,7 @@ int i2c_w1(struct gspca_dev *gspca_dev, u8 reg, u8 val)
        return i2c_w(gspca_dev, row);
 }
 
-int i2c_w2(struct gspca_dev *gspca_dev, u8 reg, u16 val)
+static int i2c_w2(struct gspca_dev *gspca_dev, u8 reg, u16 val)
 {
        struct sd *sd = (struct sd *) gspca_dev;
        u8 row[8];
@@ -1152,7 +1163,7 @@ int i2c_r1(struct gspca_dev *gspca_dev, u8 reg, u8 *val)
        struct sd *sd = (struct sd *) gspca_dev;
        u8 row[8];
 
-       row[0] = 0x81 | 0x10;
+       row[0] = 0x81 | (1 << 4);
        row[1] = sd->i2c_addr;
        row[2] = reg;
        row[3] = 0;
@@ -1160,14 +1171,15 @@ int i2c_r1(struct gspca_dev *gspca_dev, u8 reg, u8 *val)
        row[5] = 0;
        row[6] = 0;
        row[7] = 0x10;
-       reg_w(gspca_dev, 0x10c0, row, 8);
-       msleep(1);
-       row[0] = 0x81 | (2 << 4) | 0x02;
+       if (i2c_w(gspca_dev, row) < 0)
+               return -EIO;
+       row[0] = 0x81 | (1 << 4) | 0x02;
        row[2] = 0;
-       reg_w(gspca_dev, 0x10c0, row, 8);
-       msleep(1);
-       reg_r(gspca_dev, 0x10c2, 5);
-       *val = gspca_dev->usb_buf[3];
+       if (i2c_w(gspca_dev, row) < 0)
+               return -EIO;
+       if (reg_r(gspca_dev, 0x10c2, 5) < 0)
+               return -EIO;
+       *val = gspca_dev->usb_buf[4];
        return 0;
 }
 
@@ -1176,7 +1188,7 @@ int i2c_r2(struct gspca_dev *gspca_dev, u8 reg, u16 *val)
        struct sd *sd = (struct sd *) gspca_dev;
        u8 row[8];
 
-       row[0] = 0x81 | 0x10;
+       row[0] = 0x81 | (1 << 4);
        row[1] = sd->i2c_addr;
        row[2] = reg;
        row[3] = 0;
@@ -1184,14 +1196,15 @@ int i2c_r2(struct gspca_dev *gspca_dev, u8 reg, u16 *val)
        row[5] = 0;
        row[6] = 0;
        row[7] = 0x10;
-       reg_w(gspca_dev, 0x10c0, row, 8);
-       msleep(1);
-       row[0] = 0x81 | (3 << 4) | 0x02;
+       if (i2c_w(gspca_dev, row) < 0)
+               return -EIO;
+       row[0] = 0x81 | (2 << 4) | 0x02;
        row[2] = 0;
-       reg_w(gspca_dev, 0x10c0, row, 8);
-       msleep(1);
-       reg_r(gspca_dev, 0x10c2, 5);
-       *val = (gspca_dev->usb_buf[2] << 8) | gspca_dev->usb_buf[3];
+       if (i2c_w(gspca_dev, row) < 0)
+               return -EIO;
+       if (reg_r(gspca_dev, 0x10c2, 5) < 0)
+               return -EIO;
+       *val = (gspca_dev->usb_buf[3] << 8) | gspca_dev->usb_buf[4];
        return 0;
 }
 
@@ -1201,8 +1214,8 @@ static int ov9650_init_sensor(struct gspca_dev *gspca_dev)
        struct sd *sd = (struct sd *) gspca_dev;
 
        for (i = 0; i < ARRAY_SIZE(ov9650_init); i++) {
-               if (i2c_w1(gspca_dev, ov9650_init[i][0],
-                               ov9650_init[i][1]) < 0) {
+               if (i2c_w1(gspca_dev, ov9650_init[i].reg,
+                               ov9650_init[i].val) < 0) {
                        err("OV9650 sensor initialization failed");
                        return -ENODEV;
                }
@@ -1218,8 +1231,8 @@ static int ov9655_init_sensor(struct gspca_dev *gspca_dev)
        struct sd *sd = (struct sd *) gspca_dev;
 
        for (i = 0; i < ARRAY_SIZE(ov9655_init); i++) {
-               if (i2c_w1(gspca_dev, ov9655_init[i][0],
-                               ov9655_init[i][1]) < 0) {
+               if (i2c_w1(gspca_dev, ov9655_init[i].reg,
+                               ov9655_init[i].val) < 0) {
                        err("OV9655 sensor initialization failed");
                        return -ENODEV;
                }
@@ -1237,14 +1250,14 @@ static int soi968_init_sensor(struct gspca_dev *gspca_dev)
        struct sd *sd = (struct sd *) gspca_dev;
 
        for (i = 0; i < ARRAY_SIZE(soi968_init); i++) {
-               if (i2c_w1(gspca_dev, soi968_init[i][0],
-                               soi968_init[i][1]) < 0) {
+               if (i2c_w1(gspca_dev, soi968_init[i].reg,
+                               soi968_init[i].val) < 0) {
                        err("SOI968 sensor initialization failed");
                        return -ENODEV;
                }
        }
        /* disable hflip and vflip */
-       gspca_dev->ctrl_dis = (1 << HFLIP_IDX) | (1 << VFLIP_IDX);
+       gspca_dev->ctrl_dis = (1 << HFLIP_IDX) | (1 << VFLIP_IDX) | (1 << EXPOSURE_IDX);
        sd->hstart = 60;
        sd->vstart = 11;
        return 0;
@@ -1256,8 +1269,8 @@ static int ov7660_init_sensor(struct gspca_dev *gspca_dev)
        struct sd *sd = (struct sd *) gspca_dev;
 
        for (i = 0; i < ARRAY_SIZE(ov7660_init); i++) {
-               if (i2c_w1(gspca_dev, ov7660_init[i][0],
-                               ov7660_init[i][1]) < 0) {
+               if (i2c_w1(gspca_dev, ov7660_init[i].reg,
+                               ov7660_init[i].val) < 0) {
                        err("OV7660 sensor initialization failed");
                        return -ENODEV;
                }
@@ -1275,8 +1288,8 @@ static int ov7670_init_sensor(struct gspca_dev *gspca_dev)
        struct sd *sd = (struct sd *) gspca_dev;
 
        for (i = 0; i < ARRAY_SIZE(ov7670_init); i++) {
-               if (i2c_w1(gspca_dev, ov7670_init[i][0],
-                               ov7670_init[i][1]) < 0) {
+               if (i2c_w1(gspca_dev, ov7670_init[i].reg,
+                               ov7670_init[i].val) < 0) {
                        err("OV7670 sensor initialization failed");
                        return -ENODEV;
                }
@@ -1299,8 +1312,8 @@ static int mt9v_init_sensor(struct gspca_dev *gspca_dev)
        ret = i2c_r2(gspca_dev, 0xff, &value);
        if ((ret == 0) && (value == 0x8243)) {
                for (i = 0; i < ARRAY_SIZE(mt9v011_init); i++) {
-                       if (i2c_w2(gspca_dev, mt9v011_init[i][0],
-                                       mt9v011_init[i][1]) < 0) {
+                       if (i2c_w2(gspca_dev, mt9v011_init[i].reg,
+                                       mt9v011_init[i].val) < 0) {
                                err("MT9V011 sensor initialization failed");
                                return -ENODEV;
                        }
@@ -1317,8 +1330,8 @@ static int mt9v_init_sensor(struct gspca_dev *gspca_dev)
        ret = i2c_r2(gspca_dev, 0xff, &value);
        if ((ret == 0) && (value == 0x823a)) {
                for (i = 0; i < ARRAY_SIZE(mt9v111_init); i++) {
-                       if (i2c_w2(gspca_dev, mt9v111_init[i][0],
-                                       mt9v111_init[i][1]) < 0) {
+                       if (i2c_w2(gspca_dev, mt9v111_init[i].reg,
+                                       mt9v111_init[i].val) < 0) {
                                err("MT9V111 sensor initialization failed");
                                return -ENODEV;
                        }
@@ -1339,8 +1352,8 @@ static int mt9v_init_sensor(struct gspca_dev *gspca_dev)
        ret = i2c_r2(gspca_dev, 0x00, &value);
        if ((ret == 0) && (value == 0x1229)) {
                for (i = 0; i < ARRAY_SIZE(mt9v112_init); i++) {
-                       if (i2c_w2(gspca_dev, mt9v112_init[i][0],
-                                       mt9v112_init[i][1]) < 0) {
+                       if (i2c_w2(gspca_dev, mt9v112_init[i].reg,
+                                       mt9v112_init[i].val) < 0) {
                                err("MT9V112 sensor initialization failed");
                                return -ENODEV;
                        }
@@ -1360,12 +1373,13 @@ static int mt9m111_init_sensor(struct gspca_dev *gspca_dev)
        struct sd *sd = (struct sd *) gspca_dev;
        int i;
        for (i = 0; i < ARRAY_SIZE(mt9m111_init); i++) {
-               if (i2c_w2(gspca_dev, mt9m111_init[i][0],
-                               mt9m111_init[i][1]) < 0) {
+               if (i2c_w2(gspca_dev, mt9m111_init[i].reg,
+                               mt9m111_init[i].val) < 0) {
                        err("MT9M111 sensor initialization failed");
                        return -ENODEV;
                }
        }
+       gspca_dev->ctrl_dis = (1 << EXPOSURE_IDX) | (1 << AUTOGAIN_IDX) | (1 << GAIN_IDX);
        sd->hstart = 0;
        sd->vstart = 2;
        return 0;
@@ -1376,8 +1390,8 @@ static int mt9m001_init_sensor(struct gspca_dev *gspca_dev)
        struct sd *sd = (struct sd *) gspca_dev;
        int i;
        for (i = 0; i < ARRAY_SIZE(mt9m001_init); i++) {
-               if (i2c_w2(gspca_dev, mt9m001_init[i][0],
-                               mt9m001_init[i][1]) < 0) {
+               if (i2c_w2(gspca_dev, mt9m001_init[i].reg,
+                               mt9m001_init[i].val) < 0) {
                        err("MT9M001 sensor initialization failed");
                        return -ENODEV;
                }
@@ -1395,8 +1409,8 @@ static int hv7131r_init_sensor(struct gspca_dev *gspca_dev)
        struct sd *sd = (struct sd *) gspca_dev;
 
        for (i = 0; i < ARRAY_SIZE(hv7131r_init); i++) {
-               if (i2c_w1(gspca_dev, hv7131r_init[i][0],
-                               hv7131r_init[i][1]) < 0) {
+               if (i2c_w1(gspca_dev, hv7131r_init[i].reg,
+                               hv7131r_init[i].val) < 0) {
                        err("HV7131R Sensor initialization failed");
                        return -ENODEV;
                }
@@ -1620,7 +1634,6 @@ static int set_exposure(struct gspca_dev *gspca_dev)
        switch (sd->sensor) {
        case SENSOR_OV7660:
        case SENSOR_OV7670:
-       case SENSOR_SOI968:
        case SENSOR_OV9655:
        case SENSOR_OV9650:
                exp[0] |= (3 << 4);
@@ -1629,7 +1642,6 @@ static int set_exposure(struct gspca_dev *gspca_dev)
                exp[4] = sd->exposure >> 8;
                break;
        case SENSOR_MT9M001:
-       case SENSOR_MT9M111:
        case SENSOR_MT9V112:
        case SENSOR_MT9V111:
        case SENSOR_MT9V011:
@@ -1645,6 +1657,8 @@ static int set_exposure(struct gspca_dev *gspca_dev)
                exp[4] = ((sd->exposure * 0xffffff) / 0xffff) >> 8;
                exp[5] = ((sd->exposure * 0xffffff) / 0xffff) & 0xff;
                break;
+       default:
+               return 0;
        }
        i2c_w(gspca_dev, exp);
        return 0;
@@ -1671,7 +1685,6 @@ static int set_gain(struct gspca_dev *gspca_dev)
                gain[4] = micron1_gain[sd->gain] & 0xff;
                break;
        case SENSOR_MT9V112:
-       case SENSOR_MT9M111:
                gain[0] |= (3 << 4);
                gain[2] = 0x2f;
                gain[3] = micron1_gain[sd->gain] >> 8;
@@ -1688,6 +1701,8 @@ static int set_gain(struct gspca_dev *gspca_dev)
                gain[2] = 0x30;
                gain[3] = hv7131r_gain[sd->gain];
                break;
+       default:
+               return 0;
        }
        i2c_w(gspca_dev, gain);
        return 0;
@@ -1990,7 +2005,9 @@ static int sd_config(struct gspca_dev *gspca_dev,
        sd->i2c_addr = id->driver_info & 0xff;
 
        switch (sd->sensor) {
+       case SENSOR_MT9M111:
        case SENSOR_OV9650:
+       case SENSOR_SOI968:
                cam->cam_mode = sxga_mode;
                cam->nmodes = ARRAY_SIZE(sxga_mode);
                break;
@@ -2106,6 +2123,25 @@ static void configure_sensor_output(struct gspca_dev *gspca_dev, int mode)
        struct sd *sd = (struct sd *) gspca_dev;
        u8 value;
        switch (sd->sensor) {
+       case SENSOR_SOI968:
+               if (mode & MODE_SXGA) {
+                       i2c_w1(gspca_dev, 0x17, 0x1d);
+                       i2c_w1(gspca_dev, 0x18, 0xbd);
+                       i2c_w1(gspca_dev, 0x19, 0x01);
+                       i2c_w1(gspca_dev, 0x1a, 0x81);
+                       i2c_w1(gspca_dev, 0x12, 0x00);
+                       sd->hstart = 140;
+                       sd->vstart = 19;
+               } else {
+                       i2c_w1(gspca_dev, 0x17, 0x13);
+                       i2c_w1(gspca_dev, 0x18, 0x63);
+                       i2c_w1(gspca_dev, 0x19, 0x01);
+                       i2c_w1(gspca_dev, 0x1a, 0x79);
+                       i2c_w1(gspca_dev, 0x12, 0x40);
+                       sd->hstart = 60;
+                       sd->vstart = 11;
+               }
+               break;
        case SENSOR_OV9650:
                if (mode & MODE_SXGA) {
                        i2c_w1(gspca_dev, 0x17, 0x1b);
@@ -2123,6 +2159,17 @@ static void configure_sensor_output(struct gspca_dev *gspca_dev, int mode)
                        i2c_w1(gspca_dev, 0x12, (value & 0x7) | 0x40);
                }
                break;
+       case SENSOR_MT9M111:
+               if (mode & MODE_SXGA) {
+                       i2c_w2(gspca_dev, 0xf0, 0x0002);
+                       i2c_w2(gspca_dev, 0xc8, 0x970b);
+                       i2c_w2(gspca_dev, 0xf0, 0x0000);
+               } else {
+                       i2c_w2(gspca_dev, 0xf0, 0x0002);
+                       i2c_w2(gspca_dev, 0xc8, 0x8000);
+                       i2c_w2(gspca_dev, 0xf0, 0x0000);
+               }
+               break;
        }
 }
 
@@ -2211,15 +2258,10 @@ static void sd_stop0(struct gspca_dev *gspca_dev)
        kfree(sd->jpeg_hdr);
 }
 
-static void do_autoexposure(struct gspca_dev *gspca_dev)
+static void do_autoexposure(struct gspca_dev *gspca_dev, u16 avg_lum)
 {
        struct sd *sd = (struct sd *) gspca_dev;
-       int avg_lum, new_exp;
-
-       if (!sd->auto_exposure)
-               return;
-
-       avg_lum = atomic_read(&sd->avg_lum);
+       s16 new_exp;
 
        /*
         * some hardcoded values are present
@@ -2266,6 +2308,39 @@ static void do_autoexposure(struct gspca_dev *gspca_dev)
        }
 }
 
+static void do_autogain(struct gspca_dev *gspca_dev, u16 avg_lum)
+{
+       struct sd *sd = (struct sd *) gspca_dev;
+
+       if (avg_lum < MIN_AVG_LUM) {
+               if (sd->gain + 1 <= 28) {
+                       sd->gain++;
+                       set_gain(gspca_dev);
+               }
+       }
+       if (avg_lum > MAX_AVG_LUM) {
+               if (sd->gain - 1 >= 0) {
+                       sd->gain--;
+                       set_gain(gspca_dev);
+               }
+       }
+}
+
+static void sd_dqcallback(struct gspca_dev *gspca_dev)
+{
+       struct sd *sd = (struct sd *) gspca_dev;
+       int avg_lum;
+
+       if (!sd->auto_exposure)
+               return;
+
+       avg_lum = atomic_read(&sd->avg_lum);
+       if (sd->sensor == SENSOR_SOI968)
+               do_autogain(gspca_dev, avg_lum);
+       else
+               do_autoexposure(gspca_dev, avg_lum);
+}
+
 static void sd_pkt_scan(struct gspca_dev *gspca_dev,
                        struct gspca_frame *frame,      /* target */
                        u8 *data,                       /* isoc packet */
@@ -2333,7 +2408,7 @@ static const struct sd_desc sd_desc = {
        .stopN = sd_stopN,
        .stop0 = sd_stop0,
        .pkt_scan = sd_pkt_scan,
-       .dq_callback = do_autoexposure,
+       .dq_callback = sd_dqcallback,
 #ifdef CONFIG_VIDEO_ADV_DEBUG
        .set_register = sd_dbg_s_register,
        .get_register = sd_dbg_g_register,
index d6332ab80669218cdfa1d5b0fdd3a61874be9fc5..33f4d0a1f6fd5f54a9d596887c1062e32a52ae52 100644 (file)
@@ -727,7 +727,7 @@ static const u8 ov7660_sensor_init[][8] = {
        {0xa1, 0x21, 0x12, 0x05, 0x00, 0x00, 0x00, 0x10},
                                                /* Outformat = rawRGB */
        {0xa1, 0x21, 0x13, 0xb8, 0x00, 0x00, 0x00, 0x10}, /* init COM8 */
-       {0xd1, 0x21, 0x00, 0x01, 0x74, 0x74, 0x00, 0x10},
+       {0xd1, 0x21, 0x00, 0x01, 0x74, 0x92, 0x00, 0x10},
                                                /* GAIN BLUE RED VREF */
        {0xd1, 0x21, 0x04, 0x00, 0x7d, 0x62, 0x00, 0x10},
                                                /* COM 1 BAVE GEAVE AECHH */
@@ -783,7 +783,7 @@ static const u8 ov7660_sensor_init[][8] = {
        {0xc1, 0x21, 0x88, 0xaf, 0xc7, 0xdf, 0x00, 0x10}, /* gamma curve */
        {0xc1, 0x21, 0x8b, 0x99, 0x99, 0xcf, 0x00, 0x10}, /* reserved */
        {0xb1, 0x21, 0x92, 0x00, 0x00, 0x00, 0x00, 0x10}, /* DM_LNL/H */
-       {0xb1, 0x21, 0xa1, 0x00, 0x00, 0x00, 0x00, 0x10},
+       {0xa1, 0x21, 0xa1, 0x00, 0x00, 0x00, 0x00, 0x10},
 /****** (some exchanges in the win trace) ******/
        {0xa1, 0x21, 0x1e, 0x01, 0x00, 0x00, 0x00, 0x10}, /* MVFP */
                                                /* bits[3..0]reserved */
@@ -1145,17 +1145,12 @@ static int configure_gpio(struct gspca_dev *gspca_dev,
                reg_w1(gspca_dev, 0x01, 0x42);
                break;
        case SENSOR_OV7660:
-               reg_w1(gspca_dev, 0x01, 0x61);
-               reg_w1(gspca_dev, 0x17, 0x20);
-               reg_w1(gspca_dev, 0x01, 0x60);
-               reg_w1(gspca_dev, 0x01, 0x40);
-               break;
        case SENSOR_SP80708:
                reg_w1(gspca_dev, 0x01, 0x63);
                reg_w1(gspca_dev, 0x17, 0x20);
                reg_w1(gspca_dev, 0x01, 0x62);
                reg_w1(gspca_dev, 0x01, 0x42);
-               mdelay(100);
+               msleep(100);
                reg_w1(gspca_dev, 0x02, 0x62);
                break;
 /*     case SENSOR_HV7131R: */
@@ -1624,6 +1619,8 @@ static void setvflip(struct sd *sd)
 
 static void setinfrared(struct sd *sd)
 {
+       if (sd->gspca_dev.ctrl_dis & (1 << INFRARED_IDX))
+               return;
 /*fixme: different sequence for StarCam Clip and StarCam 370i */
 /* Clip */
        i2c_w1(&sd->gspca_dev, 0x02,                    /* gpio */
@@ -1637,16 +1634,19 @@ static void setfreq(struct gspca_dev *gspca_dev)
        if (gspca_dev->ctrl_dis & (1 << FREQ_IDX))
                return;
        if (sd->sensor == SENSOR_OV7660) {
+               u8 com8;
+
+               com8 = 0xdf;            /* auto gain/wb/expo */
                switch (sd->freq) {
                case 0: /* Banding filter disabled */
-                       i2c_w1(gspca_dev, 0x13, 0xdf);
+                       i2c_w1(gspca_dev, 0x13, com8 | 0x20);
                        break;
                case 1: /* 50 hz */
-                       i2c_w1(gspca_dev, 0x13, 0xff);
+                       i2c_w1(gspca_dev, 0x13, com8);
                        i2c_w1(gspca_dev, 0x3b, 0x0a);
                        break;
                case 2: /* 60 hz */
-                       i2c_w1(gspca_dev, 0x13, 0xff);
+                       i2c_w1(gspca_dev, 0x13, com8);
                        i2c_w1(gspca_dev, 0x3b, 0x02);
                        break;
                }
@@ -1796,12 +1796,6 @@ static int sd_start(struct gspca_dev *gspca_dev)
                reg_w1(gspca_dev, 0x99, 0x60);
                break;
        case SENSOR_OV7660:
-               reg_w1(gspca_dev, 0x9a, 0x05);
-               if (sd->bridge == BRIDGE_SN9C105)
-                       reg_w1(gspca_dev, 0x99, 0xff);
-               else
-                       reg_w1(gspca_dev, 0x99, 0x5b);
-               break;
        case SENSOR_SP80708:
                reg_w1(gspca_dev, 0x9a, 0x05);
                reg_w1(gspca_dev, 0x99, 0x59);
@@ -2325,18 +2319,19 @@ static const __devinitdata struct usb_device_id device_table[] = {
        {USB_DEVICE(0x0c45, 0x607c), BSI(SN9C102P, HV7131R, 0x11)},
 /*     {USB_DEVICE(0x0c45, 0x607e), BSI(SN9C102P, OV7630, 0x??)}, */
        {USB_DEVICE(0x0c45, 0x60c0), BSI(SN9C105, MI0360, 0x5d)},
-/*     {USB_DEVICE(0x0c45, 0x60c8), BSI(SN9C105, OM6801, 0x??)}, */
+/*     {USB_DEVICE(0x0c45, 0x60c8), BSI(SN9C105, OM6802, 0x??)}, */
 /*     {USB_DEVICE(0x0c45, 0x60cc), BSI(SN9C105, HV7131GP, 0x??)}, */
        {USB_DEVICE(0x0c45, 0x60ec), BSI(SN9C105, MO4000, 0x21)},
 /*     {USB_DEVICE(0x0c45, 0x60ef), BSI(SN9C105, ICM105C, 0x??)}, */
 /*     {USB_DEVICE(0x0c45, 0x60fa), BSI(SN9C105, OV7648, 0x??)}, */
        {USB_DEVICE(0x0c45, 0x60fb), BSI(SN9C105, OV7660, 0x21)},
-       {USB_DEVICE(0x0c45, 0x60fc), BSI(SN9C105, HV7131R, 0x11)},
 #if !defined CONFIG_USB_SN9C102 && !defined CONFIG_USB_SN9C102_MODULE
+       {USB_DEVICE(0x0c45, 0x60fc), BSI(SN9C105, HV7131R, 0x11)},
        {USB_DEVICE(0x0c45, 0x60fe), BSI(SN9C105, OV7630, 0x21)},
 #endif
        {USB_DEVICE(0x0c45, 0x6100), BSI(SN9C120, MI0360, 0x5d)}, /*sn9c128*/
-/*     {USB_DEVICE(0x0c45, 0x6108), BSI(SN9C120, OM6801, 0x??)}, */
+/*     {USB_DEVICE(0x0c45, 0x6102), BSI(SN9C120, PO2030N, ??)}, */
+/*     {USB_DEVICE(0x0c45, 0x6108), BSI(SN9C120, OM6802, 0x21)}, */
        {USB_DEVICE(0x0c45, 0x610a), BSI(SN9C120, OV7648, 0x21)}, /*sn9c128*/
        {USB_DEVICE(0x0c45, 0x610b), BSI(SN9C120, OV7660, 0x21)}, /*sn9c128*/
        {USB_DEVICE(0x0c45, 0x610c), BSI(SN9C120, HV7131R, 0x11)}, /*sn9c128*/
@@ -2352,6 +2347,7 @@ static const __devinitdata struct usb_device_id device_table[] = {
 #if !defined CONFIG_USB_SN9C102 && !defined CONFIG_USB_SN9C102_MODULE
        {USB_DEVICE(0x0c45, 0x6130), BSI(SN9C120, MI0360, 0x5d)},
 #endif
+/*     {USB_DEVICE(0x0c45, 0x6132), BSI(SN9C120, OV7670, 0x21)}, */
        {USB_DEVICE(0x0c45, 0x6138), BSI(SN9C120, MO4000, 0x21)},
        {USB_DEVICE(0x0c45, 0x613a), BSI(SN9C120, OV7648, 0x21)},
 #if !defined CONFIG_USB_SN9C102 && !defined CONFIG_USB_SN9C102_MODULE
@@ -2359,7 +2355,9 @@ static const __devinitdata struct usb_device_id device_table[] = {
 #endif
        {USB_DEVICE(0x0c45, 0x613c), BSI(SN9C120, HV7131R, 0x11)},
        {USB_DEVICE(0x0c45, 0x613e), BSI(SN9C120, OV7630, 0x21)},
-       {USB_DEVICE(0x0c45, 0x6143), BSI(SN9C120, SP80708, 0x18)},
+/*     {USB_DEVICE(0x0c45, 0x6142), BSI(SN9C120, PO2030N, ??)}, *sn9c120b*/
+       {USB_DEVICE(0x0c45, 0x6143), BSI(SN9C120, SP80708, 0x18)}, /*sn9c120b*/
+       {USB_DEVICE(0x0c45, 0x6148), BSI(SN9C120, OM6802, 0x21)}, /*sn9c120b*/
        {}
 };
 MODULE_DEVICE_TABLE(usb, device_table);
index d48b27c648ca553b1e355fb0b2abed64b498d9e0..b74a34218da05034f3ae77bc86b64e2bc8f9b8d1 100644 (file)
@@ -1923,7 +1923,7 @@ static int sd_config(struct gspca_dev *gspca_dev,
 
        cam = &gspca_dev->cam;
        cam->cam_mode = vga_mode;
-       cam->nmodes = sizeof vga_mode / sizeof vga_mode[0];
+       cam->nmodes = ARRAY_SIZE(vga_mode);
        sd->subtype = id->driver_info;
        sd->brightness = sd_ctrls[MY_BRIGHTNESS].qctrl.default_value;
        sd->contrast = sd_ctrls[MY_CONTRAST].qctrl.default_value;
index 3a0c893f942da2cdbeb5b388f85f76e48ced6c4f..a199298a6419a4fef681cb50f5a446c1f094cab0 100644 (file)
@@ -286,7 +286,7 @@ static int sd_config(struct gspca_dev *gspca_dev,
 
        cam = &gspca_dev->cam;
        cam->cam_mode = vga_mode;
-       cam->nmodes = sizeof vga_mode / sizeof vga_mode[0];
+       cam->nmodes = ARRAY_SIZE(vga_mode);
        sd->brightness = sd_ctrls[SD_BRIGHTNESS].qctrl.default_value;
        sd->contrast = sd_ctrls[SD_CONTRAST].qctrl.default_value;
        sd->colors = sd_ctrls[SD_COLOR].qctrl.default_value;
index 2ed2669bac3ed178bdcfde8b36e50b7470ee3111..9696c4caf5c931d70f2be9d42c71b516e093dd35 100644 (file)
@@ -1304,19 +1304,70 @@ static int reg_read(struct gspca_dev *gspca_dev,
        return gspca_dev->usb_buf[0];
 }
 
+/* send 1 or 2 bytes to the sensor via the Synchronous Serial Interface */
+static int ssi_w(struct gspca_dev *gspca_dev,
+               u16 reg, u16 val)
+{
+       struct usb_device *dev = gspca_dev->dev;
+       int ret, retry;
+
+       ret = reg_write(dev, 0x8802, reg >> 8);
+       if (ret < 0)
+               goto out;
+       ret = reg_write(dev, 0x8801, reg & 0x00ff);
+       if (ret < 0)
+               goto out;
+       if ((reg & 0xff00) == 0x1000) {         /* if 2 bytes */
+               ret = reg_write(dev, 0x8805, val & 0x00ff);
+               if (ret < 0)
+                       goto out;
+               val >>= 8;
+       }
+       ret = reg_write(dev, 0x8800, val);
+       if (ret < 0)
+               goto out;
+
+       /* poll until not busy */
+       retry = 10;
+       for (;;) {
+               ret = reg_read(gspca_dev, 0x8803);
+               if (ret < 0)
+                       break;
+               if (gspca_dev->usb_buf[0] == 0)
+                       break;
+               if (--retry <= 0) {
+                       PDEBUG(D_ERR, "ssi_w busy %02x",
+                                       gspca_dev->usb_buf[0]);
+                       ret = -1;
+                       break;
+               }
+               msleep(8);
+       }
+
+out:
+       return ret;
+}
+
 static int write_vector(struct gspca_dev *gspca_dev,
                        const u16 (*data)[2])
 {
        struct usb_device *dev = gspca_dev->dev;
-       int ret;
+       int ret = 0;
 
        while ((*data)[1] != 0) {
-               ret = reg_write(dev, (*data)[1], (*data)[0]);
+               if ((*data)[1] & 0x8000) {
+                       if ((*data)[1] == 0xdd00)       /* delay */
+                               msleep((*data)[0]);
+                       else
+                               ret = reg_write(dev, (*data)[1], (*data)[0]);
+               } else {
+                       ret = ssi_w(gspca_dev, (*data)[1], (*data)[0]);
+               }
                if (ret < 0)
-                       return ret;
+                       break;
                data++;
        }
-       return 0;
+       return ret;
 }
 
 /* this function is called at probe time */
index 0da8e0de04566a246213f31408900800e72f6826..7af511b5e9c26a849aa9db63b591e6b078cc2cbc 100644 (file)
@@ -130,8 +130,8 @@ int stv06xx_write_sensor_bytes(struct sd *sd, const u8 *data, u8 len)
                                      STV06XX_URB_MSG_TIMEOUT);
                                      if (err < 0)
                                        return err;
-       }
-       return stv06xx_write_sensor_finish(sd);
+       }
+       return stv06xx_write_sensor_finish(sd);
 }
 
 int stv06xx_write_sensor_words(struct sd *sd, const u16 *data, u8 len)
index 5127bbf9dd260ed519397f535953c830e67d16ea..aa8f995ce04ec1f263df04e1b123923fc2689ca8 100644 (file)
@@ -32,26 +32,27 @@ MODULE_LICENSE("GPL");
 struct sd {
        struct gspca_dev gspca_dev;     /* !! must be the first item */
 
-       unsigned char brightness;
-       unsigned char contrast;
-       unsigned char colors;
-       unsigned char autogain;
+       s8 brightness;
+       u8 contrast;
+       u8 colors;
+       u8 autogain;
        u8 quality;
 #define QUALITY_MIN 70
 #define QUALITY_MAX 95
 #define QUALITY_DEF 85
 
-       char bridge;
+       u8 bridge;
 #define BRIDGE_SPCA504 0
 #define BRIDGE_SPCA504B 1
 #define BRIDGE_SPCA504C 2
 #define BRIDGE_SPCA533 3
 #define BRIDGE_SPCA536 4
-       char subtype;
+       u8 subtype;
 #define AiptekMiniPenCam13 1
 #define LogitechClickSmart420 2
 #define LogitechClickSmart820 3
 #define MegapixV4 4
+#define MegaImageVI 5
 
        u8 *jpeg_hdr;
 };
@@ -67,21 +68,20 @@ static int sd_setautogain(struct gspca_dev *gspca_dev, __s32 val);
 static int sd_getautogain(struct gspca_dev *gspca_dev, __s32 *val);
 
 static struct ctrl sd_ctrls[] = {
-#define SD_BRIGHTNESS 0
        {
            {
                .id      = V4L2_CID_BRIGHTNESS,
                .type    = V4L2_CTRL_TYPE_INTEGER,
                .name    = "Brightness",
-               .minimum = 0,
-               .maximum = 0xff,
+               .minimum = -128,
+               .maximum = 127,
                .step    = 1,
-               .default_value = 0,
+#define BRIGHTNESS_DEF 0
+               .default_value = BRIGHTNESS_DEF,
            },
            .set = sd_setbrightness,
            .get = sd_getbrightness,
        },
-#define SD_CONTRAST 1
        {
            {
                .id      = V4L2_CID_CONTRAST,
@@ -90,12 +90,12 @@ static struct ctrl sd_ctrls[] = {
                .minimum = 0,
                .maximum = 0xff,
                .step    = 1,
-               .default_value = 0x20,
+#define CONTRAST_DEF 0x20
+               .default_value = CONTRAST_DEF,
            },
            .set = sd_setcontrast,
            .get = sd_getcontrast,
        },
-#define SD_COLOR 2
        {
            {
                .id      = V4L2_CID_SATURATION,
@@ -104,12 +104,12 @@ static struct ctrl sd_ctrls[] = {
                .minimum = 0,
                .maximum = 0xff,
                .step    = 1,
-               .default_value = 0x1a,
+#define COLOR_DEF 0x1a
+               .default_value = COLOR_DEF,
            },
            .set = sd_setcolors,
            .get = sd_getcolors,
        },
-#define SD_AUTOGAIN 3
        {
            {
                .id      = V4L2_CID_AUTOGAIN,
@@ -118,7 +118,8 @@ static struct ctrl sd_ctrls[] = {
                .minimum = 0,
                .maximum = 1,
                .step    = 1,
-               .default_value = 1,
+#define AUTOGAIN_DEF 1
+               .default_value = AUTOGAIN_DEF,
            },
            .set = sd_setautogain,
            .get = sd_getautogain,
@@ -180,14 +181,20 @@ static const struct v4l2_pix_format vga_mode2[] = {
 #define SPCA504_PCCAM600_OFFSET_MODE    5
 #define SPCA504_PCCAM600_OFFSET_DATA    14
  /* Frame packet header offsets for the spca533 */
-#define SPCA533_OFFSET_DATA      16
+#define SPCA533_OFFSET_DATA    16
 #define SPCA533_OFFSET_FRAMSEQ 15
 /* Frame packet header offsets for the spca536 */
-#define SPCA536_OFFSET_DATA      4
-#define SPCA536_OFFSET_FRAMSEQ  1
+#define SPCA536_OFFSET_DATA    4
+#define SPCA536_OFFSET_FRAMSEQ 1
+
+struct cmd {
+       u8 req;
+       u16 val;
+       u16 idx;
+};
 
 /* Initialisation data for the Creative PC-CAM 600 */
-static const __u16 spca504_pccam600_init_data[][3] = {
+static const struct cmd spca504_pccam600_init_data[] = {
 /*     {0xa0, 0x0000, 0x0503},  * capture mode */
        {0x00, 0x0000, 0x2000},
        {0x00, 0x0013, 0x2301},
@@ -211,22 +218,20 @@ static const __u16 spca504_pccam600_init_data[][3] = {
        {0x00, 0x0003, 0x2000},
        {0x00, 0x0013, 0x2301},
        {0x00, 0x0003, 0x2000},
-       {}
 };
 
 /* Creative PC-CAM 600 specific open data, sent before using the
  * generic initialisation data from spca504_open_data.
  */
-static const __u16 spca504_pccam600_open_data[][3] = {
+static const struct cmd spca504_pccam600_open_data[] = {
        {0x00, 0x0001, 0x2501},
        {0x20, 0x0500, 0x0001}, /* snapshot mode */
        {0x00, 0x0003, 0x2880},
        {0x00, 0x0001, 0x2881},
-       {}
 };
 
 /* Initialisation data for the logitech clicksmart 420 */
-static const __u16 spca504A_clicksmart420_init_data[][3] = {
+static const struct cmd spca504A_clicksmart420_init_data[] = {
 /*     {0xa0, 0x0000, 0x0503},  * capture mode */
        {0x00, 0x0000, 0x2000},
        {0x00, 0x0013, 0x2301},
@@ -243,7 +248,7 @@ static const __u16 spca504A_clicksmart420_init_data[][3] = {
        {0xb0, 0x0001, 0x0000},
 
 
-       {0x0a1, 0x0080, 0x0001},
+       {0xa1, 0x0080, 0x0001},
        {0x30, 0x0049, 0x0000},
        {0x30, 0x0060, 0x0005},
        {0x0c, 0x0004, 0x0000},
@@ -253,11 +258,10 @@ static const __u16 spca504A_clicksmart420_init_data[][3] = {
        {0x00, 0x0003, 0x2000},
        {0x00, 0x0000, 0x2000},
 
-       {}
 };
 
 /* clicksmart 420 open data ? */
-static const __u16 spca504A_clicksmart420_open_data[][3] = {
+static const struct cmd spca504A_clicksmart420_open_data[] = {
        {0x00, 0x0001, 0x2501},
        {0x20, 0x0502, 0x0000},
        {0x06, 0x0000, 0x0000},
@@ -401,10 +405,9 @@ static const __u16 spca504A_clicksmart420_open_data[][3] = {
        {0x00, 0x0028, 0x287f},
 
        {0xa0, 0x0000, 0x0503},
-       {}
 };
 
-static const __u8 qtable_creative_pccam[2][64] = {
+static const u8 qtable_creative_pccam[2][64] = {
        {                               /* Q-table Y-components */
         0x05, 0x03, 0x03, 0x05, 0x07, 0x0c, 0x0f, 0x12,
         0x04, 0x04, 0x04, 0x06, 0x08, 0x11, 0x12, 0x11,
@@ -429,7 +432,7 @@ static const __u8 qtable_creative_pccam[2][64] = {
  *             except for one byte. Possibly a typo?
  *             NWG: 18/05/2003.
  */
-static const __u8 qtable_spca504_default[2][64] = {
+static const u8 qtable_spca504_default[2][64] = {
        {                               /* Q-table Y-components */
         0x05, 0x03, 0x03, 0x05, 0x07, 0x0c, 0x0f, 0x12,
         0x04, 0x04, 0x04, 0x06, 0x08, 0x11, 0x12, 0x11,
@@ -453,9 +456,9 @@ static const __u8 qtable_spca504_default[2][64] = {
 
 /* read <len> bytes to gspca_dev->usb_buf */
 static void reg_r(struct gspca_dev *gspca_dev,
-                 __u16 req,
-                 __u16 index,
-                 __u16 len)
+                 u8 req,
+                 u16 index,
+                 u16 len)
 {
 #ifdef GSPCA_DEBUG
        if (len > USB_BUF_SZ) {
@@ -473,31 +476,26 @@ static void reg_r(struct gspca_dev *gspca_dev,
                        500);
 }
 
-/* write <len> bytes from gspca_dev->usb_buf */
-static void reg_w(struct gspca_dev *gspca_dev,
-                  __u16 req,
-                  __u16 value,
-                  __u16 index,
-                  __u16 len)
+/* write one byte */
+static void reg_w_1(struct gspca_dev *gspca_dev,
+                  u8 req,
+                  u16 value,
+                  u16 index,
+                  u16 byte)
 {
-#ifdef GSPCA_DEBUG
-       if (len > USB_BUF_SZ) {
-               err("reg_w: buffer overflow");
-               return;
-       }
-#endif
+       gspca_dev->usb_buf[0] = byte;
        usb_control_msg(gspca_dev->dev,
                        usb_sndctrlpipe(gspca_dev->dev, 0),
                        req,
                        USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
                        value, index,
-                       len ? gspca_dev->usb_buf : NULL, len,
+                       gspca_dev->usb_buf, 1,
                        500);
 }
 
 /* write req / index / value */
 static int reg_w_riv(struct usb_device *dev,
-                    __u16 req, __u16 index, __u16 value)
+                    u8 req, u16 index, u16 value)
 {
        int ret;
 
@@ -515,7 +513,7 @@ static int reg_w_riv(struct usb_device *dev,
 
 /* read 1 byte */
 static int reg_r_1(struct gspca_dev *gspca_dev,
-                       __u16 value)    /* wValue */
+                       u16 value)      /* wValue */
 {
        int ret;
 
@@ -536,9 +534,9 @@ static int reg_r_1(struct gspca_dev *gspca_dev,
 
 /* read 1 or 2 bytes - returns < 0 if error */
 static int reg_r_12(struct gspca_dev *gspca_dev,
-                       __u16 req,      /* bRequest */
-                       __u16 index,    /* wIndex */
-                       __u16 length)   /* wLength (1 or 2 only) */
+                       u8 req,         /* bRequest */
+                       u16 index,      /* wIndex */
+                       u16 length)     /* wLength (1 or 2 only) */
 {
        int ret;
 
@@ -559,43 +557,40 @@ static int reg_r_12(struct gspca_dev *gspca_dev,
 }
 
 static int write_vector(struct gspca_dev *gspca_dev,
-                       const __u16 data[][3])
+                       const struct cmd *data, int ncmds)
 {
        struct usb_device *dev = gspca_dev->dev;
-       int ret, i = 0;
+       int ret;
 
-       while (data[i][0] != 0 || data[i][1] != 0 || data[i][2] != 0) {
-               ret = reg_w_riv(dev, data[i][0], data[i][2], data[i][1]);
+       while (--ncmds >= 0) {
+               ret = reg_w_riv(dev, data->req, data->idx, data->val);
                if (ret < 0) {
                        PDEBUG(D_ERR,
-                               "Register write failed for 0x%x,0x%x,0x%x",
-                               data[i][0], data[i][1], data[i][2]);
+                          "Register write failed for 0x%02x, 0x%04x, 0x%04x",
+                               data->req, data->val, data->idx);
                        return ret;
                }
-               i++;
+               data++;
        }
        return 0;
 }
 
 static int spca50x_setup_qtable(struct gspca_dev *gspca_dev,
-                               unsigned int request,
-                               unsigned int ybase,
-                               unsigned int cbase,
-                               const __u8 qtable[2][64])
+                               const u8 qtable[2][64])
 {
        struct usb_device *dev = gspca_dev->dev;
        int i, err;
 
        /* loop over y components */
        for (i = 0; i < 64; i++) {
-               err = reg_w_riv(dev, request, ybase + i, qtable[0][i]);
+               err = reg_w_riv(dev, 0x00, 0x2800 + i, qtable[0][i]);
                if (err < 0)
                        return err;
        }
 
        /* loop over c components */
        for (i = 0; i < 64; i++) {
-               err = reg_w_riv(dev, request, cbase + i, qtable[1][i]);
+               err = reg_w_riv(dev, 0x00, 0x2840 + i, qtable[1][i]);
                if (err < 0)
                        return err;
        }
@@ -603,34 +598,34 @@ static int spca50x_setup_qtable(struct gspca_dev *gspca_dev,
 }
 
 static void spca504_acknowledged_command(struct gspca_dev *gspca_dev,
-                            __u16 req, __u16 idx, __u16 val)
+                            u8 req, u16 idx, u16 val)
 {
        struct usb_device *dev = gspca_dev->dev;
-       __u8 notdone;
+       int notdone;
 
        reg_w_riv(dev, req, idx, val);
        notdone = reg_r_12(gspca_dev, 0x01, 0x0001, 1);
        reg_w_riv(dev, req, idx, val);
 
-       PDEBUG(D_FRAM, "before wait 0x%x", notdone);
+       PDEBUG(D_FRAM, "before wait 0x%04x", notdone);
 
        msleep(200);
        notdone = reg_r_12(gspca_dev, 0x01, 0x0001, 1);
-       PDEBUG(D_FRAM, "after wait 0x%x", notdone);
+       PDEBUG(D_FRAM, "after wait 0x%04x", notdone);
 }
 
 static void spca504A_acknowledged_command(struct gspca_dev *gspca_dev,
-                       __u16 req,
-                       __u16 idx, __u16 val, __u8 stat, __u8 count)
+                       u8 req,
+                       u16 idx, u16 val, u8 stat, u8 count)
 {
        struct usb_device *dev = gspca_dev->dev;
-       __u8 status;
-       __u8 endcode;
+       int status;
+       u8 endcode;
 
        reg_w_riv(dev, req, idx, val);
        status = reg_r_12(gspca_dev, 0x01, 0x0001, 1);
        endcode = stat;
-       PDEBUG(D_FRAM, "Status 0x%x Need 0x%x", status, stat);
+       PDEBUG(D_FRAM, "Status 0x%x Need 0x%04x", status, stat);
        if (!count)
                return;
        count = 200;
@@ -640,7 +635,7 @@ static void spca504A_acknowledged_command(struct gspca_dev *gspca_dev,
 /*             reg_w_riv(dev, req, idx, val); */
                status = reg_r_12(gspca_dev, 0x01, 0x0001, 1);
                if (status == endcode) {
-                       PDEBUG(D_FRAM, "status 0x%x after wait 0x%x",
+                       PDEBUG(D_FRAM, "status 0x%04x after wait %d",
                                status, 200 - count);
                                break;
                }
@@ -667,8 +662,7 @@ static void spca504B_WaitCmdStatus(struct gspca_dev *gspca_dev)
        while (--count > 0) {
                reg_r(gspca_dev, 0x21, 1, 1);
                if (gspca_dev->usb_buf[0] != 0) {
-                       gspca_dev->usb_buf[0] = 0;
-                       reg_w(gspca_dev, 0x21, 0, 1, 1);
+                       reg_w_1(gspca_dev, 0x21, 0, 1, 0);
                        reg_r(gspca_dev, 0x21, 1, 1);
                        spca504B_PollingDataReady(gspca_dev);
                        break;
@@ -679,7 +673,7 @@ static void spca504B_WaitCmdStatus(struct gspca_dev *gspca_dev)
 
 static void spca50x_GetFirmware(struct gspca_dev *gspca_dev)
 {
-       __u8 *data;
+       u8 *data;
 
        data = gspca_dev->usb_buf;
        reg_r(gspca_dev, 0x20, 0, 5);
@@ -693,41 +687,34 @@ static void spca504B_SetSizeType(struct gspca_dev *gspca_dev)
 {
        struct sd *sd = (struct sd *) gspca_dev;
        struct usb_device *dev = gspca_dev->dev;
-       __u8 Size;
-       __u8 Type;
+       u8 Size;
        int rc;
 
-       Size = gspca_dev->cam.cam_mode[(int) gspca_dev->curr_mode].priv;
-       Type = 0;
+       Size = gspca_dev->cam.cam_mode[gspca_dev->curr_mode].priv;
        switch (sd->bridge) {
        case BRIDGE_SPCA533:
-               reg_w(gspca_dev, 0x31, 0, 0, 0);
+               reg_w_riv(dev, 0x31, 0, 0);
                spca504B_WaitCmdStatus(gspca_dev);
                rc = spca504B_PollingDataReady(gspca_dev);
                spca50x_GetFirmware(gspca_dev);
-               gspca_dev->usb_buf[0] = 2;                      /* type */
-               reg_w(gspca_dev, 0x24, 0, 8, 1);
+               reg_w_1(gspca_dev, 0x24, 0, 8, 2);              /* type */
                reg_r(gspca_dev, 0x24, 8, 1);
 
-               gspca_dev->usb_buf[0] = Size;
-               reg_w(gspca_dev, 0x25, 0, 4, 1);
+               reg_w_1(gspca_dev, 0x25, 0, 4, Size);
                reg_r(gspca_dev, 0x25, 4, 1);                   /* size */
                rc = spca504B_PollingDataReady(gspca_dev);
 
                /* Init the cam width height with some values get on init ? */
-               reg_w(gspca_dev, 0x31, 0, 4, 0);
+               reg_w_riv(dev, 0x31, 0, 0x04);
                spca504B_WaitCmdStatus(gspca_dev);
                rc = spca504B_PollingDataReady(gspca_dev);
                break;
        default:
 /* case BRIDGE_SPCA504B: */
 /* case BRIDGE_SPCA536: */
-               gspca_dev->usb_buf[0] = Size;
-               reg_w(gspca_dev, 0x25, 0, 4, 1);
+               reg_w_1(gspca_dev, 0x25, 0, 4, Size);
                reg_r(gspca_dev, 0x25, 4, 1);                   /* size */
-               Type = 6;
-               gspca_dev->usb_buf[0] = Type;
-               reg_w(gspca_dev, 0x27, 0, 0, 1);
+               reg_w_1(gspca_dev, 0x27, 0, 0, 6);
                reg_r(gspca_dev, 0x27, 0, 1);                   /* type */
                rc = spca504B_PollingDataReady(gspca_dev);
                break;
@@ -767,17 +754,51 @@ static void spca504_wait_status(struct gspca_dev *gspca_dev)
 
 static void spca504B_setQtable(struct gspca_dev *gspca_dev)
 {
-       gspca_dev->usb_buf[0] = 3;
-       reg_w(gspca_dev, 0x26, 0, 0, 1);
+       reg_w_1(gspca_dev, 0x26, 0, 0, 3);
        reg_r(gspca_dev, 0x26, 0, 1);
        spca504B_PollingDataReady(gspca_dev);
 }
 
-static void sp5xx_initContBrigHueRegisters(struct gspca_dev *gspca_dev)
+static void setbrightness(struct gspca_dev *gspca_dev)
+{
+       struct sd *sd = (struct sd *) gspca_dev;
+       struct usb_device *dev = gspca_dev->dev;
+       u16 reg;
+
+       reg = sd->bridge == BRIDGE_SPCA536 ? 0x20f0 : 0x21a7;
+       reg_w_riv(dev, 0x00, reg, sd->brightness);
+}
+
+static void setcontrast(struct gspca_dev *gspca_dev)
+{
+       struct sd *sd = (struct sd *) gspca_dev;
+       struct usb_device *dev = gspca_dev->dev;
+       u16 reg;
+
+       reg = sd->bridge == BRIDGE_SPCA536 ? 0x20f1 : 0x21a8;
+       reg_w_riv(dev, 0x00, reg, sd->contrast);
+}
+
+static void setcolors(struct gspca_dev *gspca_dev)
+{
+       struct sd *sd = (struct sd *) gspca_dev;
+       struct usb_device *dev = gspca_dev->dev;
+       u16 reg;
+
+       reg = sd->bridge == BRIDGE_SPCA536 ? 0x20f6 : 0x21ae;
+       reg_w_riv(dev, 0x00, reg, sd->colors);
+}
+
+static void init_ctl_reg(struct gspca_dev *gspca_dev)
 {
        struct sd *sd = (struct sd *) gspca_dev;
+       struct usb_device *dev = gspca_dev->dev;
        int pollreg = 1;
 
+       setbrightness(gspca_dev);
+       setcontrast(gspca_dev);
+       setcolors(gspca_dev);
+
        switch (sd->bridge) {
        case BRIDGE_SPCA504:
        case BRIDGE_SPCA504C:
@@ -786,20 +807,14 @@ static void sp5xx_initContBrigHueRegisters(struct gspca_dev *gspca_dev)
        default:
 /*     case BRIDGE_SPCA533: */
 /*     case BRIDGE_SPCA504B: */
-               reg_w(gspca_dev, 0, 0, 0x21a7, 0);      /* brightness */
-               reg_w(gspca_dev, 0, 0x20, 0x21a8, 0);   /* contrast */
-               reg_w(gspca_dev, 0, 0, 0x21ad, 0);      /* hue */
-               reg_w(gspca_dev, 0, 1, 0x21ac, 0);      /* sat/hue */
-               reg_w(gspca_dev, 0, 0x20, 0x21ae, 0);   /* saturation */
-               reg_w(gspca_dev, 0, 0, 0x21a3, 0);      /* gamma */
+               reg_w_riv(dev, 0, 0x00, 0x21ad);        /* hue */
+               reg_w_riv(dev, 0, 0x01, 0x21ac);        /* sat/hue */
+               reg_w_riv(dev, 0, 0x00, 0x21a3);        /* gamma */
                break;
        case BRIDGE_SPCA536:
-               reg_w(gspca_dev, 0, 0, 0x20f0, 0);
-               reg_w(gspca_dev, 0, 0x21, 0x20f1, 0);
-               reg_w(gspca_dev, 0, 0x40, 0x20f5, 0);
-               reg_w(gspca_dev, 0, 1, 0x20f4, 0);
-               reg_w(gspca_dev, 0, 0x40, 0x20f6, 0);
-               reg_w(gspca_dev, 0, 0, 0x2089, 0);
+               reg_w_riv(dev, 0, 0x40, 0x20f5);
+               reg_w_riv(dev, 0, 0x01, 0x20f4);
+               reg_w_riv(dev, 0, 0x00, 0x2089);
                break;
        }
        if (pollreg)
@@ -840,20 +855,24 @@ static int sd_config(struct gspca_dev *gspca_dev,
 /*     case BRIDGE_SPCA504: */
 /*     case BRIDGE_SPCA536: */
                cam->cam_mode = vga_mode;
-               cam->nmodes = sizeof vga_mode / sizeof vga_mode[0];
+               cam->nmodes =ARRAY_SIZE(vga_mode);
                break;
        case BRIDGE_SPCA533:
                cam->cam_mode = custom_mode;
-               cam->nmodes = sizeof custom_mode / sizeof custom_mode[0];
+               if (sd->subtype == MegaImageVI)         /* 320x240 only */
+                       cam->nmodes = ARRAY_SIZE(custom_mode) - 1;
+               else
+                       cam->nmodes = ARRAY_SIZE(custom_mode);
                break;
        case BRIDGE_SPCA504C:
                cam->cam_mode = vga_mode2;
-               cam->nmodes = sizeof vga_mode2 / sizeof vga_mode2[0];
+               cam->nmodes = ARRAY_SIZE(vga_mode2);
                break;
        }
-       sd->brightness = sd_ctrls[SD_BRIGHTNESS].qctrl.default_value;
-       sd->contrast = sd_ctrls[SD_CONTRAST].qctrl.default_value;
-       sd->colors = sd_ctrls[SD_COLOR].qctrl.default_value;
+       sd->brightness = BRIGHTNESS_DEF;
+       sd->contrast = CONTRAST_DEF;
+       sd->colors = COLOR_DEF;
+       sd->autogain = AUTOGAIN_DEF;
        sd->quality = QUALITY_DEF;
        return 0;
 }
@@ -863,32 +882,29 @@ static int sd_init(struct gspca_dev *gspca_dev)
 {
        struct sd *sd = (struct sd *) gspca_dev;
        struct usb_device *dev = gspca_dev->dev;
-       int rc;
-       __u8 i;
-       __u8 info[6];
-       int err_code;
+       int i, err_code;
+       u8 info[6];
 
        switch (sd->bridge) {
        case BRIDGE_SPCA504B:
-               reg_w(gspca_dev, 0x1d, 0, 0, 0);
-               reg_w(gspca_dev, 0, 1, 0x2306, 0);
-               reg_w(gspca_dev, 0, 0, 0x0d04, 0);
-               reg_w(gspca_dev, 0, 0, 0x2000, 0);
-               reg_w(gspca_dev, 0, 0x13, 0x2301, 0);
-               reg_w(gspca_dev, 0, 0, 0x2306, 0);
+               reg_w_riv(dev, 0x1d, 0x00, 0);
+               reg_w_riv(dev, 0, 0x01, 0x2306);
+               reg_w_riv(dev, 0, 0x00, 0x0d04);
+               reg_w_riv(dev, 0, 0x00, 0x2000);
+               reg_w_riv(dev, 0, 0x13, 0x2301);
+               reg_w_riv(dev, 0, 0x00, 0x2306);
                /* fall thru */
        case BRIDGE_SPCA533:
-               rc = spca504B_PollingDataReady(gspca_dev);
+               spca504B_PollingDataReady(gspca_dev);
                spca50x_GetFirmware(gspca_dev);
                break;
        case BRIDGE_SPCA536:
                spca50x_GetFirmware(gspca_dev);
                reg_r(gspca_dev, 0x00, 0x5002, 1);
-               gspca_dev->usb_buf[0] = 0;
-               reg_w(gspca_dev, 0x24, 0, 0, 1);
+               reg_w_1(gspca_dev, 0x24, 0, 0, 0);
                reg_r(gspca_dev, 0x24, 0, 1);
-               rc = spca504B_PollingDataReady(gspca_dev);
-               reg_w(gspca_dev, 0x34, 0, 0, 0);
+               spca504B_PollingDataReady(gspca_dev);
+               reg_w_riv(dev, 0x34, 0, 0);
                spca504B_WaitCmdStatus(gspca_dev);
                break;
        case BRIDGE_SPCA504C:   /* pccam600 */
@@ -898,12 +914,13 @@ static int sd_init(struct gspca_dev *gspca_dev)
                spca504_wait_status(gspca_dev);
                if (sd->subtype == LogitechClickSmart420)
                        write_vector(gspca_dev,
-                                       spca504A_clicksmart420_open_data);
+                               spca504A_clicksmart420_open_data,
+                               ARRAY_SIZE(spca504A_clicksmart420_open_data));
                else
-                       write_vector(gspca_dev, spca504_pccam600_open_data);
+                       write_vector(gspca_dev, spca504_pccam600_open_data,
+                               ARRAY_SIZE(spca504_pccam600_open_data));
                err_code = spca50x_setup_qtable(gspca_dev,
-                                               0x00, 0x2800,
-                                               0x2840, qtable_creative_pccam);
+                                               qtable_creative_pccam);
                if (err_code < 0) {
                        PDEBUG(D_ERR|D_STREAM, "spca50x_setup_qtable failed");
                        return err_code;
@@ -941,8 +958,8 @@ static int sd_init(struct gspca_dev *gspca_dev)
                                                        6, 0, 0x86, 1); */
 /*                     spca504A_acknowledged_command (gspca_dev, 0x24,
                                                        0, 0, 0x9D, 1); */
-                       reg_w_riv(dev, 0x0, 0x270c, 0x05); /* L92 sno1t.txt */
-                       reg_w_riv(dev, 0x0, 0x2310, 0x05);
+                       reg_w_riv(dev, 0x00, 0x270c, 0x05); /* L92 sno1t.txt */
+                       reg_w_riv(dev, 0x00, 0x2310, 0x05);
                        spca504A_acknowledged_command(gspca_dev, 0x01,
                                                        0x0f, 0, 0xff, 0);
                }
@@ -950,8 +967,6 @@ static int sd_init(struct gspca_dev *gspca_dev)
                reg_w_riv(dev, 0, 0x2000, 0);
                reg_w_riv(dev, 0, 0x2883, 1);
                err_code = spca50x_setup_qtable(gspca_dev,
-                                               0x00, 0x2800,
-                                               0x2840,
                                                qtable_spca504_default);
                if (err_code < 0) {
                        PDEBUG(D_ERR, "spca50x_setup_qtable failed");
@@ -966,10 +981,9 @@ static int sd_start(struct gspca_dev *gspca_dev)
 {
        struct sd *sd = (struct sd *) gspca_dev;
        struct usb_device *dev = gspca_dev->dev;
-       int rc;
        int enable;
-       __u8 i;
-       __u8 info[6];
+       int i;
+       u8 info[6];
 
        /* create the JPEG header */
        sd->jpeg_hdr = kmalloc(JPEG_HDR_SZ, GFP_KERNEL);
@@ -987,16 +1001,20 @@ static int sd_start(struct gspca_dev *gspca_dev)
 /*     case BRIDGE_SPCA504B: */
 /*     case BRIDGE_SPCA533: */
 /*     case BRIDGE_SPCA536: */
-               if (sd->subtype == MegapixV4 ||
-                   sd->subtype == LogitechClickSmart820) {
-                       reg_w(gspca_dev, 0xf0, 0, 0, 0);
+               switch (sd->subtype) {
+               case MegapixV4:
+               case LogitechClickSmart820:
+               case MegaImageVI:
+                       reg_w_riv(dev, 0xf0, 0, 0);
                        spca504B_WaitCmdStatus(gspca_dev);
                        reg_r(gspca_dev, 0xf0, 4, 0);
                        spca504B_WaitCmdStatus(gspca_dev);
-               } else {
-                       reg_w(gspca_dev, 0x31, 0, 4, 0);
+                       break;
+               default:
+                       reg_w_riv(dev, 0x31, 0, 0x04);
                        spca504B_WaitCmdStatus(gspca_dev);
-                       rc = spca504B_PollingDataReady(gspca_dev);
+                       spca504B_PollingDataReady(gspca_dev);
+                       break;
                }
                break;
        case BRIDGE_SPCA504:
@@ -1030,15 +1048,17 @@ static int sd_start(struct gspca_dev *gspca_dev)
                        spca504_acknowledged_command(gspca_dev, 0x24, 0, 0);
                }
                spca504B_SetSizeType(gspca_dev);
-               reg_w_riv(dev, 0x0, 0x270c, 0x05);      /* L92 sno1t.txt */
-               reg_w_riv(dev, 0x0, 0x2310, 0x05);
+               reg_w_riv(dev, 0x00, 0x270c, 0x05);     /* L92 sno1t.txt */
+               reg_w_riv(dev, 0x00, 0x2310, 0x05);
                break;
        case BRIDGE_SPCA504C:
                if (sd->subtype == LogitechClickSmart420) {
                        write_vector(gspca_dev,
-                                       spca504A_clicksmart420_init_data);
+                               spca504A_clicksmart420_init_data,
+                               ARRAY_SIZE(spca504A_clicksmart420_init_data));
                } else {
-                       write_vector(gspca_dev, spca504_pccam600_init_data);
+                       write_vector(gspca_dev, spca504_pccam600_init_data,
+                               ARRAY_SIZE(spca504_pccam600_init_data));
                }
                enable = (sd->autogain ? 0x04 : 0x01);
                reg_w_riv(dev, 0x0c, 0x0000, enable);   /* auto exposure */
@@ -1050,7 +1070,7 @@ static int sd_start(struct gspca_dev *gspca_dev)
                spca504B_SetSizeType(gspca_dev);
                break;
        }
-       sp5xx_initContBrigHueRegisters(gspca_dev);
+       init_ctl_reg(gspca_dev);
        return 0;
 }
 
@@ -1064,7 +1084,7 @@ static void sd_stopN(struct gspca_dev *gspca_dev)
 /*     case BRIDGE_SPCA533: */
 /*     case BRIDGE_SPCA536: */
 /*     case BRIDGE_SPCA504B: */
-               reg_w(gspca_dev, 0x31, 0, 0, 0);
+               reg_w_riv(dev, 0x31, 0, 0);
                spca504B_WaitCmdStatus(gspca_dev);
                spca504B_PollingDataReady(gspca_dev);
                break;
@@ -1082,7 +1102,7 @@ static void sd_stopN(struct gspca_dev *gspca_dev)
                                                        0x0f, 0x00, 0xff, 1);
                } else {
                        spca504_acknowledged_command(gspca_dev, 0x24, 0, 0);
-                       reg_w_riv(dev, 0x01, 0x000f, 0x00);
+                       reg_w_riv(dev, 0x01, 0x000f, 0x0000);
                }
                break;
        }
@@ -1097,12 +1117,12 @@ static void sd_stop0(struct gspca_dev *gspca_dev)
 
 static void sd_pkt_scan(struct gspca_dev *gspca_dev,
                        struct gspca_frame *frame,      /* target */
-                       __u8 *data,                     /* isoc packet */
+                       u8 *data,                       /* isoc packet */
                        int len)                        /* iso packet length */
 {
        struct sd *sd = (struct sd *) gspca_dev;
        int i, sof = 0;
-       static unsigned char ffd9[] = {0xff, 0xd9};
+       static u8 ffd9[] = {0xff, 0xd9};
 
 /* frames are jpeg 4.1.1 without 0xff escape */
        switch (sd->bridge) {
@@ -1190,63 +1210,6 @@ static void sd_pkt_scan(struct gspca_dev *gspca_dev,
        gspca_frame_add(gspca_dev, INTER_PACKET, frame, data, len);
 }
 
-static void setbrightness(struct gspca_dev *gspca_dev)
-{
-       struct sd *sd = (struct sd *) gspca_dev;
-       struct usb_device *dev = gspca_dev->dev;
-
-       switch (sd->bridge) {
-       default:
-/*     case BRIDGE_SPCA533: */
-/*     case BRIDGE_SPCA504B: */
-/*     case BRIDGE_SPCA504: */
-/*     case BRIDGE_SPCA504C: */
-               reg_w_riv(dev, 0x0, 0x21a7, sd->brightness);
-               break;
-       case BRIDGE_SPCA536:
-               reg_w_riv(dev, 0x0, 0x20f0, sd->brightness);
-               break;
-       }
-}
-
-static void setcontrast(struct gspca_dev *gspca_dev)
-{
-       struct sd *sd = (struct sd *) gspca_dev;
-       struct usb_device *dev = gspca_dev->dev;
-
-       switch (sd->bridge) {
-       default:
-/*     case BRIDGE_SPCA533: */
-/*     case BRIDGE_SPCA504B: */
-/*     case BRIDGE_SPCA504: */
-/*     case BRIDGE_SPCA504C: */
-               reg_w_riv(dev, 0x0, 0x21a8, sd->contrast);
-               break;
-       case BRIDGE_SPCA536:
-               reg_w_riv(dev, 0x0, 0x20f1, sd->contrast);
-               break;
-       }
-}
-
-static void setcolors(struct gspca_dev *gspca_dev)
-{
-       struct sd *sd = (struct sd *) gspca_dev;
-       struct usb_device *dev = gspca_dev->dev;
-
-       switch (sd->bridge) {
-       default:
-/*     case BRIDGE_SPCA533: */
-/*     case BRIDGE_SPCA504B: */
-/*     case BRIDGE_SPCA504: */
-/*     case BRIDGE_SPCA504C: */
-               reg_w_riv(dev, 0x0, 0x21ae, sd->colors);
-               break;
-       case BRIDGE_SPCA536:
-               reg_w_riv(dev, 0x0, 0x20f6, sd->colors);
-               break;
-       }
-}
-
 static int sd_setbrightness(struct gspca_dev *gspca_dev, __s32 val)
 {
        struct sd *sd = (struct sd *) gspca_dev;
@@ -1384,6 +1347,7 @@ static const __devinitdata struct usb_device_id device_table[] = {
        {USB_DEVICE(0x04fc, 0x5360), BS(SPCA536, 0)},
        {USB_DEVICE(0x04fc, 0xffff), BS(SPCA504B, 0)},
        {USB_DEVICE(0x052b, 0x1513), BS(SPCA533, MegapixV4)},
+       {USB_DEVICE(0x052b, 0x1803), BS(SPCA533, MegaImageVI)},
        {USB_DEVICE(0x0546, 0x3155), BS(SPCA533, 0)},
        {USB_DEVICE(0x0546, 0x3191), BS(SPCA504B, 0)},
        {USB_DEVICE(0x0546, 0x3273), BS(SPCA504B, 0)},
index 404214b8cd2bed98d22e036f6d71bd8b4672add9..1d321c30d22f57c630fafa87d2bf52eb7025c6c1 100644 (file)
@@ -264,6 +264,10 @@ static const struct v4l2_pix_format vga_mode_t16[] = {
 
 /* sensor specific data */
 struct additional_sensor_data {
+       const u8 n3[6];
+       const u8 *n4, n4sz;
+       const u8 reg80, reg8e;
+       const u8 nset8[6];
        const u8 data1[10];
        const u8 data2[9];
        const u8 data3[9];
@@ -272,14 +276,55 @@ struct additional_sensor_data {
        const u8 stream[4];
 };
 
+static const u8 n4_om6802[] = {
+       0x09, 0x01, 0x12, 0x04, 0x66, 0x8a, 0x80, 0x3c,
+       0x81, 0x22, 0x84, 0x50, 0x8a, 0x78, 0x8b, 0x68,
+       0x8c, 0x88, 0x8e, 0x33, 0x8f, 0x24, 0xaa, 0xb1,
+       0xa2, 0x60, 0xa5, 0x30, 0xa6, 0x3a, 0xa8, 0xe8,
+       0xae, 0x05, 0xb1, 0x00, 0xbb, 0x04, 0xbc, 0x48,
+       0xbe, 0x36, 0xc6, 0x88, 0xe9, 0x00, 0xc5, 0xc0,
+       0x65, 0x0a, 0xbb, 0x86, 0xaf, 0x58, 0xb0, 0x68,
+       0x87, 0x40, 0x89, 0x2b, 0x8d, 0xff, 0x83, 0x40,
+       0xac, 0x84, 0xad, 0x86, 0xaf, 0x46
+};
+static const u8 n4_other[] = {
+       0x66, 0x00, 0x7f, 0x00, 0x80, 0xac, 0x81, 0x69,
+       0x84, 0x40, 0x85, 0x70, 0x86, 0x20, 0x8a, 0x68,
+       0x8b, 0x58, 0x8c, 0x88, 0x8d, 0xff, 0x8e, 0xb8,
+       0x8f, 0x28, 0xa2, 0x60, 0xa5, 0x40, 0xa8, 0xa8,
+       0xac, 0x84, 0xad, 0x84, 0xae, 0x24, 0xaf, 0x56,
+       0xb0, 0x68, 0xb1, 0x00, 0xb2, 0x88, 0xbb, 0xc5,
+       0xbc, 0x4a, 0xbe, 0x36, 0xc2, 0x88, 0xc5, 0xc0,
+       0xc6, 0xda, 0xe9, 0x26, 0xeb, 0x00
+};
+static const u8 n4_tas5130a[] = {
+       0x80, 0x3c, 0x81, 0x68, 0x83, 0xa0, 0x84, 0x20,
+       0x8a, 0x68, 0x8b, 0x58, 0x8c, 0x88, 0x8e, 0xb4,
+       0x8f, 0x24, 0xa1, 0xb1, 0xa2, 0x30, 0xa5, 0x10,
+       0xa6, 0x4a, 0xae, 0x03, 0xb1, 0x44, 0xb2, 0x08,
+       0xb7, 0x06, 0xb9, 0xe7, 0xbb, 0xc4, 0xbc, 0x4a,
+       0xbe, 0x36, 0xbf, 0xff, 0xc2, 0x88, 0xc5, 0xc8,
+       0xc6, 0xda
+};
+
 static const struct additional_sensor_data sensor_data[] = {
-    {                          /* OM6802 */
+    {                          /* 0: OM6802 */
+       .n3 =
+               {0x61, 0x68, 0x65, 0x0a, 0x60, 0x04},
+       .n4 = n4_om6802,
+       .n4sz = sizeof n4_om6802,
+       .reg80 = 0x3c,
+       .reg8e = 0x33,
+       .nset8 = {0xa8, 0xf0, 0xc6, 0x88, 0xc0, 0x00},
        .data1 =
                {0xc2, 0x28, 0x0f, 0x22, 0xcd, 0x27, 0x2c, 0x06,
                 0xb3, 0xfc},
        .data2 =
                {0x80, 0xff, 0xff, 0x80, 0xff, 0xff, 0x80, 0xff,
                 0xff},
+       .data3 =
+               {0x80, 0xff, 0xff, 0x80, 0xff, 0xff, 0x80, 0xff,
+                0xff},
        .data4 =        /*Freq (50/60Hz). Splitted for test purpose */
                {0x66, 0xca, 0xa8, 0xf0},
        .data5 =        /* this could be removed later */
@@ -287,13 +332,23 @@ static const struct additional_sensor_data sensor_data[] = {
        .stream =
                {0x0b, 0x04, 0x0a, 0x78},
     },
-    {                          /* OTHER */
+    {                          /* 1: OTHER */
+       .n3 =
+               {0x61, 0xc2, 0x65, 0x88, 0x60, 0x00},
+       .n4 = n4_other,
+       .n4sz = sizeof n4_other,
+       .reg80 = 0xac,
+       .reg8e = 0xb8,
+       .nset8 = {0xa8, 0xa8, 0xc6, 0xda, 0xc0, 0x00},
        .data1 =
                {0xc1, 0x48, 0x04, 0x1b, 0xca, 0x2e, 0x33, 0x3a,
                 0xe8, 0xfc},
        .data2 =
                {0x4e, 0x9c, 0xec, 0x40, 0x80, 0xc0, 0x48, 0x96,
                 0xd9},
+       .data3 =
+               {0x4e, 0x9c, 0xec, 0x40, 0x80, 0xc0, 0x48, 0x96,
+                0xd9},
        .data4 =
                {0x66, 0x00, 0xa8, 0xa8},
        .data5 =
@@ -301,13 +356,23 @@ static const struct additional_sensor_data sensor_data[] = {
        .stream =
                {0x0b, 0x04, 0x0a, 0x00},
     },
-    {                          /* TAS5130A */
+    {                          /* 2: TAS5130A */
+       .n3 =
+               {0x61, 0xc2, 0x65, 0x0d, 0x60, 0x08},
+       .n4 = n4_tas5130a,
+       .n4sz = sizeof n4_tas5130a,
+       .reg80 = 0x3c,
+       .reg8e = 0xb4,
+       .nset8 = {0xa8, 0xf0, 0xc6, 0xda, 0xc0, 0x00},
        .data1 =
                {0xbb, 0x28, 0x10, 0x10, 0xbb, 0x28, 0x1e, 0x27,
                 0xc8, 0xfc},
        .data2 =
                {0x60, 0xa8, 0xe0, 0x60, 0xa8, 0xe0, 0x60, 0xa8,
                 0xe0},
+       .data3 =
+               {0x60, 0xa8, 0xe0, 0x60, 0xa8, 0xe0, 0x60, 0xa8,
+                0xe0},
        .data4 =        /* Freq (50/60Hz). Splitted for test purpose */
                {0x66, 0x00, 0xa8, 0xe8},
        .data5 =
@@ -364,7 +429,7 @@ static const u8 gamma_table[GAMMA_MAX][17] = {
        {0x00, 0x18, 0x2b, 0x44, 0x60, 0x70, 0x80, 0x8e,        /* 10 */
         0x9c, 0xaa, 0xb7, 0xc4, 0xd0, 0xd8, 0xe2, 0xf0,
         0xff},
-       {0x00, 0x1a, 0x34, 0x52, 0x66, 0x7e, 0x8D, 0x9B,        /* 11 */
+       {0x00, 0x1a, 0x34, 0x52, 0x66, 0x7e, 0x8d, 0x9b,        /* 11 */
         0xa8, 0xb4, 0xc0, 0xcb, 0xd6, 0xe1, 0xeb, 0xf5,
         0xff},
        {0x00, 0x3f, 0x5a, 0x6e, 0x7f, 0x8e, 0x9c, 0xa8,        /* 12 */
@@ -385,8 +450,6 @@ static const u8 tas5130a_sensor_init[][8] = {
        {0x62, 0x08, 0x63, 0x70, 0x64, 0x1d, 0x60, 0x09},
        {0x62, 0x20, 0x63, 0x01, 0x64, 0x02, 0x60, 0x09},
        {0x62, 0x07, 0x63, 0x03, 0x64, 0x00, 0x60, 0x09},
-       {0x62, 0x07, 0x63, 0x03, 0x64, 0x00, 0x60, 0x09},
-       {},
 };
 
 static u8 sensor_reset[] = {0x61, 0x68, 0x62, 0xff, 0x60, 0x07};
@@ -633,10 +696,10 @@ static int sd_init(struct gspca_dev *gspca_dev)
         * but wont hurt anyway, and can help someone with similar webcam
         * to see the initial parameters.*/
        struct sd *sd = (struct sd *) gspca_dev;
+       const struct additional_sensor_data *sensor;
        int i;
        u16 sensor_id;
        u8 test_byte = 0;
-       u16 reg80, reg8e;
 
        static const u8 read_indexs[] =
                { 0x0a, 0x0b, 0x66, 0x80, 0x81, 0x8e, 0x8f, 0xa5,
@@ -645,37 +708,6 @@ static int sd_init(struct gspca_dev *gspca_dev)
                        {0x08, 0x03, 0x09, 0x03, 0x12, 0x04};
        static const u8 n2[] =
                        {0x08, 0x00};
-       static const u8 n3[6] =
-                       {0x61, 0x68, 0x65, 0x0a, 0x60, 0x04};
-       static const u8 n3_other[6] =
-                       {0x61, 0xc2, 0x65, 0x88, 0x60, 0x00};
-       static const u8 n4[] =
-               {0x09, 0x01, 0x12, 0x04, 0x66, 0x8a, 0x80, 0x3c,
-                0x81, 0x22, 0x84, 0x50, 0x8a, 0x78, 0x8b, 0x68,
-                0x8c, 0x88, 0x8e, 0x33, 0x8f, 0x24, 0xaa, 0xb1,
-                0xa2, 0x60, 0xa5, 0x30, 0xa6, 0x3a, 0xa8, 0xe8,
-                0xae, 0x05, 0xb1, 0x00, 0xbb, 0x04, 0xbc, 0x48,
-                0xbe, 0x36, 0xc6, 0x88, 0xe9, 0x00, 0xc5, 0xc0,
-                0x65, 0x0a, 0xbb, 0x86, 0xaf, 0x58, 0xb0, 0x68,
-                0x87, 0x40, 0x89, 0x2b, 0x8d, 0xff, 0x83, 0x40,
-                0xac, 0x84, 0xad, 0x86, 0xaf, 0x46};
-       static const u8 n4_other[] =
-               {0x66, 0x00, 0x7f, 0x00, 0x80, 0xac, 0x81, 0x69,
-                0x84, 0x40, 0x85, 0x70, 0x86, 0x20, 0x8a, 0x68,
-                0x8b, 0x58, 0x8c, 0x88, 0x8d, 0xff, 0x8e, 0xb8,
-                0x8f, 0x28, 0xa2, 0x60, 0xa5, 0x40, 0xa8, 0xa8,
-                0xac, 0x84, 0xad, 0x84, 0xae, 0x24, 0xaf, 0x56,
-                0xb0, 0x68, 0xb1, 0x00, 0xb2, 0x88, 0xbb, 0xc5,
-                0xbc, 0x4a, 0xbe, 0x36, 0xc2, 0x88, 0xc5, 0xc0,
-                0xc6, 0xda, 0xe9, 0x26, 0xeb, 0x00};
-       static const u8 nset8[6] =
-                       { 0xa8, 0xf0, 0xc6, 0x88, 0xc0, 0x00 };
-       static const u8 nset8_other[6] =
-                       { 0xa8, 0xa8, 0xc6, 0xda, 0xc0, 0x00 };
-       static const u8 nset9[4] =
-                       { 0x0b, 0x04, 0x0a, 0x78 };
-       static const u8 nset9_other[4] =
-                       { 0x0b, 0x04, 0x0a, 0x00 };
 
        sensor_id = (reg_r(gspca_dev, 0x06) << 8)
                        | reg_r(gspca_dev, 0x07);
@@ -709,8 +741,7 @@ static int sd_init(struct gspca_dev *gspca_dev)
                }
                if (i < 0) {
                        err("Bad sensor reset %02x", test_byte);
-/*                     return -EIO; */
-/*fixme: test - continue */
+                       return -EIO;
                }
                reg_w_buf(gspca_dev, n2, sizeof n2);
        }
@@ -723,31 +754,17 @@ static int sd_init(struct gspca_dev *gspca_dev)
                i++;
        }
 
-       if (sd->sensor != SENSOR_OTHER) {
-               reg_w_buf(gspca_dev, n3, sizeof n3);
-               reg_w_buf(gspca_dev, n4, sizeof n4);
-               reg_r(gspca_dev, 0x0080);
-               reg_w(gspca_dev, 0x2c80);
-               reg80 = 0x3880;
-               reg8e = 0x338e;
-       } else {
-               reg_w_buf(gspca_dev, n3_other, sizeof n3_other);
-               reg_w_buf(gspca_dev, n4_other, sizeof n4_other);
-               sd->gamma = 5;
-               reg80 = 0xac80;
-               reg8e = 0xb88e;
-       }
+       sensor = &sensor_data[sd->sensor];
+       reg_w_buf(gspca_dev, sensor->n3, sizeof sensor->n3);
+       reg_w_buf(gspca_dev, sensor->n4, sensor->n4sz);
 
-       reg_w_ixbuf(gspca_dev, 0xd0, sensor_data[sd->sensor].data1,
-                       sizeof sensor_data[sd->sensor].data1);
-       reg_w_ixbuf(gspca_dev, 0xc7, sensor_data[sd->sensor].data2,
-                       sizeof sensor_data[sd->sensor].data2);
-       reg_w_ixbuf(gspca_dev, 0xe0, sensor_data[sd->sensor].data2,
-                       sizeof sensor_data[sd->sensor].data2);
+       reg_w_ixbuf(gspca_dev, 0xd0, sensor->data1, sizeof sensor->data1);
+       reg_w_ixbuf(gspca_dev, 0xc7, sensor->data2, sizeof sensor->data2);
+       reg_w_ixbuf(gspca_dev, 0xe0, sensor->data3, sizeof sensor->data3);
 
-       reg_w(gspca_dev, reg80);
-       reg_w(gspca_dev, reg80);
-       reg_w(gspca_dev, reg8e);
+       reg_w(gspca_dev, (sensor->reg80 << 8) + 0x80);
+       reg_w(gspca_dev, (sensor->reg80 << 8) + 0x80);
+       reg_w(gspca_dev, (sensor->reg8e << 8) + 0x8e);
 
        setbrightness(gspca_dev);
        setcontrast(gspca_dev);
@@ -760,25 +777,14 @@ static int sd_init(struct gspca_dev *gspca_dev)
        reg_w(gspca_dev, 0x2088);
        reg_w(gspca_dev, 0x2089);
 
-       reg_w_buf(gspca_dev, sensor_data[sd->sensor].data4,
-                       sizeof sensor_data[sd->sensor].data4);
-       reg_w_buf(gspca_dev, sensor_data[sd->sensor].data5,
-                       sizeof sensor_data[sd->sensor].data5);
-       if (sd->sensor != SENSOR_OTHER) {
-               reg_w_buf(gspca_dev, nset8, sizeof nset8);
-               reg_w_buf(gspca_dev, nset9, sizeof nset9);
-               reg_w(gspca_dev, 0x2880);
-       } else {
-               reg_w_buf(gspca_dev, nset8_other, sizeof nset8_other);
-               reg_w_buf(gspca_dev, nset9_other, sizeof nset9_other);
-       }
+       reg_w_buf(gspca_dev, sensor->data4, sizeof sensor->data4);
+       reg_w_buf(gspca_dev, sensor->data5, sizeof sensor->data5);
+       reg_w_buf(gspca_dev, sensor->nset8, sizeof sensor->nset8);
+       reg_w_buf(gspca_dev, sensor->stream, sizeof sensor->stream);
 
-       reg_w_ixbuf(gspca_dev, 0xd0, sensor_data[sd->sensor].data1,
-                       sizeof sensor_data[sd->sensor].data1);
-       reg_w_ixbuf(gspca_dev, 0xc7, sensor_data[sd->sensor].data2,
-                       sizeof sensor_data[sd->sensor].data2);
-       reg_w_ixbuf(gspca_dev, 0xe0, sensor_data[sd->sensor].data2,
-                       sizeof sensor_data[sd->sensor].data2);
+       reg_w_ixbuf(gspca_dev, 0xd0, sensor->data1, sizeof sensor->data1);
+       reg_w_ixbuf(gspca_dev, 0xc7, sensor->data2, sizeof sensor->data2);
+       reg_w_ixbuf(gspca_dev, 0xe0, sensor->data3, sizeof sensor->data3);
 
        return 0;
 }
@@ -828,7 +834,6 @@ static void setlightfreq(struct gspca_dev *gspca_dev)
  * i added some module parameters for test with some users */
 static void poll_sensor(struct gspca_dev *gspca_dev)
 {
-       struct sd *sd = (struct sd *) gspca_dev;
        static const u8 poll1[] =
                {0x67, 0x05, 0x68, 0x81, 0x69, 0x80, 0x6a, 0x82,
                 0x6b, 0x68, 0x6c, 0x69, 0x72, 0xd9, 0x73, 0x34,
@@ -844,24 +849,23 @@ static void poll_sensor(struct gspca_dev *gspca_dev)
                 0xa1, 0xb1, 0xda, 0x6b, 0xdb, 0x98, 0xdf, 0x0c,
                 0xc2, 0x80, 0xc3, 0x10};
 
-       if (sd->sensor == SENSOR_OM6802) {
-               PDEBUG(D_STREAM, "[Sensor requires polling]");
-               reg_w_buf(gspca_dev, poll1, sizeof poll1);
-               reg_w_buf(gspca_dev, poll2, sizeof poll2);
-               reg_w_buf(gspca_dev, poll3, sizeof poll3);
-               reg_w_buf(gspca_dev, poll4, sizeof poll4);
-       }
+       PDEBUG(D_STREAM, "[Sensor requires polling]");
+       reg_w_buf(gspca_dev, poll1, sizeof poll1);
+       reg_w_buf(gspca_dev, poll2, sizeof poll2);
+       reg_w_buf(gspca_dev, poll3, sizeof poll3);
+       reg_w_buf(gspca_dev, poll4, sizeof poll4);
 }
 
 static int sd_start(struct gspca_dev *gspca_dev)
 {
        struct sd *sd = (struct sd *) gspca_dev;
+       const struct additional_sensor_data *sensor;
        int i, mode;
        u8 t2[] = { 0x07, 0x00, 0x0d, 0x60, 0x0e, 0x80 };
        static const u8 t3[] =
                { 0x07, 0x00, 0x88, 0x02, 0x06, 0x00, 0xe7, 0x01 };
 
-       mode = gspca_dev->cam.cam_mode[(int) gspca_dev->curr_mode]. priv;
+       mode = gspca_dev->cam.cam_mode[gspca_dev->curr_mode].priv;
        switch (mode) {
        case 0:         /* 640x480 (0x00) */
                break;
@@ -889,34 +893,33 @@ static int sd_start(struct gspca_dev *gspca_dev)
        default:
 /*     case SENSOR_TAS5130A: */
                i = 0;
-               while (tas5130a_sensor_init[i][0] != 0) {
+               for (;;) {
                        reg_w_buf(gspca_dev, tas5130a_sensor_init[i],
                                         sizeof tas5130a_sensor_init[0]);
+                       if (i >= ARRAY_SIZE(tas5130a_sensor_init) - 1)
+                               break;
                        i++;
                }
                reg_w(gspca_dev, 0x3c80);
                /* just in case and to keep sync with logs (for mine) */
-               reg_w_buf(gspca_dev, tas5130a_sensor_init[3],
+               reg_w_buf(gspca_dev, tas5130a_sensor_init[i],
                                 sizeof tas5130a_sensor_init[0]);
                reg_w(gspca_dev, 0x3c80);
                break;
        }
-       reg_w_buf(gspca_dev, sensor_data[sd->sensor].data4,
-                       sizeof sensor_data[sd->sensor].data4);
+       sensor = &sensor_data[sd->sensor];
+       reg_w_buf(gspca_dev, sensor->data4, sizeof sensor->data4);
        reg_r(gspca_dev, 0x0012);
        reg_w_buf(gspca_dev, t2, sizeof t2);
        reg_w_ixbuf(gspca_dev, 0xb3, t3, sizeof t3);
        reg_w(gspca_dev, 0x0013);
        msleep(15);
-       reg_w_buf(gspca_dev, sensor_data[sd->sensor].stream,
-                       sizeof sensor_data[sd->sensor].stream);
-       poll_sensor(gspca_dev);
+       reg_w_buf(gspca_dev, sensor->stream, sizeof sensor->stream);
+       reg_w_buf(gspca_dev, sensor->stream, sizeof sensor->stream);
+
+       if (sd->sensor == SENSOR_OM6802)
+               poll_sensor(gspca_dev);
 
-       /* restart on each start, just in case, sometimes regs goes wrong
-        * when using controls from app */
-       setbrightness(gspca_dev);
-       setcontrast(gspca_dev);
-       setcolors(gspca_dev);
        return 0;
 }
 
@@ -926,10 +929,9 @@ static void sd_stopN(struct gspca_dev *gspca_dev)
 
        reg_w_buf(gspca_dev, sensor_data[sd->sensor].stream,
                        sizeof sensor_data[sd->sensor].stream);
-       msleep(20);
        reg_w_buf(gspca_dev, sensor_data[sd->sensor].stream,
                        sizeof sensor_data[sd->sensor].stream);
-       if (sd->sensor != SENSOR_OTHER) {
+       if (sd->sensor == SENSOR_OM6802) {
                msleep(20);
                reg_w(gspca_dev, 0x0309);
        }
index 9f243d7e3110554d4107c90021d13d2c4325d4e5..4b44dde9f8b8f8525c76c171def5b9d7d9289445 100644 (file)
@@ -426,7 +426,7 @@ static void sd_pkt_scan(struct gspca_dev *gspca_dev,
        gspca_frame_add(gspca_dev, packet_type0,
                        frame, data + 2, gspca_dev->width);
        gspca_frame_add(gspca_dev, packet_type1,
-                       frame, data + gspca_dev->width + 6, gspca_dev->width);
+                       frame, data + gspca_dev->width + 5, gspca_dev->width);
 }
 
 static int sd_setbrightness(struct gspca_dev *gspca_dev, __s32 val)
index 26dd155efcc32d39be0b67619a925c0acb856af7..619250e707186ccf298ef2c8e188eec6abd74c4a 100644 (file)
@@ -32,14 +32,14 @@ MODULE_LICENSE("GPL");
 struct sd {
        struct gspca_dev gspca_dev;     /* !! must be the first item */
 
-       __u8 hflip;
-       __u8 vflip;
-       __u8 lightfreq;
-       __u8 sharpness;
+       u8 hflip;
+       u8 vflip;
+       u8 lightfreq;
+       u8 sharpness;
 
        u8 image_offset;
 
-       char bridge;
+       u8 bridge;
 #define BRIDGE_VC0321 0
 #define BRIDGE_VC0323 1
        u8 sensor;
@@ -52,6 +52,10 @@ struct sd {
 #define SENSOR_OV7670 6
 #define SENSOR_PO1200 7
 #define SENSOR_PO3130NC 8
+       u8 flags;
+#define FL_SAMSUNG 0x01                /* SamsungQ1 (2 sensors) */
+#define FL_HFLIP 0x02          /* mirrored by default */
+#define FL_VFLIP 0x04          /* vertical flipped by default */
 };
 
 /* V4L2 controls supported by the driver */
@@ -65,7 +69,7 @@ static int sd_setsharpness(struct gspca_dev *gspca_dev, __s32 val);
 static int sd_getsharpness(struct gspca_dev *gspca_dev, __s32 *val);
 
 static struct ctrl sd_ctrls[] = {
-/* next 2 controls work with ov7660 and ov7670 only */
+/* next 2 controls work with some sensors only */
 #define HFLIP_IDX 0
        {
            {
@@ -152,9 +156,9 @@ static const struct v4l2_pix_format vc0323_mode[] = {
                .sizeimage = 640 * 480 * 3 / 8 + 590,
                .colorspace = V4L2_COLORSPACE_JPEG,
                .priv = 0},
-       {1280, 1024, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE, /* mi13x0_soc only */
+       {1280, 960, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE, /* mi1310_soc only */
                .bytesperline = 1280,
-               .sizeimage = 1280 * 1024 * 1 / 4 + 590,
+               .sizeimage = 1280 * 960 * 3 / 8 + 590,
                .colorspace = V4L2_COLORSPACE_JPEG,
                .priv = 2},
 };
@@ -188,11 +192,11 @@ static const struct v4l2_pix_format svga_mode[] = {
 #define OV7660_MVFP_MIRROR     0x20
 #define OV7660_MVFP_VFLIP      0x10
 
-static const __u8 mi0360_matrix[9] = {
+static const u8 mi0360_matrix[9] = {
        0x50, 0xf8, 0xf8, 0xf5, 0x50, 0xfb, 0xff, 0xf1, 0x50
 };
 
-static const __u8 mi0360_initVGA_JPG[][4] = {
+static const u8 mi0360_initVGA_JPG[][4] = {
        {0xb0, 0x03, 0x19, 0xcc},
        {0xb0, 0x04, 0x02, 0xcc},
        {0xb3, 0x00, 0x24, 0xcc},
@@ -301,7 +305,7 @@ static const __u8 mi0360_initVGA_JPG[][4] = {
        {0xb3, 0x5c, 0x01, 0xcc},
        {}
 };
-static const __u8 mi0360_initQVGA_JPG[][4] = {
+static const u8 mi0360_initQVGA_JPG[][4] = {
        {0xb0, 0x03, 0x19, 0xcc},
        {0xb0, 0x04, 0x02, 0xcc},
        {0xb3, 0x00, 0x24, 0xcc},
@@ -421,211 +425,95 @@ static const __u8 mi0360_initQVGA_JPG[][4] = {
        {}
 };
 
-static const __u8 mi1310_socinitVGA_JPG[][4] = {
+static const u8 mi1310_socinitVGA_JPG[][4] = {
        {0xb0, 0x03, 0x19, 0xcc},
        {0xb0, 0x04, 0x02, 0xcc},
-       {0xb3, 0x00, 0x24, 0xcc},
-       {0xb3, 0x00, 0x25, 0xcc},
-       {0xb3, 0x05, 0x01, 0xcc},
-       {0xb3, 0x06, 0x03, 0xcc},
-       {0xb3, 0x5c, 0x01, 0xcc},
+       {0xb3, 0x00, 0x64, 0xcc},
+       {0xb3, 0x00, 0x65, 0xcc},
+       {0xb3, 0x05, 0x00, 0xcc},
+       {0xb3, 0x06, 0x00, 0xcc},
        {0xb3, 0x08, 0x01, 0xcc},
        {0xb3, 0x09, 0x0c, 0xcc},
        {0xb3, 0x34, 0x02, 0xcc},
        {0xb3, 0x35, 0xdd, 0xcc},
+       {0xb3, 0x02, 0x00, 0xcc},
        {0xb3, 0x03, 0x0a, 0xcc},
-       {0xb3, 0x04, 0x0d, 0xcc},
+       {0xb3, 0x04, 0x05, 0xcc},
        {0xb3, 0x20, 0x00, 0xcc},
        {0xb3, 0x21, 0x00, 0xcc},
-       {0xb3, 0x22, 0x01, 0xcc},
-       {0xb3, 0x23, 0xe0, 0xcc},
+       {0xb3, 0x22, 0x03, 0xcc},
+       {0xb3, 0x23, 0xc0, 0xcc},
        {0xb3, 0x14, 0x00, 0xcc},
        {0xb3, 0x15, 0x00, 0xcc},
-       {0xb3, 0x16, 0x02, 0xcc},
-       {0xb3, 0x17, 0x7f, 0xcc},
-       {0xb8, 0x01, 0x7d, 0xcc},
-       {0xb8, 0x81, 0x09, 0xcc},
-       {0xb8, 0x27, 0x20, 0xcc},
-       {0xb8, 0x26, 0x80, 0xcc},
-       {0xb3, 0x00, 0x25, 0xcc},
-       {0xb8, 0x00, 0x13, 0xcc},
-       {0xbc, 0x00, 0x71, 0xcc},
-       {0xb8, 0x81, 0x01, 0xcc},
-       {0xb8, 0x2c, 0x5a, 0xcc},
-       {0xb8, 0x2d, 0xff, 0xcc},
-       {0xb8, 0x2e, 0xee, 0xcc},
-       {0xb8, 0x2f, 0xfb, 0xcc},
-       {0xb8, 0x30, 0x52, 0xcc},
-       {0xb8, 0x31, 0xf8, 0xcc},
-       {0xb8, 0x32, 0xf1, 0xcc},
-       {0xb8, 0x33, 0xff, 0xcc},
-       {0xb8, 0x34, 0x54, 0xcc},
-       {0xb8, 0x35, 0x00, 0xcc},
-       {0xb8, 0x36, 0x00, 0xcc},
-       {0xb8, 0x37, 0x00, 0xcc},
+       {0xb3, 0x16, 0x04, 0xcc},
+       {0xb3, 0x17, 0xff, 0xcc},
+       {0xb3, 0x00, 0x65, 0xcc},
+       {0xb8, 0x00, 0x00, 0xcc},
+       {0xbc, 0x00, 0xd0, 0xcc},
+       {0xbc, 0x01, 0x01, 0xcc},
+       {0xf0, 0x00, 0x02, 0xbb},
+       {0xc8, 0x9f, 0x0b, 0xbb},
+       {0x5b, 0x00, 0x01, 0xbb},
+       {0x2f, 0xde, 0x20, 0xbb},
        {0xf0, 0x00, 0x00, 0xbb},
-       {0x00, 0x01, 0x00, 0xdd},
-       {0x0d, 0x00, 0x09, 0xbb},
-       {0x0d, 0x00, 0x08, 0xbb},
+       {0x20, 0x03, 0x02, 0xbb},       /* h/v flip */
        {0xf0, 0x00, 0x01, 0xbb},
-       {0x00, 0x01, 0x00, 0xdd},
-       {0x06, 0x00, 0x14, 0xbb},
-       {0x3a, 0x10, 0x00, 0xbb},
-       {0x00, 0x00, 0x10, 0xdd},
-       {0x9b, 0x10, 0x00, 0xbb},
-       {0x00, 0x00, 0x10, 0xdd},
+       {0x05, 0x00, 0x07, 0xbb},
+       {0x34, 0x00, 0x00, 0xbb},
+       {0x35, 0xff, 0x00, 0xbb},
+       {0xdc, 0x07, 0x02, 0xbb},
+       {0xdd, 0x3c, 0x18, 0xbb},
+       {0xde, 0x92, 0x6d, 0xbb},
+       {0xdf, 0xcd, 0xb1, 0xbb},
+       {0xe0, 0xff, 0xe7, 0xbb},
+       {0x06, 0xf0, 0x0d, 0xbb},
+       {0x06, 0x70, 0x0e, 0xbb},
+       {0x4c, 0x00, 0x01, 0xbb},
+       {0x4d, 0x00, 0x01, 0xbb},
+       {0xf0, 0x00, 0x02, 0xbb},
+       {0x2e, 0x0c, 0x55, 0xbb},
+       {0x21, 0xb6, 0x6e, 0xbb},
+       {0x36, 0x30, 0x10, 0xbb},
+       {0x37, 0x00, 0xc1, 0xbb},
        {0xf0, 0x00, 0x00, 0xbb},
-       {0x00, 0x01, 0x00, 0xdd},
-       {0x2b, 0x00, 0x28, 0xbb},
-       {0x2c, 0x00, 0x30, 0xbb},
-       {0x2d, 0x00, 0x30, 0xbb},
-       {0x2e, 0x00, 0x28, 0xbb},
-       {0x41, 0x00, 0xd7, 0xbb},
-       {0x09, 0x02, 0x3a, 0xbb},
-       {0x0c, 0x00, 0x00, 0xbb},
-       {0x20, 0x00, 0x00, 0xbb},
-       {0x05, 0x00, 0x8c, 0xbb},
-       {0x06, 0x00, 0x32, 0xbb},
-       {0x07, 0x00, 0xc6, 0xbb},
-       {0x08, 0x00, 0x19, 0xbb},
-       {0x24, 0x80, 0x6f, 0xbb},
-       {0xc8, 0x00, 0x0f, 0xbb},
-       {0x20, 0x00, 0x0f, 0xbb},
+       {0x07, 0x00, 0x84, 0xbb},
+       {0x08, 0x02, 0x4a, 0xbb},
+       {0x05, 0x01, 0x10, 0xbb},
+       {0x06, 0x00, 0x39, 0xbb},
+       {0xf0, 0x00, 0x02, 0xbb},
+       {0x58, 0x02, 0x67, 0xbb},
+       {0x57, 0x02, 0x00, 0xbb},
+       {0x5a, 0x02, 0x67, 0xbb},
+       {0x59, 0x02, 0x00, 0xbb},
+       {0x5c, 0x12, 0x0d, 0xbb},
+       {0x5d, 0x16, 0x11, 0xbb},
+       {0x39, 0x06, 0x18, 0xbb},
+       {0x3a, 0x06, 0x18, 0xbb},
+       {0x3b, 0x06, 0x18, 0xbb},
+       {0x3c, 0x06, 0x18, 0xbb},
+       {0x64, 0x7b, 0x5b, 0xbb},
+       {0xf0, 0x00, 0x02, 0xbb},
+       {0x36, 0x30, 0x10, 0xbb},
+       {0x37, 0x00, 0xc0, 0xbb},
+       {0xbc, 0x0e, 0x00, 0xcc},
+       {0xbc, 0x0f, 0x05, 0xcc},
+       {0xbc, 0x10, 0xc0, 0xcc},
+       {0xbc, 0x11, 0x03, 0xcc},
        {0xb6, 0x00, 0x00, 0xcc},
        {0xb6, 0x03, 0x02, 0xcc},
        {0xb6, 0x02, 0x80, 0xcc},
        {0xb6, 0x05, 0x01, 0xcc},
        {0xb6, 0x04, 0xe0, 0xcc},
-       {0xb6, 0x12, 0x78, 0xcc},
+       {0xb6, 0x12, 0xf8, 0xcc},
+       {0xb6, 0x13, 0x25, 0xcc},
        {0xb6, 0x18, 0x02, 0xcc},
        {0xb6, 0x17, 0x58, 0xcc},
        {0xb6, 0x16, 0x00, 0xcc},
        {0xb6, 0x22, 0x12, 0xcc},
        {0xb6, 0x23, 0x0b, 0xcc},
-       {0xb3, 0x02, 0x02, 0xcc},
-       {0xbf, 0xc0, 0x39, 0xcc},
-       {0xbf, 0xc1, 0x04, 0xcc},
-       {0xbf, 0xcc, 0x10, 0xcc},
-       {0xb9, 0x12, 0x00, 0xcc},
-       {0xb9, 0x13, 0x0a, 0xcc},
-       {0xb9, 0x14, 0x0a, 0xcc},
-       {0xb9, 0x15, 0x0a, 0xcc},
-       {0xb9, 0x16, 0x0a, 0xcc},
-       {0xb9, 0x18, 0x00, 0xcc},
-       {0xb9, 0x19, 0x0f, 0xcc},
-       {0xb9, 0x1a, 0x0f, 0xcc},
-       {0xb9, 0x1b, 0x0f, 0xcc},
-       {0xb9, 0x1c, 0x0f, 0xcc},
-       {0xb8, 0x8e, 0x00, 0xcc},
-       {0xb8, 0x8f, 0xff, 0xcc},
-       {0xb3, 0x01, 0x41, 0xcc},
-       {0x03, 0x03, 0xc0, 0xbb},
-       {0x06, 0x00, 0x10, 0xbb},
-       {0xb6, 0x12, 0xf8, 0xcc},
-       {0xb8, 0x0c, 0x20, 0xcc},
-       {0xb8, 0x0d, 0x70, 0xcc},
-       {0xb6, 0x13, 0x13, 0xcc},
-       {0x2f, 0x00, 0xC0, 0xbb},
-       {0xb8, 0xa0, 0x12, 0xcc},
-       {},
-};
-static const __u8 mi1310_socinitQVGA_JPG[][4] = {
-       {0xb0, 0x03, 0x19, 0xcc},
-       {0xb0, 0x04, 0x02, 0xcc},
-       {0xb3, 0x00, 0x24, 0xcc},
-       {0xb3, 0x00, 0x25, 0xcc},
-       {0xb3, 0x05, 0x01, 0xcc},
-       {0xb3, 0x06, 0x03, 0xcc},
-       {0xb3, 0x5c, 0x01, 0xcc},
-       {0xb3, 0x08, 0x01, 0xcc},
-       {0xb3, 0x09, 0x0c, 0xcc},
-       {0xb3, 0x34, 0x02, 0xcc},
-       {0xb3, 0x35, 0xdd, 0xcc},
-       {0xb3, 0x03, 0x0a, 0xcc},
-       {0xb3, 0x04, 0x0d, 0xcc},
-       {0xb3, 0x20, 0x00, 0xcc},
-       {0xb3, 0x21, 0x00, 0xcc},
-       {0xb3, 0x22, 0x01, 0xcc},
-       {0xb3, 0x23, 0xe0, 0xcc},
-       {0xb3, 0x14, 0x00, 0xcc},
-       {0xb3, 0x15, 0x00, 0xcc},
-       {0xb3, 0x16, 0x02, 0xcc},
-       {0xb3, 0x17, 0x7f, 0xcc},
-       {0xb8, 0x01, 0x7d, 0xcc},
-       {0xb8, 0x81, 0x09, 0xcc},
-       {0xb8, 0x27, 0x20, 0xcc},
-       {0xb8, 0x26, 0x80, 0xcc},
-       {0xb3, 0x00, 0x25, 0xcc},
-       {0xb8, 0x00, 0x13, 0xcc},
-       {0xbc, 0x00, 0xd1, 0xcc},
-       {0xb8, 0x81, 0x01, 0xcc},
-       {0xb8, 0x2c, 0x5a, 0xcc},
-       {0xb8, 0x2d, 0xff, 0xcc},
-       {0xb8, 0x2e, 0xee, 0xcc},
-       {0xb8, 0x2f, 0xfb, 0xcc},
-       {0xb8, 0x30, 0x52, 0xcc},
-       {0xb8, 0x31, 0xf8, 0xcc},
-       {0xb8, 0x32, 0xf1, 0xcc},
-       {0xb8, 0x33, 0xff, 0xcc},
-       {0xb8, 0x34, 0x54, 0xcc},
-       {0xb8, 0x35, 0x00, 0xcc},
-       {0xb8, 0x36, 0x00, 0xcc},
-       {0xb8, 0x37, 0x00, 0xcc},
-       {0xf0, 0x00, 0x00, 0xbb},
-       {0x00, 0x01, 0x00, 0xdd},
-       {0x0d, 0x00, 0x09, 0xbb},
-       {0x0d, 0x00, 0x08, 0xbb},
-       {0xf0, 0x00, 0x01, 0xbb},
-       {0x00, 0x01, 0x00, 0xdd},
-       {0x06, 0x00, 0x14, 0xbb},
-       {0x3a, 0x10, 0x00, 0xbb},
-       {0x00, 0x00, 0x10, 0xdd},
-       {0x9b, 0x10, 0x00, 0xbb},
-       {0x00, 0x00, 0x10, 0xdd},
-       {0xf0, 0x00, 0x00, 0xbb},
-       {0x00, 0x01, 0x00, 0xdd},
-       {0x2b, 0x00, 0x28, 0xbb},
-       {0x2c, 0x00, 0x30, 0xbb},
-       {0x2d, 0x00, 0x30, 0xbb},
-       {0x2e, 0x00, 0x28, 0xbb},
-       {0x41, 0x00, 0xd7, 0xbb},
-       {0x09, 0x02, 0x3a, 0xbb},
-       {0x0c, 0x00, 0x00, 0xbb},
-       {0x20, 0x00, 0x00, 0xbb},
-       {0x05, 0x00, 0x8c, 0xbb},
-       {0x06, 0x00, 0x32, 0xbb},
-       {0x07, 0x00, 0xc6, 0xbb},
-       {0x08, 0x00, 0x19, 0xbb},
-       {0x24, 0x80, 0x6f, 0xbb},
-       {0xc8, 0x00, 0x0f, 0xbb},
-       {0x20, 0x00, 0x0f, 0xbb},
-       {0xb6, 0x00, 0x00, 0xcc},
-       {0xb6, 0x03, 0x01, 0xcc},
-       {0xb6, 0x02, 0x40, 0xcc},
-       {0xb6, 0x05, 0x00, 0xcc},
-       {0xb6, 0x04, 0xf0, 0xcc},
-       {0xb6, 0x12, 0x78, 0xcc},
-       {0xb6, 0x18, 0x00, 0xcc},
-       {0xb6, 0x17, 0x96, 0xcc},
-       {0xb6, 0x16, 0x00, 0xcc},
-       {0xb6, 0x22, 0x12, 0xcc},
-       {0xb6, 0x23, 0x0b, 0xcc},
-       {0xb3, 0x02, 0x02, 0xcc},
        {0xbf, 0xc0, 0x39, 0xcc},
        {0xbf, 0xc1, 0x04, 0xcc},
-       {0xbf, 0xcc, 0x10, 0xcc},
-       {0xb9, 0x12, 0x00, 0xcc},
-       {0xb9, 0x13, 0x0a, 0xcc},
-       {0xb9, 0x14, 0x0a, 0xcc},
-       {0xb9, 0x15, 0x0a, 0xcc},
-       {0xb9, 0x16, 0x0a, 0xcc},
-       {0xb9, 0x18, 0x00, 0xcc},
-       {0xb9, 0x19, 0x0f, 0xcc},
-       {0xb9, 0x1a, 0x0f, 0xcc},
-       {0xb9, 0x1b, 0x0f, 0xcc},
-       {0xb9, 0x1c, 0x0f, 0xcc},
-       {0xb8, 0x8e, 0x00, 0xcc},
-       {0xb8, 0x8f, 0xff, 0xcc},
+       {0xbf, 0xcc, 0x00, 0xcc},
        {0xbc, 0x02, 0x18, 0xcc},
        {0xbc, 0x03, 0x50, 0xcc},
        {0xbc, 0x04, 0x18, 0xcc},
@@ -636,133 +524,335 @@ static const __u8 mi1310_socinitQVGA_JPG[][4] = {
        {0xbc, 0x0a, 0x10, 0xcc},
        {0xbc, 0x0b, 0x00, 0xcc},
        {0xbc, 0x0c, 0x00, 0xcc},
+       {0xb3, 0x5c, 0x01, 0xcc},
+       {0xf0, 0x00, 0x01, 0xbb},
+       {0x80, 0x00, 0x03, 0xbb},
+       {0x81, 0xc7, 0x14, 0xbb},
+       {0x82, 0xeb, 0xe8, 0xbb},
+       {0x83, 0xfe, 0xf4, 0xbb},
+       {0x84, 0xcd, 0x10, 0xbb},
+       {0x85, 0xf3, 0xee, 0xbb},
+       {0x86, 0xff, 0xf1, 0xbb},
+       {0x87, 0xcd, 0x10, 0xbb},
+       {0x88, 0xf3, 0xee, 0xbb},
+       {0x89, 0x01, 0xf1, 0xbb},
+       {0x8a, 0xe5, 0x17, 0xbb},
+       {0x8b, 0xe8, 0xe2, 0xbb},
+       {0x8c, 0xf7, 0xed, 0xbb},
+       {0x8d, 0x00, 0xff, 0xbb},
+       {0x8e, 0xec, 0x10, 0xbb},
+       {0x8f, 0xf0, 0xed, 0xbb},
+       {0x90, 0xf9, 0xf2, 0xbb},
+       {0x91, 0x00, 0x00, 0xbb},
+       {0x92, 0xe9, 0x0d, 0xbb},
+       {0x93, 0xf4, 0xf2, 0xbb},
+       {0x94, 0xfb, 0xf5, 0xbb},
+       {0x95, 0x00, 0xff, 0xbb},
+       {0xb6, 0x0f, 0x08, 0xbb},
+       {0xb7, 0x3d, 0x16, 0xbb},
+       {0xb8, 0x0c, 0x04, 0xbb},
+       {0xb9, 0x1c, 0x07, 0xbb},
+       {0xba, 0x0a, 0x03, 0xbb},
+       {0xbb, 0x1b, 0x09, 0xbb},
+       {0xbc, 0x17, 0x0d, 0xbb},
+       {0xbd, 0x23, 0x1d, 0xbb},
+       {0xbe, 0x00, 0x28, 0xbb},
+       {0xbf, 0x11, 0x09, 0xbb},
+       {0xc0, 0x16, 0x15, 0xbb},
+       {0xc1, 0x00, 0x1b, 0xbb},
+       {0xc2, 0x0e, 0x07, 0xbb},
+       {0xc3, 0x14, 0x10, 0xbb},
+       {0xc4, 0x00, 0x17, 0xbb},
+       {0x06, 0x74, 0x8e, 0xbb},
+       {0xf0, 0x00, 0x01, 0xbb},
+       {0x06, 0xf4, 0x8e, 0xbb},
+       {0x00, 0x00, 0x50, 0xdd},
+       {0x06, 0x74, 0x8e, 0xbb},
+       {0xf0, 0x00, 0x02, 0xbb},
+       {0x24, 0x50, 0x20, 0xbb},
+       {0xf0, 0x00, 0x02, 0xbb},
+       {0x34, 0x0c, 0x50, 0xbb},
        {0xb3, 0x01, 0x41, 0xcc},
+       {0xf0, 0x00, 0x00, 0xbb},
+       {0x03, 0x03, 0xc0, 0xbb},
+       {},
+};
+static const u8 mi1310_socinitQVGA_JPG[][4] = {
+       {0xb0, 0x03, 0x19, 0xcc},       {0xb0, 0x04, 0x02, 0xcc},
+       {0xb3, 0x00, 0x64, 0xcc},       {0xb3, 0x00, 0x65, 0xcc},
+       {0xb3, 0x05, 0x00, 0xcc},       {0xb3, 0x06, 0x00, 0xcc},
+       {0xb3, 0x08, 0x01, 0xcc},       {0xb3, 0x09, 0x0c, 0xcc},
+       {0xb3, 0x34, 0x02, 0xcc},       {0xb3, 0x35, 0xdd, 0xcc},
+       {0xb3, 0x02, 0x00, 0xcc},       {0xb3, 0x03, 0x0a, 0xcc},
+       {0xb3, 0x04, 0x05, 0xcc},       {0xb3, 0x20, 0x00, 0xcc},
+       {0xb3, 0x21, 0x00, 0xcc},       {0xb3, 0x22, 0x03, 0xcc},
+       {0xb3, 0x23, 0xc0, 0xcc},       {0xb3, 0x14, 0x00, 0xcc},
+       {0xb3, 0x15, 0x00, 0xcc},       {0xb3, 0x16, 0x04, 0xcc},
+       {0xb3, 0x17, 0xff, 0xcc},       {0xb3, 0x00, 0x65, 0xcc},
+       {0xb8, 0x00, 0x00, 0xcc},       {0xbc, 0x00, 0xf0, 0xcc},
+       {0xbc, 0x01, 0x01, 0xcc},       {0xf0, 0x00, 0x02, 0xbb},
+       {0xc8, 0x9f, 0x0b, 0xbb},       {0x5b, 0x00, 0x01, 0xbb},
+       {0x2f, 0xde, 0x20, 0xbb},       {0xf0, 0x00, 0x00, 0xbb},
+       {0x20, 0x03, 0x02, 0xbb},       /* h/v flip */
+       {0xf0, 0x00, 0x01, 0xbb},
+       {0x05, 0x00, 0x07, 0xbb},       {0x34, 0x00, 0x00, 0xbb},
+       {0x35, 0xff, 0x00, 0xbb},       {0xdc, 0x07, 0x02, 0xbb},
+       {0xdd, 0x3c, 0x18, 0xbb},       {0xde, 0x92, 0x6d, 0xbb},
+       {0xdf, 0xcd, 0xb1, 0xbb},       {0xe0, 0xff, 0xe7, 0xbb},
+       {0x06, 0xf0, 0x0d, 0xbb},       {0x06, 0x70, 0x0e, 0xbb},
+       {0x4c, 0x00, 0x01, 0xbb},       {0x4d, 0x00, 0x01, 0xbb},
+       {0xf0, 0x00, 0x02, 0xbb},       {0x2e, 0x0c, 0x55, 0xbb},
+       {0x21, 0xb6, 0x6e, 0xbb},       {0x36, 0x30, 0x10, 0xbb},
+       {0x37, 0x00, 0xc1, 0xbb},       {0xf0, 0x00, 0x00, 0xbb},
+       {0x07, 0x00, 0x84, 0xbb},       {0x08, 0x02, 0x4a, 0xbb},
+       {0x05, 0x01, 0x10, 0xbb},       {0x06, 0x00, 0x39, 0xbb},
+       {0xf0, 0x00, 0x02, 0xbb},       {0x58, 0x02, 0x67, 0xbb},
+       {0x57, 0x02, 0x00, 0xbb},       {0x5a, 0x02, 0x67, 0xbb},
+       {0x59, 0x02, 0x00, 0xbb},       {0x5c, 0x12, 0x0d, 0xbb},
+       {0x5d, 0x16, 0x11, 0xbb},       {0x39, 0x06, 0x18, 0xbb},
+       {0x3a, 0x06, 0x18, 0xbb},       {0x3b, 0x06, 0x18, 0xbb},
+       {0x3c, 0x06, 0x18, 0xbb},       {0x64, 0x7b, 0x5b, 0xbb},
+       {0xf0, 0x00, 0x02, 0xbb},       {0x36, 0x30, 0x10, 0xbb},
+       {0x37, 0x00, 0xc0, 0xbb},       {0xbc, 0x0e, 0x00, 0xcc},
+       {0xbc, 0x0f, 0x05, 0xcc},       {0xbc, 0x10, 0xc0, 0xcc},
+       {0xbc, 0x11, 0x03, 0xcc},       {0xb6, 0x00, 0x00, 0xcc},
+       {0xb6, 0x03, 0x01, 0xcc},       {0xb6, 0x02, 0x40, 0xcc},
+       {0xb6, 0x05, 0x00, 0xcc},       {0xb6, 0x04, 0xf0, 0xcc},
+       {0xb6, 0x12, 0xf8, 0xcc},       {0xb6, 0x13, 0x25, 0xcc},
+       {0xb6, 0x18, 0x00, 0xcc},       {0xb6, 0x17, 0x96, 0xcc},
+       {0xb6, 0x16, 0x00, 0xcc},       {0xb6, 0x22, 0x12, 0xcc},
+       {0xb6, 0x23, 0x0b, 0xcc},       {0xbf, 0xc0, 0x39, 0xcc},
+       {0xbf, 0xc1, 0x04, 0xcc},       {0xbf, 0xcc, 0x00, 0xcc},
+       {0xb3, 0x5c, 0x01, 0xcc},       {0xf0, 0x00, 0x01, 0xbb},
+       {0x80, 0x00, 0x03, 0xbb},       {0x81, 0xc7, 0x14, 0xbb},
+       {0x82, 0xeb, 0xe8, 0xbb},       {0x83, 0xfe, 0xf4, 0xbb},
+       {0x84, 0xcd, 0x10, 0xbb},       {0x85, 0xf3, 0xee, 0xbb},
+       {0x86, 0xff, 0xf1, 0xbb},       {0x87, 0xcd, 0x10, 0xbb},
+       {0x88, 0xf3, 0xee, 0xbb},       {0x89, 0x01, 0xf1, 0xbb},
+       {0x8a, 0xe5, 0x17, 0xbb},       {0x8b, 0xe8, 0xe2, 0xbb},
+       {0x8c, 0xf7, 0xed, 0xbb},       {0x8d, 0x00, 0xff, 0xbb},
+       {0x8e, 0xec, 0x10, 0xbb},       {0x8f, 0xf0, 0xed, 0xbb},
+       {0x90, 0xf9, 0xf2, 0xbb},       {0x91, 0x00, 0x00, 0xbb},
+       {0x92, 0xe9, 0x0d, 0xbb},       {0x93, 0xf4, 0xf2, 0xbb},
+       {0x94, 0xfb, 0xf5, 0xbb},       {0x95, 0x00, 0xff, 0xbb},
+       {0xb6, 0x0f, 0x08, 0xbb},       {0xb7, 0x3d, 0x16, 0xbb},
+       {0xb8, 0x0c, 0x04, 0xbb},       {0xb9, 0x1c, 0x07, 0xbb},
+       {0xba, 0x0a, 0x03, 0xbb},       {0xbb, 0x1b, 0x09, 0xbb},
+       {0xbc, 0x17, 0x0d, 0xbb},       {0xbd, 0x23, 0x1d, 0xbb},
+       {0xbe, 0x00, 0x28, 0xbb},       {0xbf, 0x11, 0x09, 0xbb},
+       {0xc0, 0x16, 0x15, 0xbb},       {0xc1, 0x00, 0x1b, 0xbb},
+       {0xc2, 0x0e, 0x07, 0xbb},       {0xc3, 0x14, 0x10, 0xbb},
+       {0xc4, 0x00, 0x17, 0xbb},       {0x06, 0x74, 0x8e, 0xbb},
+       {0xf0, 0x00, 0x01, 0xbb},       {0x06, 0xf4, 0x8e, 0xbb},
+       {0x00, 0x00, 0x50, 0xdd},       {0x06, 0x74, 0x8e, 0xbb},
+       {0xf0, 0x00, 0x02, 0xbb},       {0x24, 0x50, 0x20, 0xbb},
+       {0xf0, 0x00, 0x02, 0xbb},       {0x34, 0x0c, 0x50, 0xbb},
+       {0xb3, 0x01, 0x41, 0xcc},       {0xf0, 0x00, 0x00, 0xbb},
        {0x03, 0x03, 0xc0, 0xbb},
-       {0x06, 0x00, 0x10, 0xbb},
-       {0xb6, 0x12, 0xf8, 0xcc},
-       {0xb8, 0x0c, 0x20, 0xcc},
-       {0xb8, 0x0d, 0x70, 0xcc},
-       {0xb6, 0x13, 0x13, 0xcc},
-       {0x2f, 0x00, 0xC0, 0xbb},
-       {0xb8, 0xa0, 0x12, 0xcc},
        {},
 };
 static const u8 mi1310_soc_InitSXGA_JPG[][4] = {
        {0xb0, 0x03, 0x19, 0xcc},
        {0xb0, 0x04, 0x02, 0xcc},
-       {0xb3, 0x00, 0x24, 0xcc},
-       {0xb3, 0x00, 0x25, 0xcc},
+       {0xb3, 0x00, 0x64, 0xcc},
+       {0xb3, 0x00, 0x65, 0xcc},
        {0xb3, 0x05, 0x00, 0xcc},
-       {0xb3, 0x06, 0x01, 0xcc},
-       {0xb3, 0x5c, 0x01, 0xcc},
+       {0xb3, 0x06, 0x00, 0xcc},
        {0xb3, 0x08, 0x01, 0xcc},
        {0xb3, 0x09, 0x0c, 0xcc},
        {0xb3, 0x34, 0x02, 0xcc},
        {0xb3, 0x35, 0xdd, 0xcc},
+       {0xb3, 0x02, 0x00, 0xcc},
        {0xb3, 0x03, 0x0a, 0xcc},
        {0xb3, 0x04, 0x0d, 0xcc},
        {0xb3, 0x20, 0x00, 0xcc},
        {0xb3, 0x21, 0x00, 0xcc},
-       {0xb3, 0x22, 0x04, 0xcc},
-       {0xb3, 0x23, 0x00, 0xcc},
+       {0xb3, 0x22, 0x03, 0xcc},
+       {0xb3, 0x23, 0xc0, 0xcc},
        {0xb3, 0x14, 0x00, 0xcc},
        {0xb3, 0x15, 0x00, 0xcc},
        {0xb3, 0x16, 0x04, 0xcc},
        {0xb3, 0x17, 0xff, 0xcc},
-       {0xb8, 0x01, 0x7d, 0xcc},
-       {0xb8, 0x81, 0x09, 0xcc},
-       {0xb8, 0x27, 0x20, 0xcc},
-       {0xb8, 0x26, 0x80, 0xcc},
-       {0xb8, 0x06, 0x00, 0xcc},
-       {0xb8, 0x07, 0x05, 0xcc},
-       {0xb8, 0x08, 0x00, 0xcc},
-       {0xb8, 0x09, 0x04, 0xcc},
-       {0xb3, 0x00, 0x25, 0xcc},
-       {0xb8, 0x00, 0x11, 0xcc},
-       {0xbc, 0x00, 0x71, 0xcc},
-       {0xb8, 0x81, 0x01, 0xcc},
-       {0xb8, 0x2c, 0x5a, 0xcc},
-       {0xb8, 0x2d, 0xff, 0xcc},
-       {0xb8, 0x2e, 0xee, 0xcc},
-       {0xb8, 0x2f, 0xfb, 0xcc},
-       {0xb8, 0x30, 0x52, 0xcc},
-       {0xb8, 0x31, 0xf8, 0xcc},
-       {0xb8, 0x32, 0xf1, 0xcc},
-       {0xb8, 0x33, 0xff, 0xcc},
-       {0xb8, 0x34, 0x54, 0xcc},
+       {0xb3, 0x00, 0x65, 0xcc},
+       {0xb8, 0x00, 0x00, 0xcc},
+       {0xbc, 0x00, 0x70, 0xcc},
+       {0xbc, 0x01, 0x01, 0xcc},
+       {0xf0, 0x00, 0x02, 0xbb},
+       {0xc8, 0x9f, 0x0b, 0xbb},
+       {0x5b, 0x00, 0x01, 0xbb},
        {0xf0, 0x00, 0x00, 0xbb},
-       {0x00, 0x01, 0x00, 0xdd},
-       {0x0d, 0x00, 0x09, 0xbb},
-       {0x0d, 0x00, 0x08, 0xbb},
+       {0x20, 0x03, 0x02, 0xbb},       /* h/v flip */
        {0xf0, 0x00, 0x01, 0xbb},
-       {0x00, 0x01, 0x00, 0xdd},
-       {0x06, 0x00, 0x14, 0xbb},
-       {0x3a, 0x10, 0x00, 0xbb},
-       {0x00, 0x00, 0x10, 0xdd},
-       {0x9b, 0x10, 0x00, 0xbb},
-       {0x00, 0x00, 0x10, 0xdd},
+       {0x05, 0x00, 0x07, 0xbb},
+       {0x34, 0x00, 0x00, 0xbb},
+       {0x35, 0xff, 0x00, 0xbb},
+       {0xdc, 0x07, 0x02, 0xbb},
+       {0xdd, 0x3c, 0x18, 0xbb},
+       {0xde, 0x92, 0x6d, 0xbb},
+       {0xdf, 0xcd, 0xb1, 0xbb},
+       {0xe0, 0xff, 0xe7, 0xbb},
+       {0x06, 0xf0, 0x0d, 0xbb},
+       {0x06, 0x70, 0x0e, 0xbb},
+       {0x4c, 0x00, 0x01, 0xbb},
+       {0x4d, 0x00, 0x01, 0xbb},
+       {0xf0, 0x00, 0x02, 0xbb},
+       {0x2e, 0x0c, 0x60, 0xbb},
+       {0x21, 0xb6, 0x6e, 0xbb},
+       {0x37, 0x01, 0x40, 0xbb},
        {0xf0, 0x00, 0x00, 0xbb},
-       {0x00, 0x01, 0x00, 0xdd},
-       {0x2b, 0x00, 0x28, 0xbb},
-       {0x2c, 0x00, 0x30, 0xbb},
-       {0x2d, 0x00, 0x30, 0xbb},
-       {0x2e, 0x00, 0x28, 0xbb},
-       {0x41, 0x00, 0xd7, 0xbb},
-       {0x09, 0x02, 0x3a, 0xbb},
-       {0x0c, 0x00, 0x00, 0xbb},
-       {0x20, 0x00, 0x00, 0xbb},
-       {0x05, 0x00, 0x8c, 0xbb},
-       {0x06, 0x00, 0x32, 0xbb},
-       {0x07, 0x00, 0xc6, 0xbb},
-       {0x08, 0x00, 0x19, 0xbb},
-       {0x24, 0x80, 0x6f, 0xbb},
-       {0xc8, 0x00, 0x0f, 0xbb},
-       {0x20, 0x00, 0x03, 0xbb},
+       {0x07, 0x00, 0x84, 0xbb},
+       {0x08, 0x02, 0x4a, 0xbb},
+       {0x05, 0x01, 0x10, 0xbb},
+       {0x06, 0x00, 0x39, 0xbb},
+       {0xf0, 0x00, 0x02, 0xbb},
+       {0x58, 0x02, 0x67, 0xbb},
+       {0x57, 0x02, 0x00, 0xbb},
+       {0x5a, 0x02, 0x67, 0xbb},
+       {0x59, 0x02, 0x00, 0xbb},
+       {0x5c, 0x12, 0x0d, 0xbb},
+       {0x5d, 0x16, 0x11, 0xbb},
+       {0x39, 0x06, 0x18, 0xbb},
+       {0x3a, 0x06, 0x18, 0xbb},
+       {0x3b, 0x06, 0x18, 0xbb},
+       {0x3c, 0x06, 0x18, 0xbb},
+       {0x64, 0x7b, 0x5b, 0xbb},
        {0xb6, 0x00, 0x00, 0xcc},
        {0xb6, 0x03, 0x05, 0xcc},
        {0xb6, 0x02, 0x00, 0xcc},
-       {0xb6, 0x05, 0x04, 0xcc},
-       {0xb6, 0x04, 0x00, 0xcc},
+       {0xb6, 0x05, 0x03, 0xcc},
+       {0xb6, 0x04, 0xc0, 0xcc},
        {0xb6, 0x12, 0xf8, 0xcc},
-       {0xb6, 0x18, 0x0a, 0xcc},
-       {0xb6, 0x17, 0x00, 0xcc},
+       {0xb6, 0x13, 0x29, 0xcc},
+       {0xb6, 0x18, 0x09, 0xcc},
+       {0xb6, 0x17, 0x60, 0xcc},
        {0xb6, 0x16, 0x00, 0xcc},
        {0xb6, 0x22, 0x12, 0xcc},
        {0xb6, 0x23, 0x0b, 0xcc},
-       {0xb3, 0x02, 0x02, 0xcc},
        {0xbf, 0xc0, 0x39, 0xcc},
        {0xbf, 0xc1, 0x04, 0xcc},
-       {0xbf, 0xcc, 0x10, 0xcc},
-       {0xb9, 0x12, 0x00, 0xcc},
-       {0xb9, 0x13, 0x14, 0xcc},
-       {0xb9, 0x14, 0x14, 0xcc},
-       {0xb9, 0x15, 0x14, 0xcc},
-       {0xb9, 0x16, 0x14, 0xcc},
-       {0xb9, 0x18, 0x00, 0xcc},
-       {0xb9, 0x19, 0x1e, 0xcc},
-       {0xb9, 0x1a, 0x1e, 0xcc},
-       {0xb9, 0x1b, 0x1e, 0xcc},
-       {0xb9, 0x1c, 0x1e, 0xcc},
+       {0xbf, 0xcc, 0x00, 0xcc},
        {0xb3, 0x01, 0x41, 0xcc},
-       {0xb8, 0x8e, 0x00, 0xcc},
-       {0xb8, 0x8f, 0xff, 0xcc},
-       {0xb6, 0x12, 0xf8, 0xcc},
-       {0xb8, 0x0c, 0x20, 0xcc},
-       {0xb8, 0x0d, 0x70, 0xcc},
-       {0xb6, 0x13, 0x13, 0xcc},
-       {0x2f, 0x00, 0xC0, 0xbb},
-       {0xb8, 0xa0, 0x12, 0xcc},
+       {0x00, 0x00, 0x80, 0xdd},
+       {0xf0, 0x00, 0x02, 0xbb},
+       {0x00, 0x00, 0x10, 0xdd},
+       {0x22, 0xa0, 0x78, 0xbb},
+       {0x23, 0xa0, 0x78, 0xbb},
+       {0x24, 0x7f, 0x00, 0xbb},
+       {0x28, 0xea, 0x02, 0xbb},
+       {0x29, 0x86, 0x7a, 0xbb},
+       {0x5e, 0x52, 0x4c, 0xbb},
+       {0x5f, 0x20, 0x24, 0xbb},
+       {0x60, 0x00, 0x02, 0xbb},
+       {0x02, 0x00, 0xee, 0xbb},
+       {0x03, 0x39, 0x23, 0xbb},
+       {0x04, 0x07, 0x24, 0xbb},
+       {0x09, 0x00, 0xc0, 0xbb},
+       {0x0a, 0x00, 0x79, 0xbb},
+       {0x0b, 0x00, 0x04, 0xbb},
+       {0x0c, 0x00, 0x5c, 0xbb},
+       {0x0d, 0x00, 0xd9, 0xbb},
+       {0x0e, 0x00, 0x53, 0xbb},
+       {0x0f, 0x00, 0x21, 0xbb},
+       {0x10, 0x00, 0xa4, 0xbb},
+       {0x11, 0x00, 0xe5, 0xbb},
+       {0x15, 0x00, 0x00, 0xbb},
+       {0x16, 0x00, 0x00, 0xbb},
+       {0x17, 0x00, 0x00, 0xbb},
+       {0x18, 0x00, 0x00, 0xbb},
+       {0x19, 0x00, 0x00, 0xbb},
+       {0x1a, 0x00, 0x00, 0xbb},
+       {0x1b, 0x00, 0x00, 0xbb},
+       {0x1c, 0x00, 0x00, 0xbb},
+       {0x1d, 0x00, 0x00, 0xbb},
+       {0x1e, 0x00, 0x00, 0xbb},
+       {0xf0, 0x00, 0x01, 0xbb},
+       {0x00, 0x00, 0x20, 0xdd},
+       {0x06, 0xf0, 0x8e, 0xbb},
+       {0x00, 0x00, 0x80, 0xdd},
+       {0x06, 0x70, 0x8e, 0xbb},
+       {0xf0, 0x00, 0x02, 0xbb},
+       {0x00, 0x00, 0x20, 0xdd},
+       {0x5e, 0x6a, 0x53, 0xbb},
+       {0x5f, 0x40, 0x2c, 0xbb},
+       {0xf0, 0x00, 0x01, 0xbb},
+       {0x00, 0x00, 0x20, 0xdd},
+       {0x58, 0x00, 0x00, 0xbb},
+       {0x53, 0x09, 0x03, 0xbb},
+       {0x54, 0x31, 0x18, 0xbb},
+       {0x55, 0x8b, 0x5f, 0xbb},
+       {0x56, 0xc0, 0xa9, 0xbb},
+       {0x57, 0xe0, 0xd2, 0xbb},
+       {0xe1, 0x00, 0x00, 0xbb},
+       {0xdc, 0x09, 0x03, 0xbb},
+       {0xdd, 0x31, 0x18, 0xbb},
+       {0xde, 0x8b, 0x5f, 0xbb},
+       {0xdf, 0xc0, 0xa9, 0xbb},
+       {0xe0, 0xe0, 0xd2, 0xbb},
+       {0xb3, 0x5c, 0x01, 0xcc},
+       {0xf0, 0x00, 0x01, 0xbb},
+       {0x06, 0xf0, 0x8e, 0xbb},
+       {0xf0, 0x00, 0x02, 0xbb},
+       {0x2f, 0xde, 0x20, 0xbb},
+       {0xf0, 0x00, 0x02, 0xbb},
+       {0x24, 0x50, 0x20, 0xbb},
+       {0xbc, 0x0e, 0x00, 0xcc},
+       {0xbc, 0x0f, 0x05, 0xcc},
+       {0xbc, 0x10, 0xc0, 0xcc},
+       {0xf0, 0x00, 0x02, 0xbb},
+       {0x34, 0x0c, 0x50, 0xbb},
+       {0xbc, 0x11, 0x03, 0xcc},
+       {0xf0, 0x00, 0x01, 0xbb},
+       {0x80, 0x00, 0x03, 0xbb},
+       {0x81, 0xc7, 0x14, 0xbb},
+       {0x82, 0xeb, 0xe8, 0xbb},
+       {0x83, 0xfe, 0xf4, 0xbb},
+       {0x84, 0xcd, 0x10, 0xbb},
+       {0x85, 0xf3, 0xee, 0xbb},
+       {0x86, 0xff, 0xf1, 0xbb},
+       {0x87, 0xcd, 0x10, 0xbb},
+       {0x88, 0xf3, 0xee, 0xbb},
+       {0x89, 0x01, 0xf1, 0xbb},
+       {0x8a, 0xe5, 0x17, 0xbb},
+       {0x8b, 0xe8, 0xe2, 0xbb},
+       {0x8c, 0xf7, 0xed, 0xbb},
+       {0x8d, 0x00, 0xff, 0xbb},
+       {0x8e, 0xec, 0x10, 0xbb},
+       {0x8f, 0xf0, 0xed, 0xbb},
+       {0x90, 0xf9, 0xf2, 0xbb},
+       {0x91, 0x00, 0x00, 0xbb},
+       {0x92, 0xe9, 0x0d, 0xbb},
+       {0x93, 0xf4, 0xf2, 0xbb},
+       {0x94, 0xfb, 0xf5, 0xbb},
+       {0x95, 0x00, 0xff, 0xbb},
+       {0xb6, 0x0f, 0x08, 0xbb},
+       {0xb7, 0x3d, 0x16, 0xbb},
+       {0xb8, 0x0c, 0x04, 0xbb},
+       {0xb9, 0x1c, 0x07, 0xbb},
+       {0xba, 0x0a, 0x03, 0xbb},
+       {0xbb, 0x1b, 0x09, 0xbb},
+       {0xbc, 0x17, 0x0d, 0xbb},
+       {0xbd, 0x23, 0x1d, 0xbb},
+       {0xbe, 0x00, 0x28, 0xbb},
+       {0xbf, 0x11, 0x09, 0xbb},
+       {0xc0, 0x16, 0x15, 0xbb},
+       {0xc1, 0x00, 0x1b, 0xbb},
+       {0xc2, 0x0e, 0x07, 0xbb},
+       {0xc3, 0x14, 0x10, 0xbb},
+       {0xc4, 0x00, 0x17, 0xbb},
+       {0x06, 0x74, 0x8e, 0xbb},
+       {0xf0, 0x00, 0x00, 0xbb},
+       {0x03, 0x03, 0xc0, 0xbb},
        {}
 };
 
-static const __u8 mi1320_gamma[17] = {
+static const u8 mi1320_gamma[17] = {
        0x00, 0x13, 0x38, 0x59, 0x79, 0x92, 0xa7, 0xb9, 0xc8,
        0xd4, 0xdf, 0xe7, 0xee, 0xf4, 0xf9, 0xfc, 0xff
 };
-static const __u8 mi1320_matrix[9] = {
+static const u8 mi1320_matrix[9] = {
        0x54, 0xda, 0x06, 0xf1, 0x50, 0xf4, 0xf7, 0xea, 0x52
 };
-static const __u8 mi1320_initVGA_data[][4] = {
+static const u8 mi1320_initVGA_data[][4] = {
        {0xb3, 0x01, 0x01, 0xcc},       {0x00, 0x00, 0x33, 0xdd},
        {0xb0, 0x03, 0x19, 0xcc},       {0x00, 0x00, 0x33, 0xdd},
        {0xb0, 0x04, 0x02, 0xcc},       {0x00, 0x00, 0x33, 0xdd},
@@ -841,7 +931,7 @@ static const __u8 mi1320_initVGA_data[][4] = {
        {0xb3, 0x5c, 0x01, 0xcc},       {0xb3, 0x01, 0x41, 0xcc},
        {}
 };
-static const __u8 mi1320_initQVGA_data[][4] = {
+static const u8 mi1320_initQVGA_data[][4] = {
        {0xb3, 0x01, 0x01, 0xcc},       {0x00, 0x00, 0x33, 0xdd},
        {0xb0, 0x03, 0x19, 0xcc},       {0x00, 0x00, 0x33, 0xdd},
        {0xb0, 0x04, 0x02, 0xcc},       {0x00, 0x00, 0x33, 0xdd},
@@ -948,7 +1038,7 @@ static const u8 mi1320_soc_InitVGA[][4] = {
        {0x07, 0x00, 0xe0, 0xbb},
        {0x08, 0x00, 0x0b, 0xbb},
        {0x21, 0x00, 0x0c, 0xbb},
-       {0x20, 0x01, 0x03, 0xbb},
+       {0x20, 0x01, 0x03, 0xbb},       /* h/v flip */
        {0xbf, 0xc0, 0x26, 0xcc},
        {0xbf, 0xc1, 0x02, 0xcc},
        {0xbf, 0xcc, 0x04, 0xcc},
@@ -958,7 +1048,7 @@ static const u8 mi1320_soc_InitVGA[][4] = {
        {0x06, 0x00, 0x11, 0xbb},
        {0x07, 0x01, 0x42, 0xbb},
        {0x08, 0x00, 0x11, 0xbb},
-       {0x20, 0x01, 0x03, 0xbb},
+       {0x20, 0x01, 0x03, 0xbb},       /* h/v flip */
        {0x21, 0x80, 0x00, 0xbb},
        {0x22, 0x0d, 0x0f, 0xbb},
        {0x24, 0x80, 0x00, 0xbb},
@@ -1051,7 +1141,7 @@ static const u8 mi1320_soc_InitQVGA[][4] = {
        {0x07, 0x00, 0xe0, 0xbb},
        {0x08, 0x00, 0x0b, 0xbb},
        {0x21, 0x00, 0x0c, 0xbb},
-       {0x20, 0x01, 0x03, 0xbb},
+       {0x20, 0x01, 0x03, 0xbb},       /* h/v flip */
        {0xbf, 0xc0, 0x26, 0xcc},
        {0xbf, 0xc1, 0x02, 0xcc},
        {0xbf, 0xcc, 0x04, 0xcc},
@@ -1071,7 +1161,7 @@ static const u8 mi1320_soc_InitQVGA[][4] = {
        {0x06, 0x00, 0x11, 0xbb},
        {0x07, 0x01, 0x42, 0xbb},
        {0x08, 0x00, 0x11, 0xbb},
-       {0x20, 0x01, 0x03, 0xbb},
+       {0x20, 0x01, 0x03, 0xbb},       /* h/v flip */
        {0x21, 0x80, 0x00, 0xbb},
        {0x22, 0x0d, 0x0f, 0xbb},
        {0x24, 0x80, 0x00, 0xbb},
@@ -1161,7 +1251,7 @@ static const u8 mi1320_soc_InitSXGA[][4] = {
        {0x00, 0x00, 0x20, 0xdd},
        {0xf0, 0x00, 0x00, 0xbb},
        {0x00, 0x00, 0x30, 0xdd},
-       {0x20, 0x01, 0x03, 0xbb},
+       {0x20, 0x01, 0x03, 0xbb},       /* h/v flip */
        {0x00, 0x00, 0x20, 0xdd},
        {0xbf, 0xc0, 0x26, 0xcc},
        {0xbf, 0xc1, 0x02, 0xcc},
@@ -1172,7 +1262,7 @@ static const u8 mi1320_soc_InitSXGA[][4] = {
        {0x06, 0x00, 0x11, 0xbb},
        {0x07, 0x01, 0x42, 0xbb},
        {0x08, 0x00, 0x11, 0xbb},
-       {0x20, 0x01, 0x03, 0xbb},
+       {0x20, 0x01, 0x03, 0xbb},       /* h/v flip */
        {0x21, 0x80, 0x00, 0xbb},
        {0x22, 0x0d, 0x0f, 0xbb},
        {0x24, 0x80, 0x00, 0xbb},
@@ -1230,7 +1320,7 @@ static const u8 mi1320_soc_InitSXGA[][4] = {
        {0x06, 0x00, 0x11, 0xbb},
        {0x07, 0x00, 0x85, 0xbb},
        {0x08, 0x00, 0x27, 0xbb},
-       {0x20, 0x01, 0x03, 0xbb},
+       {0x20, 0x01, 0x03, 0xbb},       /* h/v flip */
        {0x21, 0x80, 0x00, 0xbb},
        {0x22, 0x0d, 0x0f, 0xbb},
        {0x24, 0x80, 0x00, 0xbb},
@@ -1249,15 +1339,15 @@ static const u8 mi1320_soc_InitSXGA[][4] = {
        {0x64, 0x5e, 0x1c, 0xbb},
        {}
 };
-static const __u8 po3130_gamma[17] = {
+static const u8 po3130_gamma[17] = {
        0x00, 0x13, 0x38, 0x59, 0x79, 0x92, 0xa7, 0xb9, 0xc8,
        0xd4, 0xdf, 0xe7, 0xee, 0xf4, 0xf9, 0xfc, 0xff
 };
-static const __u8 po3130_matrix[9] = {
+static const u8 po3130_matrix[9] = {
        0x5f, 0xec, 0xf5, 0xf1, 0x5a, 0xf5, 0xf1, 0xec, 0x63
 };
 
-static const __u8 po3130_initVGA_data[][4] = {
+static const u8 po3130_initVGA_data[][4] = {
        {0xb0, 0x4d, 0x00, 0xcc},       {0xb3, 0x01, 0x01, 0xcc},
        {0x00, 0x00, 0x50, 0xdd},       {0xb0, 0x03, 0x01, 0xcc},
        {0xb3, 0x00, 0x04, 0xcc},       {0xb3, 0x00, 0x24, 0xcc},
@@ -1340,7 +1430,7 @@ static const __u8 po3130_initVGA_data[][4] = {
        {0xb3, 0x5c, 0x00, 0xcc},       {0xb3, 0x01, 0x41, 0xcc},
        {}
 };
-static const __u8 po3130_rundata[][4] = {
+static const u8 po3130_rundata[][4] = {
        {0x00, 0x47, 0x45, 0xaa},       {0x00, 0x48, 0x9b, 0xaa},
        {0x00, 0x49, 0x3a, 0xaa},       {0x00, 0x4a, 0x01, 0xaa},
        {0x00, 0x44, 0x40, 0xaa},
@@ -1355,7 +1445,7 @@ static const __u8 po3130_rundata[][4] = {
        {}
 };
 
-static const __u8 po3130_initQVGA_data[][4] = {
+static const u8 po3130_initQVGA_data[][4] = {
        {0xb0, 0x4d, 0x00, 0xcc},       {0xb3, 0x01, 0x01, 0xcc},
        {0x00, 0x00, 0x50, 0xdd},       {0xb0, 0x03, 0x09, 0xcc},
        {0xb3, 0x00, 0x04, 0xcc},       {0xb3, 0x00, 0x24, 0xcc},
@@ -1441,121 +1531,207 @@ static const __u8 po3130_initQVGA_data[][4] = {
        {}
 };
 
-static const __u8 hv7131r_gamma[17] = {
-/*     0x00, 0x13, 0x38, 0x59, 0x79, 0x92, 0xa7, 0xb9, 0xc8,
- *     0xd4, 0xdf, 0xe7, 0xee, 0xf4, 0xf9, 0xfc, 0xff */
-       0x04, 0x1a, 0x36, 0x55, 0x6f, 0x87, 0x9d, 0xb0, 0xc1,
-       0xcf, 0xda, 0xe4, 0xec, 0xf3, 0xf8, 0xfd, 0xff
+static const u8 hv7131r_gamma[17] = {
+       0x00, 0x13, 0x38, 0x59, 0x79, 0x92, 0xa7, 0xb9, 0xc8,
+       0xd4, 0xdf, 0xe7, 0xee, 0xf4, 0xf9, 0xfc, 0xff
 };
-static const __u8 hv7131r_matrix[9] = {
+static const u8 hv7131r_matrix[9] = {
        0x5f, 0xec, 0xf5, 0xf1, 0x5a, 0xf5, 0xf1, 0xec, 0x63
 };
-static const __u8 hv7131r_initVGA_data[][4] = {
-       {0xb0, 0x4d, 0x00, 0xcc},       {0xb3, 0x01, 0x01, 0xcc},
-       {0x00, 0x00, 0x50, 0xdd},       {0xb0, 0x03, 0x01, 0xcc},
+static const u8 hv7131r_initVGA_data[][4] = {
+       {0xb3, 0x01, 0x01, 0xcc},
+       {0xb0, 0x03, 0x19, 0xcc},
+       {0xb0, 0x04, 0x02, 0xcc},
+       {0x00, 0x00, 0x20, 0xdd},
        {0xb3, 0x00, 0x24, 0xcc},
-       {0xb3, 0x00, 0x25, 0xcc},       {0xb3, 0x08, 0x01, 0xcc},
-       {0xb3, 0x09, 0x0c, 0xcc},       {0xb3, 0x05, 0x00, 0xcc},
-       {0xb3, 0x06, 0x01, 0xcc},
-       {0xb3, 0x01, 0x45, 0xcc},       {0xb3, 0x03, 0x0b, 0xcc},
-       {0xb3, 0x04, 0x05, 0xcc},       {0xb3, 0x20, 0x00, 0xcc},
+       {0xb3, 0x00, 0x25, 0xcc},
+       {0xb3, 0x08, 0x01, 0xcc},
+       {0xb3, 0x09, 0x0c, 0xcc},
+       {0xb3, 0x05, 0x01, 0xcc},
+       {0xb3, 0x06, 0x03, 0xcc},
+       {0xb3, 0x01, 0x45, 0xcc},
+       {0xb3, 0x03, 0x0b, 0xcc},
+       {0xb3, 0x04, 0x05, 0xcc},
+       {0xb3, 0x20, 0x00, 0xcc},
        {0xb3, 0x21, 0x00, 0xcc},
-       {0xb3, 0x22, 0x01, 0xcc},       {0xb3, 0x23, 0xe0, 0xcc},
-       {0xb3, 0x14, 0x00, 0xcc},       {0xb3, 0x15, 0x00, 0xcc},
+       {0xb3, 0x22, 0x01, 0xcc},
+       {0xb3, 0x23, 0xe0, 0xcc},
+       {0xb3, 0x14, 0x00, 0xcc},
+       {0xb3, 0x15, 0x02, 0xcc},
        {0xb3, 0x16, 0x02, 0xcc},
-       {0xb3, 0x17, 0x7f, 0xcc},       {0xb3, 0x34, 0x01, 0xcc},
-       {0xb3, 0x35, 0x91, 0xcc},       {0xb3, 0x00, 0x27, 0xcc},
+       {0xb3, 0x17, 0x7f, 0xcc},
+       {0xb3, 0x34, 0x01, 0xcc},
+       {0xb3, 0x35, 0x91, 0xcc},
+       {0xb3, 0x00, 0x27, 0xcc},
        {0xbc, 0x00, 0x73, 0xcc},
-       {0xb8, 0x00, 0x23, 0xcc},       {0x00, 0x01, 0x0c, 0xaa},
-       {0x00, 0x14, 0x01, 0xaa},       {0x00, 0x15, 0xe6, 0xaa},
-       {0x00, 0x16, 0x02, 0xaa},
-       {0x00, 0x17, 0x86, 0xaa},       {0x00, 0x23, 0x00, 0xaa},
-       {0x00, 0x25, 0x09, 0xaa},       {0x00, 0x26, 0x27, 0xaa},
-       {0x00, 0x27, 0xc0, 0xaa},
-       {0xb8, 0x2c, 0x60, 0xcc},       {0xb8, 0x2d, 0xf8, 0xcc},
-       {0xb8, 0x2e, 0xf8, 0xcc},       {0xb8, 0x2f, 0xf8, 0xcc},
+       {0xb8, 0x00, 0x23, 0xcc},
+       {0xb8, 0x2c, 0x50, 0xcc},
+       {0xb8, 0x2d, 0xf8, 0xcc},
+       {0xb8, 0x2e, 0xf8, 0xcc},
+       {0xb8, 0x2f, 0xf8, 0xcc},
        {0xb8, 0x30, 0x50, 0xcc},
-       {0xb8, 0x31, 0xf8, 0xcc},       {0xb8, 0x32, 0xf8, 0xcc},
-       {0xb8, 0x33, 0xf8, 0xcc},       {0xb8, 0x34, 0x65, 0xcc},
+       {0xb8, 0x31, 0xf8, 0xcc},
+       {0xb8, 0x32, 0xf8, 0xcc},
+       {0xb8, 0x33, 0xf8, 0xcc},
+       {0xb8, 0x34, 0x58, 0xcc},
        {0xb8, 0x35, 0x00, 0xcc},
-       {0xb8, 0x36, 0x00, 0xcc},       {0xb8, 0x37, 0x00, 0xcc},
-       {0xb8, 0x27, 0x20, 0xcc},       {0xb8, 0x01, 0x7d, 0xcc},
+       {0xb8, 0x36, 0x00, 0xcc},
+       {0xb8, 0x37, 0x00, 0xcc},
+       {0xb8, 0x27, 0x20, 0xcc},
+       {0xb8, 0x01, 0x7d, 0xcc},
        {0xb8, 0x81, 0x09, 0xcc},
-       {0xb3, 0x01, 0x41, 0xcc},       {0xb8, 0xfe, 0x00, 0xcc},
-       {0xb8, 0xff, 0x28, 0xcc},       {0xb9, 0x00, 0x28, 0xcc},
-       {0xb9, 0x01, 0x28, 0xcc},
-       {0xb9, 0x02, 0x28, 0xcc},       {0xb9, 0x03, 0x00, 0xcc},
-       {0xb9, 0x04, 0x00, 0xcc},       {0xb9, 0x05, 0x3c, 0xcc},
-       {0xb9, 0x06, 0x3c, 0xcc},
-       {0xb9, 0x07, 0x3c, 0xcc},       {0xb9, 0x08, 0x3c, 0xcc},
-       {0xb8, 0x8e, 0x00, 0xcc},       {0xb8, 0x8f, 0xff, 0xcc},
+       {0xb3, 0x01, 0x41, 0xcc},
+       {0xb8, 0x8e, 0x00, 0xcc},
+       {0xb8, 0x8f, 0xff, 0xcc},
+       {0x00, 0x01, 0x0c, 0xaa},
+       {0x00, 0x14, 0x01, 0xaa},
+       {0x00, 0x15, 0xe6, 0xaa},
+       {0x00, 0x16, 0x02, 0xaa},
+       {0x00, 0x17, 0x86, 0xaa},
+       {0x00, 0x23, 0x00, 0xaa},
+       {0x00, 0x25, 0x03, 0xaa},
+       {0x00, 0x26, 0xa9, 0xaa},
+       {0x00, 0x27, 0x80, 0xaa},
        {0x00, 0x30, 0x18, 0xaa},
+       {0xb6, 0x00, 0x00, 0xcc},
+       {0xb6, 0x03, 0x02, 0xcc},
+       {0xb6, 0x02, 0x80, 0xcc},
+       {0xb6, 0x05, 0x01, 0xcc},
+       {0xb6, 0x04, 0xe0, 0xcc},
+       {0xb6, 0x12, 0x78, 0xcc},
+       {0xb6, 0x18, 0x02, 0xcc},
+       {0xb6, 0x17, 0x58, 0xcc},
+       {0xb6, 0x16, 0x00, 0xcc},
+       {0xb6, 0x22, 0x12, 0xcc},
+       {0xb6, 0x23, 0x0b, 0xcc},
+       {0xb3, 0x02, 0x02, 0xcc},
+       {0xbf, 0xc0, 0x39, 0xcc},
+       {0xbf, 0xc1, 0x04, 0xcc},
+       {0xbf, 0xcc, 0x10, 0xcc},
+       {0xb6, 0x12, 0xf8, 0xcc},
+       {0xb6, 0x13, 0x13, 0xcc},
+       {0xb9, 0x12, 0x00, 0xcc},
+       {0xb9, 0x13, 0x0a, 0xcc},
+       {0xb9, 0x14, 0x0a, 0xcc},
+       {0xb9, 0x15, 0x0a, 0xcc},
+       {0xb9, 0x16, 0x0a, 0xcc},
+       {0xb8, 0x0c, 0x20, 0xcc},
+       {0xb8, 0x0d, 0x70, 0xcc},
+       {0xb9, 0x18, 0x00, 0xcc},
+       {0xb9, 0x19, 0x0f, 0xcc},
+       {0xb9, 0x1a, 0x0f, 0xcc},
+       {0xb9, 0x1b, 0x0f, 0xcc},
+       {0xb9, 0x1c, 0x0f, 0xcc},
+       {0xb3, 0x5c, 0x01, 0xcc},
        {}
 };
 
-static const __u8 hv7131r_initQVGA_data[][4] = {
-       {0xb0, 0x4d, 0x00, 0xcc},       {0xb3, 0x01, 0x01, 0xcc},
-       {0x00, 0x00, 0x50, 0xdd},       {0xb0, 0x03, 0x01, 0xcc},
+static const u8 hv7131r_initQVGA_data[][4] = {
+       {0xb3, 0x01, 0x01, 0xcc},
+       {0xb0, 0x03, 0x19, 0xcc},
+       {0xb0, 0x04, 0x02, 0xcc},
+       {0x00, 0x00, 0x20, 0xdd},
        {0xb3, 0x00, 0x24, 0xcc},
-       {0xb3, 0x00, 0x25, 0xcc},       {0xb3, 0x08, 0x01, 0xcc},
-       {0xb3, 0x09, 0x0c, 0xcc},       {0xb3, 0x05, 0x00, 0xcc},
-       {0xb3, 0x06, 0x01, 0xcc},
-       {0xb3, 0x03, 0x0b, 0xcc},       {0xb3, 0x04, 0x05, 0xcc},
-       {0xb3, 0x20, 0x00, 0xcc},       {0xb3, 0x21, 0x00, 0xcc},
+       {0xb3, 0x00, 0x25, 0xcc},
+       {0xb3, 0x08, 0x01, 0xcc},
+       {0xb3, 0x09, 0x0c, 0xcc},
+       {0xb3, 0x05, 0x01, 0xcc},
+       {0xb3, 0x06, 0x03, 0xcc},
+       {0xb3, 0x01, 0x45, 0xcc},
+       {0xb3, 0x03, 0x0b, 0xcc},
+       {0xb3, 0x04, 0x05, 0xcc},
+       {0xb3, 0x20, 0x00, 0xcc},
+       {0xb3, 0x21, 0x00, 0xcc},
        {0xb3, 0x22, 0x01, 0xcc},
-       {0xb3, 0x23, 0xe0, 0xcc},       {0xb3, 0x14, 0x00, 0xcc},
-       {0xb3, 0x15, 0x00, 0xcc},       {0xb3, 0x16, 0x02, 0xcc},
+       {0xb3, 0x23, 0xe0, 0xcc},
+       {0xb3, 0x14, 0x00, 0xcc},
+       {0xb3, 0x15, 0x02, 0xcc},
+       {0xb3, 0x16, 0x02, 0xcc},
        {0xb3, 0x17, 0x7f, 0xcc},
-       {0xb3, 0x34, 0x01, 0xcc},       {0xb3, 0x35, 0x91, 0xcc},
-       {0xb3, 0x00, 0x27, 0xcc},       {0xbc, 0x00, 0xd1, 0xcc},
-       {0xb8, 0x00, 0x21, 0xcc},
-       {0x00, 0x01, 0x0c, 0xaa},       {0x00, 0x14, 0x01, 0xaa},
-       {0x00, 0x15, 0xe6, 0xaa},       {0x00, 0x16, 0x02, 0xaa},
-       {0x00, 0x17, 0x86, 0xaa},
-       {0x00, 0x23, 0x00, 0xaa},       {0x00, 0x25, 0x01, 0xaa},
-       {0x00, 0x26, 0xd4, 0xaa},       {0x00, 0x27, 0xc0, 0xaa},
-       {0xbc, 0x02, 0x08, 0xcc},
-       {0xbc, 0x03, 0x70, 0xcc},       {0xbc, 0x04, 0x08, 0xcc},
-       {0xbc, 0x05, 0x00, 0xcc},       {0xbc, 0x06, 0x00, 0xcc},
-       {0xbc, 0x08, 0x3c, 0xcc},
-       {0xbc, 0x09, 0x40, 0xcc},       {0xbc, 0x0a, 0x04, 0xcc},
-       {0xbc, 0x0b, 0x00, 0xcc},       {0xbc, 0x0c, 0x00, 0xcc},
-       {0xb8, 0xfe, 0x02, 0xcc},
-       {0xb8, 0xff, 0x07, 0xcc},       {0xb9, 0x00, 0x14, 0xcc},
-       {0xb9, 0x01, 0x14, 0xcc},       {0xb9, 0x02, 0x14, 0xcc},
-       {0xb9, 0x03, 0x00, 0xcc},
-       {0xb9, 0x04, 0x02, 0xcc},       {0xb9, 0x05, 0x05, 0xcc},
-       {0xb9, 0x06, 0x0f, 0xcc},       {0xb9, 0x07, 0x0f, 0xcc},
-       {0xb9, 0x08, 0x0f, 0xcc},
-       {0xb8, 0x2c, 0x60, 0xcc},       {0xb8, 0x2d, 0xf8, 0xcc},
-       {0xb8, 0x2e, 0xf8, 0xcc},       {0xb8, 0x2f, 0xf8, 0xcc},
+       {0xb3, 0x34, 0x01, 0xcc},
+       {0xb3, 0x35, 0x91, 0xcc},
+       {0xb3, 0x00, 0x27, 0xcc},
+       {0xbc, 0x00, 0xd3, 0xcc},
+       {0xb8, 0x00, 0x23, 0xcc},
+       {0xb8, 0x2c, 0x50, 0xcc},
+       {0xb8, 0x2d, 0xf8, 0xcc},
+       {0xb8, 0x2e, 0xf8, 0xcc},
+       {0xb8, 0x2f, 0xf8, 0xcc},
        {0xb8, 0x30, 0x50, 0xcc},
-       {0xb8, 0x31, 0xf8, 0xcc},       {0xb8, 0x32, 0xf8, 0xcc},
+       {0xb8, 0x31, 0xf8, 0xcc},
+       {0xb8, 0x32, 0xf8, 0xcc},
        {0xb8, 0x33, 0xf8, 0xcc},
-       {0xb8, 0x34, 0x65, 0xcc},       {0xb8, 0x35, 0x00, 0xcc},
-       {0xb8, 0x36, 0x00, 0xcc},       {0xb8, 0x37, 0x00, 0xcc},
+       {0xb8, 0x34, 0x58, 0xcc},
+       {0xb8, 0x35, 0x00, 0xcc},
+       {0xb8, 0x36, 0x00, 0xcc},
+       {0xb8, 0x37, 0x00, 0xcc},
        {0xb8, 0x27, 0x20, 0xcc},
-       {0xb8, 0x01, 0x7d, 0xcc},       {0xb8, 0x81, 0x09, 0xcc},
-       {0xb3, 0x01, 0x41, 0xcc},       {0xb8, 0xfe, 0x00, 0xcc},
-       {0xb8, 0xff, 0x28, 0xcc},
-       {0xb9, 0x00, 0x28, 0xcc},       {0xb9, 0x01, 0x28, 0xcc},
-       {0xb9, 0x02, 0x28, 0xcc},       {0xb9, 0x03, 0x00, 0xcc},
-       {0xb9, 0x04, 0x00, 0xcc},
-       {0xb9, 0x05, 0x3c, 0xcc},       {0xb9, 0x06, 0x3c, 0xcc},
-       {0xb9, 0x07, 0x3c, 0xcc},       {0xb9, 0x08, 0x3c, 0xcc},
+       {0xb8, 0x01, 0x7d, 0xcc},
+       {0xb8, 0x81, 0x09, 0xcc},
+       {0xb3, 0x01, 0x41, 0xcc},
        {0xb8, 0x8e, 0x00, 0xcc},
-       {0xb8, 0x8f, 0xff, 0xcc},       {0x00, 0x30, 0x18, 0xaa},
+       {0xb8, 0x8f, 0xff, 0xcc},
+       {0x00, 0x01, 0x0c, 0xaa},
+       {0x00, 0x14, 0x01, 0xaa},
+       {0x00, 0x15, 0xe6, 0xaa},
+       {0x00, 0x16, 0x02, 0xaa},
+       {0x00, 0x17, 0x86, 0xaa},
+       {0x00, 0x23, 0x00, 0xaa},
+       {0x00, 0x25, 0x03, 0xaa},
+       {0x00, 0x26, 0xa9, 0xaa},
+       {0x00, 0x27, 0x80, 0xaa},
+       {0x00, 0x30, 0x18, 0xaa},
+       {0xb6, 0x00, 0x00, 0xcc},
+       {0xb6, 0x03, 0x01, 0xcc},
+       {0xb6, 0x02, 0x40, 0xcc},
+       {0xb6, 0x05, 0x00, 0xcc},
+       {0xb6, 0x04, 0xf0, 0xcc},
+       {0xb6, 0x12, 0x78, 0xcc},
+       {0xb6, 0x18, 0x00, 0xcc},
+       {0xb6, 0x17, 0x96, 0xcc},
+       {0xb6, 0x16, 0x00, 0xcc},
+       {0xb6, 0x22, 0x12, 0xcc},
+       {0xb6, 0x23, 0x0b, 0xcc},
+       {0xb3, 0x02, 0x02, 0xcc},
+       {0xbf, 0xc0, 0x39, 0xcc},
+       {0xbf, 0xc1, 0x04, 0xcc},
+       {0xbf, 0xcc, 0x10, 0xcc},
+       {0xbc, 0x02, 0x18, 0xcc},
+       {0xbc, 0x03, 0x50, 0xcc},
+       {0xbc, 0x04, 0x18, 0xcc},
+       {0xbc, 0x05, 0x00, 0xcc},
+       {0xbc, 0x06, 0x00, 0xcc},
+       {0xbc, 0x08, 0x30, 0xcc},
+       {0xbc, 0x09, 0x40, 0xcc},
+       {0xbc, 0x0a, 0x10, 0xcc},
+       {0xbc, 0x0b, 0x00, 0xcc},
+       {0xbc, 0x0c, 0x00, 0xcc},
+       {0xb9, 0x12, 0x00, 0xcc},
+       {0xb9, 0x13, 0x0a, 0xcc},
+       {0xb9, 0x14, 0x0a, 0xcc},
+       {0xb9, 0x15, 0x0a, 0xcc},
+       {0xb9, 0x16, 0x0a, 0xcc},
+       {0xb9, 0x18, 0x00, 0xcc},
+       {0xb9, 0x19, 0x0f, 0xcc},
+       {0xb8, 0x0c, 0x20, 0xcc},
+       {0xb8, 0x0d, 0x70, 0xcc},
+       {0xb9, 0x1a, 0x0f, 0xcc},
+       {0xb9, 0x1b, 0x0f, 0xcc},
+       {0xb9, 0x1c, 0x0f, 0xcc},
+       {0xb6, 0x12, 0xf8, 0xcc},
+       {0xb6, 0x13, 0x13, 0xcc},
+       {0xb3, 0x5c, 0x01, 0xcc},
        {}
 };
 
-static const __u8 ov7660_gamma[17] = {
+static const u8 ov7660_gamma[17] = {
        0x00, 0x13, 0x38, 0x59, 0x79, 0x92, 0xa7, 0xb9, 0xc8,
        0xd4, 0xdf, 0xe7, 0xee, 0xf4, 0xf9, 0xfc, 0xff
 };
-static const __u8 ov7660_matrix[9] = {
+static const u8 ov7660_matrix[9] = {
        0x5a, 0xf0, 0xf6, 0xf3, 0x57, 0xf6, 0xf3, 0xef, 0x62
 };
-static const __u8 ov7660_initVGA_data[][4] = {
+static const u8 ov7660_initVGA_data[][4] = {
        {0xb0, 0x4d, 0x00, 0xcc},       {0xb3, 0x01, 0x01, 0xcc},
        {0x00, 0x00, 0x50, 0xdd},
        {0xb0, 0x03, 0x01, 0xcc},
@@ -1613,7 +1789,7 @@ static const __u8 ov7660_initVGA_data[][4] = {
        {0x00, 0x29, 0x3c, 0xaa},       {0xb3, 0x01, 0x45, 0xcc},
        {}
 };
-static const __u8 ov7660_initQVGA_data[][4] = {
+static const u8 ov7660_initQVGA_data[][4] = {
        {0xb0, 0x4d, 0x00, 0xcc},       {0xb3, 0x01, 0x01, 0xcc},
        {0x00, 0x00, 0x50, 0xdd},       {0xb0, 0x03, 0x01, 0xcc},
        {0xb3, 0x00, 0x21, 0xcc},       {0xb3, 0x00, 0x26, 0xcc},
@@ -1682,26 +1858,26 @@ static const __u8 ov7660_initQVGA_data[][4] = {
        {}
 };
 
-static const __u8 ov7660_50HZ[][4] = {
+static const u8 ov7660_50HZ[][4] = {
        {0x00, 0x3b, 0x08, 0xaa},
        {0x00, 0x9d, 0x40, 0xaa},
        {0x00, 0x13, 0xa7, 0xaa},
        {}
 };
 
-static const __u8 ov7660_60HZ[][4] = {
+static const u8 ov7660_60HZ[][4] = {
        {0x00, 0x3b, 0x00, 0xaa},
        {0x00, 0x9e, 0x40, 0xaa},
        {0x00, 0x13, 0xa7, 0xaa},
        {}
 };
 
-static const __u8 ov7660_NoFliker[][4] = {
+static const u8 ov7660_NoFliker[][4] = {
        {0x00, 0x13, 0x87, 0xaa},
        {}
 };
 
-static const __u8 ov7670_initVGA_JPG[][4] = {
+static const u8 ov7670_initVGA_JPG[][4] = {
        {0xb3, 0x01, 0x05, 0xcc},
        {0x00, 0x00, 0x30, 0xdd},       {0xb0, 0x03, 0x19, 0xcc},
        {0x00, 0x00, 0x10, 0xdd},
@@ -1831,7 +2007,7 @@ static const __u8 ov7670_initVGA_JPG[][4] = {
        {},
 };
 
-static const __u8 ov7670_initQVGA_JPG[][4] = {
+static const u8 ov7670_initQVGA_JPG[][4] = {
        {0xb3, 0x01, 0x05, 0xcc},       {0x00, 0x00, 0x30, 0xdd},
        {0xb0, 0x03, 0x19, 0xcc},       {0x00, 0x00, 0x10, 0xdd},
        {0xb0, 0x04, 0x02, 0xcc},       {0x00, 0x00, 0x10, 0xdd},
@@ -1966,14 +2142,14 @@ static const __u8 ov7670_initQVGA_JPG[][4] = {
 };
 
 /* PO1200 - values from usbvm326.inf and ms-win trace */
-static const __u8 po1200_gamma[17] = {
+static const u8 po1200_gamma[17] = {
        0x00, 0x13, 0x38, 0x59, 0x79, 0x92, 0xa7, 0xb9, 0xc8,
        0xd4, 0xdf, 0xe7, 0xee, 0xf4, 0xf9, 0xfc, 0xff
 };
-static const __u8 po1200_matrix[9] = {
+static const u8 po1200_matrix[9] = {
        0x60, 0xf9, 0xe5, 0xe7, 0x50, 0x05, 0xf3, 0xe6, 0x5e
 };
-static const __u8 po1200_initVGA_data[][4] = {
+static const u8 po1200_initVGA_data[][4] = {
        {0xb0, 0x03, 0x19, 0xcc},       /* reset? */
        {0xb0, 0x03, 0x19, 0xcc},
 /*     {0x00, 0x00, 0x33, 0xdd}, */
@@ -2276,9 +2452,9 @@ static const struct sensor_info sensor_info_data[] = {
 
 /* read 'len' bytes in gspca_dev->usb_buf */
 static void reg_r(struct gspca_dev *gspca_dev,
-                 __u16 req,
-                 __u16 index,
-                 __u16 len)
+                 u16 req,
+                 u16 index,
+                 u16 len)
 {
        usb_control_msg(gspca_dev->dev,
                        usb_rcvctrlpipe(gspca_dev->dev, 0),
@@ -2290,9 +2466,9 @@ static void reg_r(struct gspca_dev *gspca_dev,
 }
 
 static void reg_w(struct usb_device *dev,
-                           __u16 req,
-                           __u16 value,
-                           __u16 index)
+                           u16 req,
+                           u16 value,
+                           u16 index)
 {
        usb_control_msg(dev,
                        usb_sndctrlpipe(dev, 0),
@@ -2342,11 +2518,18 @@ static u16 read_sensor_register(struct gspca_dev *gspca_dev,
 
 static int vc032x_probe_sensor(struct gspca_dev *gspca_dev)
 {
+       struct sd *sd = (struct sd *) gspca_dev;
        struct usb_device *dev = gspca_dev->dev;
        int i;
        u16 value;
        const struct sensor_info *ptsensor_info;
 
+/*fixme: should also check the other sensor (back mi1320_soc, front mc501cb)*/
+       if (sd->flags & FL_SAMSUNG) {
+               reg_w(dev, 0xa0, 0x01, 0xb301);
+               reg_w(dev, 0x89, 0xf0ff, 0xffff); /* select the back sensor */
+       }
+
        reg_r(gspca_dev, 0xa1, 0xbfcf, 1);
        PDEBUG(D_PROBE, "check sensor header %02x", gspca_dev->usb_buf[0]);
        for (i = 0; i < ARRAY_SIZE(sensor_info_data); i++) {
@@ -2406,17 +2589,17 @@ static void i2c_write(struct gspca_dev *gspca_dev,
 }
 
 static void put_tab_to_reg(struct gspca_dev *gspca_dev,
-                       const __u8 *tab, __u8 tabsize, __u16 addr)
+                       const u8 *tab, u8 tabsize, u16 addr)
 {
        int j;
-       __u16 ad = addr;
+       u16 ad = addr;
 
        for (j = 0; j < tabsize; j++)
                reg_w(gspca_dev->dev, 0xa0, tab[j], ad++);
 }
 
 static void usb_exchange(struct gspca_dev *gspca_dev,
-                       const __u8 data[][4])
+                       const u8 data[][4])
 {
        struct usb_device *dev = gspca_dev->dev;
        int i = 0;
@@ -2466,7 +2649,8 @@ static int sd_config(struct gspca_dev *gspca_dev,
        };
 
        cam = &gspca_dev->cam;
-       sd->bridge = id->driver_info;
+       sd->bridge = id->driver_info >> 8;
+       sd->flags = id->driver_info & 0xff;
        sensor = vc032x_probe_sensor(gspca_dev);
        switch (sensor) {
        case -1:
@@ -2519,8 +2703,6 @@ static int sd_config(struct gspca_dev *gspca_dev,
                case SENSOR_MI1320_SOC:
                        cam->cam_mode = bi_mode;
                        cam->nmodes = ARRAY_SIZE(bi_mode);
-                       cam->input_flags = V4L2_IN_ST_VFLIP |
-                                          V4L2_IN_ST_HFLIP;
                        break;
                default:
                        cam->cam_mode = vc0323_mode;
@@ -2532,14 +2714,14 @@ static int sd_config(struct gspca_dev *gspca_dev,
 
        sd->hflip = HFLIP_DEF;
        sd->vflip = VFLIP_DEF;
-       if (sd->sensor == SENSOR_OV7670) {
-               sd->hflip = 1;
-               sd->vflip = 1;
-       }
+       if (sd->sensor == SENSOR_OV7670)
+               sd->flags |= FL_HFLIP | FL_VFLIP;
        sd->lightfreq = FREQ_DEF;
        if (sd->sensor != SENSOR_OV7670)
                gspca_dev->ctrl_dis = (1 << LIGHTFREQ_IDX);
        switch (sd->sensor) {
+       case SENSOR_MI1310_SOC:
+       case SENSOR_MI1320_SOC:
        case SENSOR_OV7660:
        case SENSOR_OV7670:
        case SENSOR_PO1200:
@@ -2568,39 +2750,50 @@ static int sd_init(struct gspca_dev *gspca_dev)
        return 0;
 }
 
-/* for OV7660 and OV7670 only */
+/* some sensors only */
 static void sethvflip(struct gspca_dev *gspca_dev)
 {
        struct sd *sd = (struct sd *) gspca_dev;
-       __u8 data;
-
+       u8 data[2], hflip, vflip;
+
+       hflip = sd->hflip;
+       if (sd->flags & FL_HFLIP)
+               hflip = !hflip;
+       vflip = sd->vflip;
+       if (sd->flags & FL_VFLIP)
+               vflip = !vflip;
        switch (sd->sensor) {
-       case SENSOR_OV7660:
-               data = 1;
+       case SENSOR_MI1310_SOC:
+       case SENSOR_MI1320_SOC:
+               data[0] = data[1] = 0;          /* select page 0 */
+               i2c_write(gspca_dev, 0xf0, data, 2);
+               data[0] = sd->sensor == SENSOR_MI1310_SOC ? 0x03 : 0x01;
+               data[1] = 0x02 * hflip
+                       | 0x01 * vflip;
+               i2c_write(gspca_dev, 0x20, data, 2);
                break;
+       case SENSOR_OV7660:
        case SENSOR_OV7670:
-               data = 7;
+               data[0] = sd->sensor == SENSOR_OV7660 ? 0x01 : 0x07;
+               data[0] |= OV7660_MVFP_MIRROR * hflip
+                       | OV7660_MVFP_VFLIP * vflip;
+               i2c_write(gspca_dev, OV7660_REG_MVFP, data, 1);
                break;
        case SENSOR_PO1200:
-               data = 0;
-               i2c_write(gspca_dev, 0x03, &data, 1);
-               data = 0x80 * sd->hflip
-                       | 0x40 * sd->vflip
+               data[0] = 0;
+               i2c_write(gspca_dev, 0x03, data, 1);
+               data[0] = 0x80 * hflip
+                       | 0x40 * vflip
                        | 0x06;
-               i2c_write(gspca_dev, 0x1e, &data, 1);
-               return;
-       default:
-               return;
+               i2c_write(gspca_dev, 0x1e, data, 1);
+               break;
        }
-       data |= OV7660_MVFP_MIRROR * sd->hflip
-               | OV7660_MVFP_VFLIP * sd->vflip;
-       i2c_write(gspca_dev, OV7660_REG_MVFP, &data, 1);
 }
 
 static void setlightfreq(struct gspca_dev *gspca_dev)
 {
        struct sd *sd = (struct sd *) gspca_dev;
-       static const __u8 (*ov7660_freq_tb[3])[4] =
+       static const u8 (*ov7660_freq_tb[3])[4] =
                {ov7660_NoFliker, ov7660_50HZ, ov7660_60HZ};
 
        if (sd->sensor != SENSOR_OV7660)
@@ -2612,7 +2805,7 @@ static void setlightfreq(struct gspca_dev *gspca_dev)
 static void setsharpness(struct gspca_dev *gspca_dev)
 {
        struct sd *sd = (struct sd *) gspca_dev;
-       __u8 data;
+       u8 data;
 
        if (sd->sensor != SENSOR_PO1200)
                return;
@@ -2625,9 +2818,9 @@ static void setsharpness(struct gspca_dev *gspca_dev)
 static int sd_start(struct gspca_dev *gspca_dev)
 {
        struct sd *sd = (struct sd *) gspca_dev;
-       const __u8 (*init)[4];
-       const __u8 *GammaT = NULL;
-       const __u8 *MatrixT = NULL;
+       const u8 (*init)[4];
+       const u8 *GammaT = NULL;
+       const u8 *MatrixT = NULL;
        int mode;
        static const u8 (*mi1320_soc_init[])[4] = {
                mi1320_soc_InitSXGA,
@@ -2635,6 +2828,13 @@ static int sd_start(struct gspca_dev *gspca_dev)
                mi1320_soc_InitQVGA,
        };
 
+/*fixme: back sensor only*/
+       if (sd->flags & FL_SAMSUNG) {
+               reg_w(gspca_dev->dev, 0x89, 0xf0ff, 0xffff);
+               reg_w(gspca_dev->dev, 0xa9, 0x8348, 0x000e);
+               reg_w(gspca_dev->dev, 0xa9, 0x0000, 0x001a);
+       }
+
        /* Assume start use the good resolution from gspca_dev->mode */
        if (sd->bridge == BRIDGE_VC0321) {
                reg_w(gspca_dev->dev, 0xa0, 0xff, 0xbfec);
@@ -2737,16 +2937,22 @@ static int sd_start(struct gspca_dev *gspca_dev)
                put_tab_to_reg(gspca_dev, MatrixT, 9, 0xb82c);
 
                /* set the led on 0x0892 0x0896 */
-               if (sd->sensor != SENSOR_PO1200) {
-                       reg_w(gspca_dev->dev, 0x89, 0xffff, 0xfdff);
-                       msleep(100);
-                       sethvflip(gspca_dev);
-                       setlightfreq(gspca_dev);
-               } else {
-                       setsharpness(gspca_dev);
-                       sethvflip(gspca_dev);
+               switch (sd->sensor) {
+               case SENSOR_PO1200:
+               case SENSOR_HV7131R:
                        reg_w(gspca_dev->dev, 0x89, 0x0400, 0x1415);
+                       break;
+               case SENSOR_MI1310_SOC:
+                       reg_w(gspca_dev->dev, 0x89, 0x058c, 0x0000);
+                       break;
+               default:
+                       reg_w(gspca_dev->dev, 0x89, 0xffff, 0xfdff);
+                       break;
                }
+               msleep(100);
+               setsharpness(gspca_dev);
+               sethvflip(gspca_dev);
+               setlightfreq(gspca_dev);
        }
        return 0;
 }
@@ -2754,8 +2960,12 @@ static int sd_start(struct gspca_dev *gspca_dev)
 static void sd_stopN(struct gspca_dev *gspca_dev)
 {
        struct usb_device *dev = gspca_dev->dev;
+       struct sd *sd = (struct sd *) gspca_dev;
 
-       reg_w(dev, 0x89, 0xffff, 0xffff);
+       if (sd->sensor == SENSOR_MI1310_SOC)
+               reg_w(dev, 0x89, 0x058c, 0x00ff);
+       else
+               reg_w(dev, 0x89, 0xffff, 0xffff);
        reg_w(dev, 0xa0, 0x01, 0xb301);
        reg_w(dev, 0xa0, 0x09, 0xb003);
 }
@@ -2764,15 +2974,20 @@ static void sd_stopN(struct gspca_dev *gspca_dev)
 static void sd_stop0(struct gspca_dev *gspca_dev)
 {
        struct usb_device *dev = gspca_dev->dev;
+       struct sd *sd = (struct sd *) gspca_dev;
 
        if (!gspca_dev->present)
                return;
-       reg_w(dev, 0x89, 0xffff, 0xffff);
+/*fixme: is this useful?*/
+       if (sd->sensor == SENSOR_MI1310_SOC)
+               reg_w(dev, 0x89, 0x058c, 0x00ff);
+       else
+               reg_w(dev, 0x89, 0xffff, 0xffff);
 }
 
 static void sd_pkt_scan(struct gspca_dev *gspca_dev,
                        struct gspca_frame *frame,      /* target */
-                       __u8 *data,                     /* isoc packet */
+                       u8 *data,                       /* isoc packet */
                        int len)                        /* iso pkt length */
 {
        struct sd *sd = (struct sd *) gspca_dev;
@@ -2872,21 +3087,12 @@ static int sd_getsharpness(struct gspca_dev *gspca_dev, __s32 *val)
 static int sd_querymenu(struct gspca_dev *gspca_dev,
                        struct v4l2_querymenu *menu)
 {
+       static const char *freq_nm[3] = {"NoFliker", "50 Hz", "60 Hz"};
+
        switch (menu->id) {
        case V4L2_CID_POWER_LINE_FREQUENCY:
-               switch (menu->index) {
-               case 0:         /* V4L2_CID_POWER_LINE_FREQUENCY_DISABLED */
-                       strcpy((char *) menu->name, "NoFliker");
-                       return 0;
-               case 1:         /* V4L2_CID_POWER_LINE_FREQUENCY_50HZ */
-                       strcpy((char *) menu->name, "50 Hz");
-                       return 0;
-               default:
-/*             case 2:          * V4L2_CID_POWER_LINE_FREQUENCY_60HZ */
-                       strcpy((char *) menu->name, "60 Hz");
-                       return 0;
-               }
-               break;
+               strcpy((char *) menu->name, freq_nm[menu->index]);
+               return 0;
        }
        return -EINVAL;
 }
@@ -2906,19 +3112,23 @@ static const struct sd_desc sd_desc = {
 };
 
 /* -- module initialisation -- */
+#define BF(bridge, flags) \
+       .driver_info = (BRIDGE_ ## bridge << 8) \
+               | (flags)
 static const __devinitdata struct usb_device_id device_table[] = {
-       {USB_DEVICE(0x041e, 0x405b), .driver_info = BRIDGE_VC0323},
-       {USB_DEVICE(0x046d, 0x0892), .driver_info = BRIDGE_VC0321},
-       {USB_DEVICE(0x046d, 0x0896), .driver_info = BRIDGE_VC0321},
-       {USB_DEVICE(0x046d, 0x0897), .driver_info = BRIDGE_VC0321},
-       {USB_DEVICE(0x0ac8, 0x0321), .driver_info = BRIDGE_VC0321},
-       {USB_DEVICE(0x0ac8, 0x0323), .driver_info = BRIDGE_VC0323},
-       {USB_DEVICE(0x0ac8, 0x0328), .driver_info = BRIDGE_VC0321},
-       {USB_DEVICE(0x0ac8, 0xc001), .driver_info = BRIDGE_VC0321},
-       {USB_DEVICE(0x0ac8, 0xc002), .driver_info = BRIDGE_VC0321},
-       {USB_DEVICE(0x15b8, 0x6001), .driver_info = BRIDGE_VC0323},
-       {USB_DEVICE(0x15b8, 0x6002), .driver_info = BRIDGE_VC0323},
-       {USB_DEVICE(0x17ef, 0x4802), .driver_info = BRIDGE_VC0323},
+       {USB_DEVICE(0x041e, 0x405b), BF(VC0323, FL_VFLIP)},
+       {USB_DEVICE(0x046d, 0x0892), BF(VC0321, 0)},
+       {USB_DEVICE(0x046d, 0x0896), BF(VC0321, 0)},
+       {USB_DEVICE(0x046d, 0x0897), BF(VC0321, 0)},
+       {USB_DEVICE(0x0ac8, 0x0321), BF(VC0321, 0)},
+       {USB_DEVICE(0x0ac8, 0x0323), BF(VC0323, 0)},
+       {USB_DEVICE(0x0ac8, 0x0328), BF(VC0321, 0)},
+       {USB_DEVICE(0x0ac8, 0xc001), BF(VC0321, 0)},
+       {USB_DEVICE(0x0ac8, 0xc002), BF(VC0321, 0)},
+       {USB_DEVICE(0x0ac8, 0xc301), BF(VC0323, FL_SAMSUNG)},
+       {USB_DEVICE(0x15b8, 0x6001), BF(VC0323, 0)},
+       {USB_DEVICE(0x15b8, 0x6002), BF(VC0323, 0)},
+       {USB_DEVICE(0x17ef, 0x4802), BF(VC0323, 0)},
        {}
 };
 MODULE_DEVICE_TABLE(usb, device_table);
index 3d2756f7874adac447954820267bf519198f53f8..cdf3357b4c9f307e4aeb82eb0d43270f1e27b87a 100644 (file)
@@ -7574,7 +7574,7 @@ static int sd_get_jcomp(struct gspca_dev *gspca_dev,
 static const struct sd_desc sd_desc = {
        .name = MODULE_NAME,
        .ctrls = sd_ctrls,
-       .nctrls = sizeof sd_ctrls / sizeof sd_ctrls[0],
+       .nctrls = ARRAY_SIZE(sd_ctrls),
        .config = sd_config,
        .init = sd_init,
        .start = sd_start,
index 06791749d1a0e11635234cb9d4f7728f420f2a9e..5a6b78b8d25d0957a78d734ce1498b54a7ef025d 100644 (file)
@@ -178,24 +178,24 @@ error:
 
 int hdpvr_set_options(struct hdpvr_device *dev)
 {
-       hdpvr_config_call(dev, CTRL_VIDEO_STD_TYPE, dev->options.video_std);
+       hdpvr_config_call(dev, CTRL_VIDEO_STD_TYPE, dev->options.video_std);
 
-       hdpvr_config_call(dev, CTRL_VIDEO_INPUT_VALUE,
+       hdpvr_config_call(dev, CTRL_VIDEO_INPUT_VALUE,
                         dev->options.video_input+1);
 
-       hdpvr_set_audio(dev, dev->options.audio_input+1,
+       hdpvr_set_audio(dev, dev->options.audio_input+1,
                       dev->options.audio_codec);
 
-       hdpvr_set_bitrate(dev);
-       hdpvr_config_call(dev, CTRL_BITRATE_MODE_VALUE,
+       hdpvr_set_bitrate(dev);
+       hdpvr_config_call(dev, CTRL_BITRATE_MODE_VALUE,
                         dev->options.bitrate_mode);
-       hdpvr_config_call(dev, CTRL_GOP_MODE_VALUE, dev->options.gop_mode);
+       hdpvr_config_call(dev, CTRL_GOP_MODE_VALUE, dev->options.gop_mode);
 
-       hdpvr_config_call(dev, CTRL_BRIGHTNESS, dev->options.brightness);
-       hdpvr_config_call(dev, CTRL_CONTRAST,   dev->options.contrast);
-       hdpvr_config_call(dev, CTRL_HUE,        dev->options.hue);
-       hdpvr_config_call(dev, CTRL_SATURATION, dev->options.saturation);
-       hdpvr_config_call(dev, CTRL_SHARPNESS,  dev->options.sharpness);
+       hdpvr_config_call(dev, CTRL_BRIGHTNESS, dev->options.brightness);
+       hdpvr_config_call(dev, CTRL_CONTRAST,   dev->options.contrast);
+       hdpvr_config_call(dev, CTRL_HUE,        dev->options.hue);
+       hdpvr_config_call(dev, CTRL_SATURATION, dev->options.saturation);
+       hdpvr_config_call(dev, CTRL_SHARPNESS,  dev->options.sharpness);
 
-       return 0;
+       return 0;
 }
index 188bd5aea25888653d8b4f8000f2fdae42378cb9..1c9bc94c905c0afb29f460c7b044fde1175cc8c6 100644 (file)
@@ -126,7 +126,7 @@ static int device_authorization(struct hdpvr_device *dev)
        char *print_buf = kzalloc(5*buf_size+1, GFP_KERNEL);
        if (!print_buf) {
                v4l2_err(&dev->v4l2_dev, "Out of memory\n");
-               goto error;
+               return retval;
        }
 #endif
 
@@ -140,7 +140,7 @@ static int device_authorization(struct hdpvr_device *dev)
        if (ret != 46) {
                v4l2_err(&dev->v4l2_dev,
                         "unexpected answer of status request, len %d\n", ret);
-               goto error;
+               goto unlock;
        }
 #ifdef HDPVR_DEBUG
        else {
@@ -163,7 +163,7 @@ static int device_authorization(struct hdpvr_device *dev)
                v4l2_err(&dev->v4l2_dev, "unknown firmware version 0x%x\n",
                        dev->usbc_buf[1]);
                ret = -EINVAL;
-               goto error;
+               goto unlock;
        }
 
        response = dev->usbc_buf+38;
@@ -188,10 +188,10 @@ static int device_authorization(struct hdpvr_device *dev)
                              10000);
        v4l2_dbg(MSG_INFO, hdpvr_debug, &dev->v4l2_dev,
                 "magic request returned %d\n", ret);
-       mutex_unlock(&dev->usbc_mutex);
 
        retval = ret != 8;
-error:
+unlock:
+       mutex_unlock(&dev->usbc_mutex);
        return retval;
 }
 
@@ -350,6 +350,7 @@ static int hdpvr_probe(struct usb_interface *interface,
 
        mutex_lock(&dev->io_mutex);
        if (hdpvr_alloc_buffers(dev, NUM_BUFFERS)) {
+               mutex_unlock(&dev->io_mutex);
                v4l2_err(&dev->v4l2_dev,
                         "allocating transfer buffers failed\n");
                goto error;
@@ -381,7 +382,6 @@ static int hdpvr_probe(struct usb_interface *interface,
 
 error:
        if (dev) {
-               mutex_unlock(&dev->io_mutex);
                /* this frees allocated memory */
                hdpvr_delete(dev);
        }
index c4b5d1515c10f54c1eaf942ae8e9f56f4a9d7094..296330a0e1e55cd0dc732680dfa3a79d2c52dcd5 100644 (file)
@@ -127,7 +127,6 @@ int hdpvr_register_i2c_adapter(struct hdpvr_device *dev)
                sizeof(i2c_adap->name));
        i2c_adap->algo  = &hdpvr_algo;
        i2c_adap->class = I2C_CLASS_TV_ANALOG;
-       i2c_adap->id    = I2C_HW_B_HDPVR;
        i2c_adap->owner = THIS_MODULE;
        i2c_adap->dev.parent = &dev->udev->dev;
 
index d678765cbba233a1b6bc869c858532b01735233b..2eb9dc2ebe59797a9ffeac30eea0dbbd7eeae504 100644 (file)
@@ -375,6 +375,7 @@ static int hdpvr_open(struct file *file)
         * in resumption */
        mutex_lock(&dev->io_mutex);
        dev->open_count++;
+       mutex_unlock(&dev->io_mutex);
 
        fh->dev = dev;
 
@@ -383,7 +384,6 @@ static int hdpvr_open(struct file *file)
 
        retval = 0;
 err:
-       mutex_unlock(&dev->io_mutex);
        return retval;
 }
 
@@ -519,8 +519,10 @@ static unsigned int hdpvr_poll(struct file *filp, poll_table *wait)
 
        mutex_lock(&dev->io_mutex);
 
-       if (video_is_unregistered(dev->video_dev))
+       if (video_is_unregistered(dev->video_dev)) {
+               mutex_unlock(&dev->io_mutex);
                return -EIO;
+       }
 
        if (dev->status == STATUS_IDLE) {
                if (hdpvr_start_streaming(dev)) {
index 86f2fefe1edf28a9db5b93b9c13af6696dbf8e5d..247d3115a9b7cff4c9b328dc731e3b8e003de448 100644 (file)
@@ -122,12 +122,12 @@ static int get_key_haup_common(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw,
        return 1;
 }
 
-static inline int get_key_haup(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw)
+static int get_key_haup(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw)
 {
        return get_key_haup_common (ir, ir_key, ir_raw, 3, 0);
 }
 
-static inline int get_key_haup_xvr(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw)
+static int get_key_haup_xvr(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw)
 {
        return get_key_haup_common (ir, ir_key, ir_raw, 6, 3);
 }
@@ -297,7 +297,7 @@ static void ir_work(struct work_struct *work)
 
 static int ir_probe(struct i2c_client *client, const struct i2c_device_id *id)
 {
-       IR_KEYTAB_TYPE *ir_codes = NULL;
+       struct ir_scancode_table *ir_codes = NULL;
        const char *name = NULL;
        int ir_type;
        struct IR_i2c *ir;
@@ -322,13 +322,13 @@ static int ir_probe(struct i2c_client *client, const struct i2c_device_id *id)
                name        = "Pixelview";
                ir->get_key = get_key_pixelview;
                ir_type     = IR_TYPE_OTHER;
-               ir_codes    = ir_codes_empty;
+               ir_codes    = &ir_codes_empty_table;
                break;
        case 0x4b:
                name        = "PV951";
                ir->get_key = get_key_pv951;
                ir_type     = IR_TYPE_OTHER;
-               ir_codes    = ir_codes_pv951;
+               ir_codes    = &ir_codes_pv951_table;
                break;
        case 0x18:
        case 0x1a:
@@ -336,36 +336,38 @@ static int ir_probe(struct i2c_client *client, const struct i2c_device_id *id)
                ir->get_key = get_key_haup;
                ir_type     = IR_TYPE_RC5;
                if (hauppauge == 1) {
-                       ir_codes    = ir_codes_hauppauge_new;
+                       ir_codes    = &ir_codes_hauppauge_new_table;
                } else {
-                       ir_codes    = ir_codes_rc5_tv;
+                       ir_codes    = &ir_codes_rc5_tv_table;
                }
                break;
        case 0x30:
                name        = "KNC One";
                ir->get_key = get_key_knc1;
                ir_type     = IR_TYPE_OTHER;
-               ir_codes    = ir_codes_empty;
+               ir_codes    = &ir_codes_empty_table;
                break;
        case 0x6b:
                name        = "FusionHDTV";
                ir->get_key = get_key_fusionhdtv;
                ir_type     = IR_TYPE_RC5;
-               ir_codes    = ir_codes_fusionhdtv_mce;
+               ir_codes    = &ir_codes_fusionhdtv_mce_table;
                break;
        case 0x7a:
        case 0x47:
        case 0x71:
        case 0x2d:
-               if (adap->id == I2C_HW_B_CX2388x) {
+               if (adap->id == I2C_HW_B_CX2388x ||
+                   adap->id == I2C_HW_B_CX2341X) {
                        /* Handled by cx88-input */
-                       name        = "CX2388x remote";
+                       name = adap->id == I2C_HW_B_CX2341X ? "CX2341x remote"
+                                                           : "CX2388x remote";
                        ir_type     = IR_TYPE_RC5;
                        ir->get_key = get_key_haup_xvr;
                        if (hauppauge == 1) {
-                               ir_codes    = ir_codes_hauppauge_new;
+                               ir_codes    = &ir_codes_hauppauge_new_table;
                        } else {
-                               ir_codes    = ir_codes_rc5_tv;
+                               ir_codes    = &ir_codes_rc5_tv_table;
                        }
                } else {
                        /* Handled by saa7134-input */
@@ -377,7 +379,7 @@ static int ir_probe(struct i2c_client *client, const struct i2c_device_id *id)
                name        = "AVerMedia Cardbus remote";
                ir->get_key = get_key_avermedia_cardbus;
                ir_type     = IR_TYPE_OTHER;
-               ir_codes    = ir_codes_avermedia_cardbus;
+               ir_codes    = &ir_codes_avermedia_cardbus_table;
                break;
        default:
                dprintk(1, DEVNAME ": Unsupported i2c address 0x%02x\n", addr);
@@ -392,7 +394,36 @@ static int ir_probe(struct i2c_client *client, const struct i2c_device_id *id)
 
                ir_codes = init_data->ir_codes;
                name = init_data->name;
-               ir->get_key = init_data->get_key;
+               if (init_data->type)
+                       ir_type = init_data->type;
+
+               switch (init_data->internal_get_key_func) {
+               case IR_KBD_GET_KEY_CUSTOM:
+                       /* The bridge driver provided us its own function */
+                       ir->get_key = init_data->get_key;
+                       break;
+               case IR_KBD_GET_KEY_PIXELVIEW:
+                       ir->get_key = get_key_pixelview;
+                       break;
+               case IR_KBD_GET_KEY_PV951:
+                       ir->get_key = get_key_pv951;
+                       break;
+               case IR_KBD_GET_KEY_HAUP:
+                       ir->get_key = get_key_haup;
+                       break;
+               case IR_KBD_GET_KEY_KNC1:
+                       ir->get_key = get_key_knc1;
+                       break;
+               case IR_KBD_GET_KEY_FUSIONHDTV:
+                       ir->get_key = get_key_fusionhdtv;
+                       break;
+               case IR_KBD_GET_KEY_HAUP_XVR:
+                       ir->get_key = get_key_haup_xvr;
+                       break;
+               case IR_KBD_GET_KEY_AVERMEDIA_CARDBUS:
+                       ir->get_key = get_key_avermedia_cardbus;
+                       break;
+               }
        }
 
        /* Make sure we are all setup before going on */
@@ -454,7 +485,8 @@ static int ir_remove(struct i2c_client *client)
 static const struct i2c_device_id ir_kbd_id[] = {
        /* Generic entry for any IR receiver */
        { "ir_video", 0 },
-       /* IR device specific entries could be added here */
+       /* IR device specific entries should be added here */
+       { "ir_rx_z8f0811_haup", 0 },
        { }
 };
 
index 2883c8780760f28a327bab83594cfc77d13f4dd4..4873b6ca580109e43dbd783f4fe47bdb095f2a8c 100644 (file)
@@ -977,26 +977,27 @@ static const struct ivtv_card ivtv_card_avertv_mce116 = {
 
 /* ------------------------------------------------------------------------- */
 
-/* AVerMedia PVR-150 Plus (M113) card */
+/* AVerMedia PVR-150 Plus / AVerTV M113 cards with a Daewoo/Partsnic Tuner */
 
 static const struct ivtv_card_pci_info ivtv_pci_aver_pvr150[] = {
-       { PCI_DEVICE_ID_IVTV16, IVTV_PCI_ID_AVERMEDIA, 0xc035 },
+       { PCI_DEVICE_ID_IVTV16, IVTV_PCI_ID_AVERMEDIA, 0xc034 }, /* NTSC */
+       { PCI_DEVICE_ID_IVTV16, IVTV_PCI_ID_AVERMEDIA, 0xc035 }, /* NTSC FM */
        { 0, 0, 0 }
 };
 
 static const struct ivtv_card ivtv_card_aver_pvr150 = {
        .type = IVTV_CARD_AVER_PVR150PLUS,
-       .name = "AVerMedia PVR-150 Plus",
+       .name = "AVerMedia PVR-150 Plus / AVerTV M113 Partsnic (Daewoo) Tuner",
        .v4l2_capabilities = IVTV_CAP_ENCODER,
        .hw_video = IVTV_HW_CX25840,
        .hw_audio = IVTV_HW_CX25840,
        .hw_audio_ctrl = IVTV_HW_CX25840,
        .hw_muxer = IVTV_HW_GPIO,
-       .hw_all = IVTV_HW_CX25840 | IVTV_HW_TUNER,
+       .hw_all = IVTV_HW_CX25840 | IVTV_HW_TUNER |
+                 IVTV_HW_WM8739 | IVTV_HW_GPIO,
        .video_inputs = {
                { IVTV_CARD_INPUT_VID_TUNER,  0, CX25840_COMPOSITE2 },
-               { IVTV_CARD_INPUT_SVIDEO1,    1,
-                 CX25840_SVIDEO_LUMA3 | CX25840_SVIDEO_CHROMA4 },
+               { IVTV_CARD_INPUT_SVIDEO1,    1, CX25840_SVIDEO3    },
                { IVTV_CARD_INPUT_COMPOSITE1, 1, CX25840_COMPOSITE1 },
        },
        .audio_inputs = {
@@ -1004,18 +1005,66 @@ static const struct ivtv_card ivtv_card_aver_pvr150 = {
                { IVTV_CARD_INPUT_LINE_IN1,   CX25840_AUDIO_SERIAL, 1 },
        },
        .radio_input = { IVTV_CARD_INPUT_AUD_TUNER, CX25840_AUDIO_SERIAL, 2 },
-       .gpio_init = { .direction = 0x0800, .initial_value = 0 },
-       .gpio_audio_input  = { .mask = 0x0800, .tuner = 0, .linein = 0, .radio = 0x0800 },
+       /* The 74HC4052 Dual 4:1 multiplexer is controlled by 2 GPIO lines */
+       .gpio_init = { .direction = 0xc000, .initial_value = 0 },
+       .gpio_audio_input  = { .mask   = 0xc000,
+                              .tuner  = 0x0000,
+                              .linein = 0x4000,
+                              .radio  = 0x8000 },
        .tuners = {
-               /* This card has a Partsnic PTI-5NF05 tuner */
-               { .std = V4L2_STD_MN, .tuner = TUNER_TCL_2002N },
+               /* Subsystem ID's 0xc03[45] have a Partsnic PTI-5NF05 tuner */
+               { .std = V4L2_STD_MN, .tuner = TUNER_PARTSNIC_PTI_5NF05 },
        },
        .pci_list = ivtv_pci_aver_pvr150,
+       /* Subsystem ID 0xc035 has a TEA5767(?) FM tuner, 0xc034 does not */
        .i2c = &ivtv_i2c_radio,
 };
 
 /* ------------------------------------------------------------------------- */
 
+/* AVerMedia UltraTV 1500 MCE (newer non-cx88 version, M113 variant) card */
+
+static const struct ivtv_card_pci_info ivtv_pci_aver_ultra1500mce[] = {
+       { PCI_DEVICE_ID_IVTV16, IVTV_PCI_ID_AVERMEDIA, 0xc019 },
+       { 0, 0, 0 }
+};
+
+static const struct ivtv_card ivtv_card_aver_ultra1500mce = {
+       .type = IVTV_CARD_AVER_ULTRA1500MCE,
+       .name = "AVerMedia UltraTV 1500 MCE / AVerTV M113 Philips Tuner",
+       .v4l2_capabilities = IVTV_CAP_ENCODER,
+       .hw_video = IVTV_HW_CX25840,
+       .hw_audio = IVTV_HW_CX25840,
+       .hw_audio_ctrl = IVTV_HW_CX25840,
+       .hw_muxer = IVTV_HW_GPIO,
+       .hw_all = IVTV_HW_CX25840 | IVTV_HW_TUNER |
+                 IVTV_HW_WM8739 | IVTV_HW_GPIO,
+       .video_inputs = {
+               { IVTV_CARD_INPUT_VID_TUNER,  0, CX25840_COMPOSITE2 },
+               { IVTV_CARD_INPUT_SVIDEO1,    1, CX25840_SVIDEO3    },
+               { IVTV_CARD_INPUT_COMPOSITE1, 1, CX25840_COMPOSITE1 },
+       },
+       .audio_inputs = {
+               { IVTV_CARD_INPUT_AUD_TUNER,  CX25840_AUDIO5,       0 },
+               { IVTV_CARD_INPUT_LINE_IN1,   CX25840_AUDIO_SERIAL, 1 },
+       },
+       .radio_input = { IVTV_CARD_INPUT_AUD_TUNER, CX25840_AUDIO_SERIAL, 2 },
+       /* The 74HC4052 Dual 4:1 multiplexer is controlled by 2 GPIO lines */
+       .gpio_init = { .direction = 0xc000, .initial_value = 0 },
+       .gpio_audio_input  = { .mask   = 0xc000,
+                              .tuner  = 0x0000,
+                              .linein = 0x4000,
+                              .radio  = 0x8000 },
+       .tuners = {
+               /* The UltraTV 1500 MCE has a Philips FM1236 MK5 TV/FM tuner */
+               { .std = V4L2_STD_MN, .tuner = TUNER_PHILIPS_FM1236_MK3 },
+       },
+       .pci_list = ivtv_pci_aver_ultra1500mce,
+       .i2c = &ivtv_i2c_std,
+};
+
+/* ------------------------------------------------------------------------- */
+
 /* AVerMedia EZMaker PCI Deluxe card */
 
 static const struct ivtv_card_pci_info ivtv_pci_aver_ezmaker[] = {
@@ -1180,6 +1229,7 @@ static const struct ivtv_card *ivtv_card_list[] = {
        &ivtv_card_aver_ezmaker,
        &ivtv_card_aver_m104,
        &ivtv_card_buffalo,
+       &ivtv_card_aver_ultra1500mce,
 
        /* Variations of standard cards but with the same PCI IDs.
           These cards must come last in this list. */
index 0b8fe85fb697972aae85181a36e09fe86f99e946..e99a0a2555782e33615a0cac5a439d197e298ddd 100644 (file)
@@ -50,7 +50,8 @@
 #define IVTV_CARD_AVER_EZMAKER       23 /* AVerMedia EZMaker PCI Deluxe */
 #define IVTV_CARD_AVER_M104          24 /* AverMedia M104 miniPCI card */
 #define IVTV_CARD_BUFFALO_MV5L       25 /* Buffalo PC-MV5L/PCI card */
-#define IVTV_CARD_LAST                      25
+#define IVTV_CARD_AVER_ULTRA1500MCE  26 /* AVerMedia UltraTV 1500 MCE */
+#define IVTV_CARD_LAST                      26
 
 /* Variants of existing cards but with the same PCI IDs. The driver
    detects these based on other device information.
index 558f8a837ff4f14bd04721a5cdd554add2d03cbe..63ea0fb660630d8a3d4693e75a0b552eba2277b0 100644 (file)
@@ -186,6 +186,7 @@ MODULE_PARM_DESC(cardtype,
                 "\t\t\t24 = AverMedia EZMaker PCI Deluxe\n"
                 "\t\t\t25 = AverMedia M104 (not yet working)\n"
                 "\t\t\t26 = Buffalo PC-MV5L/PCI\n"
+                "\t\t\t27 = AVerMedia UltraTV 1500 MCE\n"
                 "\t\t\t 0 = Autodetect (default)\n"
                 "\t\t\t-1 = Ignore this card\n\t\t");
 MODULE_PARM_DESC(pal, "Set PAL standard: BGH, DK, I, M, N, Nc, 60");
@@ -218,7 +219,7 @@ MODULE_PARM_DESC(ivtv_yuv_mode,
                 "\t\t\tDefault: 0 (interlaced)");
 MODULE_PARM_DESC(ivtv_yuv_threshold,
                 "If ivtv_yuv_mode is 2 (auto) then playback content as\n\t\tprogressive if src height <= ivtv_yuvthreshold\n"
-                "\t\t\tDefault: 480");;
+                "\t\t\tDefault: 480");
 MODULE_PARM_DESC(enc_mpg_buffers,
                 "Encoder MPG Buffers (in MB)\n"
                 "\t\t\tDefault: " __stringify(IVTV_DEFAULT_ENC_MPG_BUFFERS));
index 85ac707228e74377a9d4dd81ea5132146f2a07b1..aede061cae5d0b353edd7415af27575317e10578 100644 (file)
@@ -236,18 +236,6 @@ static int subdev_s_radio(struct v4l2_subdev *sd)
        return 0;
 }
 
-static int subdev_s_std(struct v4l2_subdev *sd, v4l2_std_id std)
-{
-       struct ivtv *itv = sd_to_ivtv(sd);
-       u16 mask, data;
-
-       mask = itv->card->gpio_audio_input.mask;
-       data = itv->card->gpio_audio_input.tuner;
-       if (mask)
-               write_reg((read_reg(IVTV_REG_GPIO_OUT) & ~mask) | (data & mask), IVTV_REG_GPIO_OUT);
-       return 0;
-}
-
 static int subdev_s_audio_routing(struct v4l2_subdev *sd,
                                  u32 input, u32 output, u32 config)
 {
@@ -344,7 +332,6 @@ static const struct v4l2_subdev_core_ops subdev_core_ops = {
        .g_ctrl = subdev_g_ctrl,
        .s_ctrl = subdev_s_ctrl,
        .queryctrl = subdev_queryctrl,
-       .s_std = subdev_s_std,
 };
 
 static const struct v4l2_subdev_tuner_ops subdev_tuner_ops = {
index e52aa322b13426dc3139aff85f5af87927cd5f7d..8f15a31d3f662e95c7b36452b643039da6560040 100644 (file)
@@ -509,7 +509,6 @@ static struct i2c_algorithm ivtv_algo = {
 /* template for our-bit banger */
 static struct i2c_adapter ivtv_i2c_adap_hw_template = {
        .name = "ivtv i2c driver",
-       .id = I2C_HW_B_CX2341X,
        .algo = &ivtv_algo,
        .algo_data = NULL,                      /* filled from template */
        .owner = THIS_MODULE,
@@ -560,7 +559,6 @@ static int ivtv_getsda_old(void *data)
 /* template for i2c-bit-algo */
 static struct i2c_adapter ivtv_i2c_adap_template = {
        .name = "ivtv i2c driver",
-       .id = I2C_HW_B_CX2341X,
        .algo = NULL,                   /* set by i2c-algo-bit */
        .algo_data = NULL,              /* filled from template */
        .owner = THIS_MODULE,
index 1d66855a379a99209aa51cfa418e7aa1f6e0d0db..d0765bed79c9512c727e561ddf4bf8cb59a7c525 100644 (file)
@@ -1915,8 +1915,7 @@ static void __devexit meye_remove(struct pci_dev *pcidev)
 }
 
 static struct pci_device_id meye_pci_tbl[] = {
-       { PCI_VENDOR_ID_KAWASAKI, PCI_DEVICE_ID_MCHIP_KL5A72002,
-         PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 },
+       { PCI_VDEVICE(KAWASAKI, PCI_DEVICE_ID_MCHIP_KL5A72002), 0 },
        { }
 };
 
index 416933ca607d28ac6a500907d9e6282399c6775b..cc06d5e4adcc65adf769993081a02840a95cefce 100644 (file)
@@ -65,9 +65,10 @@ void pvr2_msp3400_subdev_update(struct pvr2_hdw *hdw, struct v4l2_subdev *sd)
                u32 input;
 
                pvr2_trace(PVR2_TRACE_CHIPS, "subdev msp3400 v4l2 set_stereo");
+               sp = (sid < ARRAY_SIZE(routing_schemes)) ?
+                       routing_schemes[sid] : NULL;
 
-               if ((sid < ARRAY_SIZE(routing_schemes)) &&
-                   ((sp = routing_schemes[sid]) != NULL) &&
+               if ((sp != NULL) &&
                    (hdw->input_val >= 0) &&
                    (hdw->input_val < sp->cnt)) {
                        input = sp->def[hdw->input_val];
index 610bd848df246537ddd3b65da677c0643a4d8037..a334b1a966a2a4b07f3dc44f2398a9a12c095550 100644 (file)
@@ -540,7 +540,6 @@ static struct i2c_algorithm pvr2_i2c_algo_template = {
 static struct i2c_adapter pvr2_i2c_adap_template = {
        .owner         = THIS_MODULE,
        .class         = 0,
-       .id            = I2C_HW_B_BT848,
 };
 
 
index 8d17cf61330671f1d71c94dfc82a689f7b0bbf69..f976df452a34105367287e7c62a92fba1bd60d3a 100644 (file)
@@ -1057,7 +1057,8 @@ static int pwc_create_sysfs_files(struct video_device *vdev)
                goto err;
        if (pdev->features & FEATURE_MOTOR_PANTILT) {
                rc = device_create_file(&vdev->dev, &dev_attr_pan_tilt);
-               if (rc) goto err_button;
+               if (rc)
+                       goto err_button;
        }
 
        return 0;
@@ -1072,6 +1073,7 @@ err:
 static void pwc_remove_sysfs_files(struct video_device *vdev)
 {
        struct pwc_device *pdev = video_get_drvdata(vdev);
+
        if (pdev->features & FEATURE_MOTOR_PANTILT)
                device_remove_file(&vdev->dev, &dev_attr_pan_tilt);
        device_remove_file(&vdev->dev, &dev_attr_button);
@@ -1229,13 +1231,11 @@ static void pwc_cleanup(struct pwc_device *pdev)
        video_unregister_device(pdev->vdev);
 
 #ifdef CONFIG_USB_PWC_INPUT_EVDEV
-       if (pdev->button_dev) {
+       if (pdev->button_dev)
                input_unregister_device(pdev->button_dev);
-               input_free_device(pdev->button_dev);
-               kfree(pdev->button_dev->phys);
-               pdev->button_dev = NULL;
-       }
 #endif
+
+       kfree(pdev);
 }
 
 /* Note that all cleanup is done in the reverse order as in _open */
@@ -1281,8 +1281,6 @@ static int pwc_video_close(struct file *file)
                PWC_DEBUG_OPEN("<< video_close() vopen=%d\n", pdev->vopen);
        } else {
                pwc_cleanup(pdev);
-               /* Free memory (don't set pdev to 0 just yet) */
-               kfree(pdev);
                /* search device_hint[] table if we occupy a slot, by any chance */
                for (hint = 0; hint < MAX_DEV_HINTS; hint++)
                        if (device_hint[hint].pdev == pdev)
@@ -1499,13 +1497,10 @@ static int usb_pwc_probe(struct usb_interface *intf, const struct usb_device_id
        struct usb_device *udev = interface_to_usbdev(intf);
        struct pwc_device *pdev = NULL;
        int vendor_id, product_id, type_id;
-       int i, hint, rc;
+       int hint, rc;
        int features = 0;
        int video_nr = -1; /* default: use next available device */
        char serial_number[30], *name;
-#ifdef CONFIG_USB_PWC_INPUT_EVDEV
-       char *phys = NULL;
-#endif
 
        vendor_id = le16_to_cpu(udev->descriptor.idVendor);
        product_id = le16_to_cpu(udev->descriptor.idProduct);
@@ -1757,8 +1752,7 @@ static int usb_pwc_probe(struct usb_interface *intf, const struct usb_device_id
        pdev->vframes = default_fps;
        strcpy(pdev->serial, serial_number);
        pdev->features = features;
-       if (vendor_id == 0x046D && product_id == 0x08B5)
-       {
+       if (vendor_id == 0x046D && product_id == 0x08B5) {
                /* Logitech QuickCam Orbit
                   The ranges have been determined experimentally; they may differ from cam to cam.
                   Also, the exact ranges left-right and up-down are different for my cam
@@ -1780,8 +1774,8 @@ static int usb_pwc_probe(struct usb_interface *intf, const struct usb_device_id
        pdev->vdev = video_device_alloc();
        if (!pdev->vdev) {
                PWC_ERROR("Err, cannot allocate video_device struture. Failing probe.");
-               kfree(pdev);
-               return -ENOMEM;
+               rc = -ENOMEM;
+               goto err_free_mem;
        }
        memcpy(pdev->vdev, &pwc_template, sizeof(pwc_template));
        pdev->vdev->parent = &intf->dev;
@@ -1806,25 +1800,23 @@ static int usb_pwc_probe(struct usb_interface *intf, const struct usb_device_id
        }
 
        pdev->vdev->release = video_device_release;
-       i = video_register_device(pdev->vdev, VFL_TYPE_GRABBER, video_nr);
-       if (i < 0) {
-               PWC_ERROR("Failed to register as video device (%d).\n", i);
-               rc = i;
-               goto err;
-       }
-       else {
-               PWC_INFO("Registered as /dev/video%d.\n", pdev->vdev->num);
+       rc = video_register_device(pdev->vdev, VFL_TYPE_GRABBER, video_nr);
+       if (rc < 0) {
+               PWC_ERROR("Failed to register as video device (%d).\n", rc);
+               goto err_video_release;
        }
 
+       PWC_INFO("Registered as /dev/video%d.\n", pdev->vdev->num);
+
        /* occupy slot */
        if (hint < MAX_DEV_HINTS)
                device_hint[hint].pdev = pdev;
 
        PWC_DEBUG_PROBE("probe() function returning struct at 0x%p.\n", pdev);
-       usb_set_intfdata (intf, pdev);
+       usb_set_intfdata(intf, pdev);
        rc = pwc_create_sysfs_files(pdev->vdev);
        if (rc)
-               goto err_unreg;
+               goto err_video_unreg;
 
        /* Set the leds off */
        pwc_set_leds(pdev, 0, 0);
@@ -1835,16 +1827,16 @@ static int usb_pwc_probe(struct usb_interface *intf, const struct usb_device_id
        pdev->button_dev = input_allocate_device();
        if (!pdev->button_dev) {
                PWC_ERROR("Err, insufficient memory for webcam snapshot button device.");
-               return -ENOMEM;
+               rc = -ENOMEM;
+               pwc_remove_sysfs_files(pdev->vdev);
+               goto err_video_unreg;
        }
 
+       usb_make_path(udev, pdev->button_phys, sizeof(pdev->button_phys));
+       strlcat(pdev->button_phys, "/input0", sizeof(pdev->button_phys));
+
        pdev->button_dev->name = "PWC snapshot button";
-       phys = kasprintf(GFP_KERNEL,"usb-%s-%s", pdev->udev->bus->bus_name, pdev->udev->devpath);
-       if (!phys) {
-               input_free_device(pdev->button_dev);
-               return -ENOMEM;
-       }
-       pdev->button_dev->phys = phys;
+       pdev->button_dev->phys = pdev->button_phys;
        usb_to_input_id(pdev->udev, &pdev->button_dev->id);
        pdev->button_dev->dev.parent = &pdev->udev->dev;
        pdev->button_dev->evbit[0] = BIT_MASK(EV_KEY);
@@ -1853,25 +1845,27 @@ static int usb_pwc_probe(struct usb_interface *intf, const struct usb_device_id
        rc = input_register_device(pdev->button_dev);
        if (rc) {
                input_free_device(pdev->button_dev);
-               kfree(pdev->button_dev->phys);
                pdev->button_dev = NULL;
-               return rc;
+               pwc_remove_sysfs_files(pdev->vdev);
+               goto err_video_unreg;
        }
 #endif
 
        return 0;
 
-err_unreg:
+err_video_unreg:
        if (hint < MAX_DEV_HINTS)
                device_hint[hint].pdev = NULL;
        video_unregister_device(pdev->vdev);
-err:
-       video_device_release(pdev->vdev); /* Drip... drip... drip... */
-       kfree(pdev); /* Oops, no memory leaks please */
+       pdev->vdev = NULL;      /* So we don't try to release it below */
+err_video_release:
+       video_device_release(pdev->vdev);
+err_free_mem:
+       kfree(pdev);
        return rc;
 }
 
-/* The user janked out the cable... */
+/* The user yanked out the cable... */
 static void usb_pwc_disconnect(struct usb_interface *intf)
 {
        struct pwc_device *pdev;
@@ -1902,7 +1896,7 @@ static void usb_pwc_disconnect(struct usb_interface *intf)
        /* Alert waiting processes */
        wake_up_interruptible(&pdev->frameq);
        /* Wait until device is closed */
-       if(pdev->vopen) {
+       if (pdev->vopen) {
                mutex_lock(&pdev->modlock);
                pdev->unplugged = 1;
                mutex_unlock(&pdev->modlock);
@@ -1911,8 +1905,6 @@ static void usb_pwc_disconnect(struct usb_interface *intf)
                /* Device is closed, so we can safely unregister it */
                PWC_DEBUG_PROBE("Unregistering video device in disconnect().\n");
                pwc_cleanup(pdev);
-               /* Free memory (don't set pdev to 0 just yet) */
-               kfree(pdev);
 
 disconnect_out:
                /* search device_hint[] table if we occupy a slot, by any chance */
index 2876ce08451095fc275b151c129529744673ef93..bdb4ced57496c34b45c93709d7a6ddac8a25a97c 100644 (file)
@@ -1033,7 +1033,7 @@ long pwc_video_do_ioctl(struct file *file, unsigned int cmd, void *arg)
                        if (std->index != 0)
                                return -EINVAL;
                        std->id = V4L2_STD_UNKNOWN;
-                       strncpy(std->name, "webcam", sizeof(std->name));
+                       strlcpy(std->name, "webcam", sizeof(std->name));
                        return 0;
                }
 
index 0b658dee05a41f047fa55f171c4972fc5b140aa3..0902355dfa77a3daadaa7f025ac359d66e3171b1 100644 (file)
 #define DEVICE_USE_CODEC3(x) ((x)>=700)
 #define DEVICE_USE_CODEC23(x) ((x)>=675)
 
-
-#ifndef V4L2_PIX_FMT_PWC1
-#define V4L2_PIX_FMT_PWC1      v4l2_fourcc('P','W','C','1')
-#define V4L2_PIX_FMT_PWC2      v4l2_fourcc('P','W','C','2')
-#endif
-
 /* The following structures were based on cpia.h. Why reinvent the wheel? :-) */
 struct pwc_iso_buf
 {
@@ -259,6 +253,7 @@ struct pwc_device
    int snapshot_button_status;         /* set to 1 when the user push the button, reset to 0 when this value is read */
 #ifdef CONFIG_USB_PWC_INPUT_EVDEV
    struct input_dev *button_dev;       /* webcam snapshot button input */
+   char button_phys[64];
 #endif
 
    /*** Misc. data ***/
index c25e81af5ce09be383110d3d0452c53b3cd64074..c3e96f070973f993242af93d0822cdceae8bb143 100644 (file)
@@ -40,7 +40,7 @@
 /* insmod options */
 static unsigned int debug;
 static unsigned int xtal;
-static unsigned int rbds;
+static unsigned int mmbs;
 static unsigned int plvl;
 static unsigned int bufblocks = 100;
 
@@ -48,8 +48,8 @@ module_param(debug, int, 0644);
 MODULE_PARM_DESC(debug, "enable debug messages");
 module_param(xtal, int, 0);
 MODULE_PARM_DESC(xtal, "select oscillator frequency (0..3), default 0");
-module_param(rbds, int, 0);
-MODULE_PARM_DESC(rbds, "select mode, 0=RDS, 1=RBDS, default 0");
+module_param(mmbs, int, 0);
+MODULE_PARM_DESC(mmbs, "enable MMBS mode: 0=off (default), 1=on");
 module_param(plvl, int, 0);
 MODULE_PARM_DESC(plvl, "select pause level (0..3), default 0");
 module_param(bufblocks, int, 0);
@@ -78,6 +78,7 @@ struct saa6588 {
        unsigned char last_blocknum;
        wait_queue_head_t read_queue;
        int data_available_for_read;
+       u8 sync;
 };
 
 static inline struct saa6588 *to_saa6588(struct v4l2_subdev *sd)
@@ -261,13 +262,16 @@ static void saa6588_i2c_poll(struct saa6588 *s)
        unsigned char tmp;
 
        /* Although we only need 3 bytes, we have to read at least 6.
-          SAA6588 returns garbage otherwise */
+          SAA6588 returns garbage otherwise. */
        if (6 != i2c_master_recv(client, &tmpbuf[0], 6)) {
                if (debug > 1)
                        dprintk(PREFIX "read error!\n");
                return;
        }
 
+       s->sync = tmpbuf[0] & 0x10;
+       if (!s->sync)
+               return;
        blocknum = tmpbuf[0] >> 5;
        if (blocknum == s->last_blocknum) {
                if (debug > 3)
@@ -286,9 +290,8 @@ static void saa6588_i2c_poll(struct saa6588 *s)
           occurred during reception of this block.
           Bit 6: Corrected bit. Indicates that an error was
           corrected for this data block.
-          Bits 5-3: Received Offset. Indicates the offset received
-          by the sync system.
-          Bits 2-0: Offset Name. Indicates the offset applied to this data.
+          Bits 5-3: Same as bits 0-2.
+          Bits 2-0: Block number.
 
           SAA6588 byte order is Status-MSB-LSB, so we have to swap the
           first and the last of the 3 bytes block.
@@ -298,12 +301,21 @@ static void saa6588_i2c_poll(struct saa6588 *s)
        tmpbuf[2] = tmpbuf[0];
        tmpbuf[0] = tmp;
 
+       /* Map 'Invalid block E' to 'Invalid Block' */
+       if (blocknum == 6)
+               blocknum = V4L2_RDS_BLOCK_INVALID;
+       /* And if are not in mmbs mode, then 'Block E' is also mapped
+          to 'Invalid Block'. As far as I can tell MMBS is discontinued,
+          and if there is ever a need to support E blocks, then please
+          contact the linux-media mailinglist. */
+       else if (!mmbs && blocknum == 5)
+               blocknum = V4L2_RDS_BLOCK_INVALID;
        tmp = blocknum;
        tmp |= blocknum << 3;   /* Received offset == Offset Name (OK ?) */
        if ((tmpbuf[2] & 0x03) == 0x03)
-               tmp |= 0x80;    /* uncorrectable error */
+               tmp |= V4L2_RDS_BLOCK_ERROR;     /* uncorrectable error */
        else if ((tmpbuf[2] & 0x03) != 0x00)
-               tmp |= 0x40;    /* corrected error */
+               tmp |= V4L2_RDS_BLOCK_CORRECTED; /* corrected error */
        tmpbuf[2] = tmp;        /* Is this enough ? Should we also check other bits ? */
 
        spin_lock_irqsave(&s->lock, flags);
@@ -321,14 +333,14 @@ static void saa6588_work(struct work_struct *work)
        schedule_delayed_work(&s->work, msecs_to_jiffies(20));
 }
 
-static int saa6588_configure(struct saa6588 *s)
+static void saa6588_configure(struct saa6588 *s)
 {
        struct i2c_client *client = v4l2_get_subdevdata(&s->sd);
        unsigned char buf[3];
        int rc;
 
        buf[0] = cSyncRestart;
-       if (rbds)
+       if (mmbs)
                buf[0] |= cProcessingModeRBDS;
 
        buf[1] = cFlywheelDefault;
@@ -374,8 +386,6 @@ static int saa6588_configure(struct saa6588 *s)
        rc = i2c_master_send(client, buf, 3);
        if (rc != 3)
                printk(PREFIX "i2c i/o error: rc == %d (should be 3)\n", rc);
-
-       return 0;
 }
 
 /* ---------------------------------------------------------------------- */
@@ -416,6 +426,24 @@ static long saa6588_ioctl(struct v4l2_subdev *sd, unsigned int cmd, void *arg)
        return 0;
 }
 
+static int saa6588_g_tuner(struct v4l2_subdev *sd, struct v4l2_tuner *vt)
+{
+       struct saa6588 *s = to_saa6588(sd);
+
+       vt->capability |= V4L2_TUNER_CAP_RDS;
+       if (s->sync)
+               vt->rxsubchans |= V4L2_TUNER_SUB_RDS;
+       return 0;
+}
+
+static int saa6588_s_tuner(struct v4l2_subdev *sd, struct v4l2_tuner *vt)
+{
+       struct saa6588 *s = to_saa6588(sd);
+
+       saa6588_configure(s);
+       return 0;
+}
+
 static int saa6588_g_chip_ident(struct v4l2_subdev *sd, struct v4l2_dbg_chip_ident *chip)
 {
        struct i2c_client *client = v4l2_get_subdevdata(sd);
@@ -430,8 +458,14 @@ static const struct v4l2_subdev_core_ops saa6588_core_ops = {
        .ioctl = saa6588_ioctl,
 };
 
+static const struct v4l2_subdev_tuner_ops saa6588_tuner_ops = {
+       .g_tuner = saa6588_g_tuner,
+       .s_tuner = saa6588_s_tuner,
+};
+
 static const struct v4l2_subdev_ops saa6588_ops = {
        .core = &saa6588_core_ops,
+       .tuner = &saa6588_tuner_ops,
 };
 
 /* ---------------------------------------------------------------------- */
index 5bcce092e804dff85d5598f2c940b417c36aa5b4..22bfd62c9551589229aad5cd8d80f335c8c1a4eb 100644 (file)
@@ -47,6 +47,7 @@ config VIDEO_SAA7134_DVB
        select DVB_TDA10048 if !DVB_FE_CUSTOMISE
        select MEDIA_TUNER_TDA18271 if !MEDIA_TUNER_CUSTOMISE
        select MEDIA_TUNER_TDA8290 if !MEDIA_TUNER_CUSTOMISE
+       select DVB_ZL10039 if !DVB_FE_CUSTOMISE
        ---help---
          This adds support for DVB cards based on the
          Philips saa7134 chip.
index 63c4b8f1f541b5f2c7e22fffaa9f9dc0b98be316..1eabff6b2456a5744fcaf6b7fe0e42d344fab576 100644 (file)
@@ -468,7 +468,7 @@ static int handle_ctrl(int has_ac3, struct saa6752hs_mpeg_params *params,
                if (set && new != V4L2_MPEG_AUDIO_ENCODING_LAYER_2 &&
                    (!has_ac3 || new != V4L2_MPEG_AUDIO_ENCODING_AC3))
                        return -ERANGE;
-               new = old;
+               params->au_encoding = new;
                break;
        case V4L2_CID_MPEG_AUDIO_L2_BITRATE:
                old = params->au_l2_bitrate;
index 8b0b64a89874dcbaa1e591c72af22074477a8c88..d48c450ed77c948a0d278f7f26c6543fcc7d62b7 100644 (file)
@@ -40,6 +40,7 @@ MODULE_PARM_DESC(debug,"enable debug messages [alsa]");
  */
 
 /* defaults */
+#define MIXER_ADDR_UNSELECTED  -1
 #define MIXER_ADDR_TVTUNER     0
 #define MIXER_ADDR_LINE1       1
 #define MIXER_ADDR_LINE2       2
@@ -68,7 +69,9 @@ typedef struct snd_card_saa7134 {
        struct snd_card *card;
        spinlock_t mixer_lock;
        int mixer_volume[MIXER_ADDR_LAST+1][2];
-       int capture_source[MIXER_ADDR_LAST+1][2];
+       int capture_source_addr;
+       int capture_source[2];
+       struct snd_kcontrol *capture_ctl[MIXER_ADDR_LAST+1];
        struct pci_dev *pci;
        struct saa7134_dev *dev;
 
@@ -314,6 +317,115 @@ static int dsp_buffer_free(struct saa7134_dev *dev)
        return 0;
 }
 
+/*
+ * Setting the capture source and updating the ALSA controls
+ */
+static int snd_saa7134_capsrc_set(struct snd_kcontrol *kcontrol,
+                                 int left, int right, bool force_notify)
+{
+       snd_card_saa7134_t *chip = snd_kcontrol_chip(kcontrol);
+       int change = 0, addr = kcontrol->private_value;
+       int active, old_addr;
+       u32 anabar, xbarin;
+       int analog_io, rate;
+       struct saa7134_dev *dev;
+
+       dev = chip->dev;
+
+       spin_lock_irq(&chip->mixer_lock);
+
+       active = left != 0 || right != 0;
+       old_addr = chip->capture_source_addr;
+
+       /* The active capture source cannot be deactivated */
+       if (active) {
+               change = old_addr != addr ||
+                        chip->capture_source[0] != left ||
+                        chip->capture_source[1] != right;
+
+               chip->capture_source[0] = left;
+               chip->capture_source[1] = right;
+               chip->capture_source_addr = addr;
+               dev->dmasound.input = addr;
+       }
+       spin_unlock_irq(&chip->mixer_lock);
+
+       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;
+               }
+       }
+
+       if (change) {
+               if (force_notify)
+                       snd_ctl_notify(chip->card,
+                                      SNDRV_CTL_EVENT_MASK_VALUE,
+                                      &chip->capture_ctl[addr]->id);
+
+               if (old_addr != MIXER_ADDR_UNSELECTED && old_addr != addr)
+                       snd_ctl_notify(chip->card,
+                                      SNDRV_CTL_EVENT_MASK_VALUE,
+                                      &chip->capture_ctl[old_addr]->id);
+       }
+
+       return change;
+}
 
 /*
  * ALSA PCM preparation
@@ -401,6 +513,10 @@ static int snd_card_saa7134_capture_prepare(struct snd_pcm_substream * substream
 
        dev->dmasound.rate = runtime->rate;
 
+       /* Setup and update the card/ALSA controls */
+       snd_saa7134_capsrc_set(saa7134->capture_ctl[dev->dmasound.input], 1, 1,
+                              true);
+
        return 0;
 
 }
@@ -435,6 +551,16 @@ snd_card_saa7134_capture_pointer(struct snd_pcm_substream * substream)
 
 /*
  * ALSA hardware capabilities definition
+ *
+ *  Report only 32kHz for ALSA:
+ *
+ *  - SAA7133/35 uses DDEP (DemDec Easy Programming mode), which works in 32kHz
+ *    only
+ *  - SAA7134 for TV mode uses DemDec mode (32kHz)
+ *  - Radio works in 32kHz only
+ *  - When recording 48kHz from Line1/Line2, switching of capture source to TV
+ *    means
+ *    switching to 32kHz without any frequency translation
  */
 
 static struct snd_pcm_hardware snd_card_saa7134_capture =
@@ -448,9 +574,9 @@ static struct snd_pcm_hardware snd_card_saa7134_capture =
                                SNDRV_PCM_FMTBIT_U8 | \
                                SNDRV_PCM_FMTBIT_U16_LE | \
                                SNDRV_PCM_FMTBIT_U16_BE,
-       .rates =                SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_48000,
+       .rates =                SNDRV_PCM_RATE_32000,
        .rate_min =             32000,
-       .rate_max =             48000,
+       .rate_max =             32000,
        .channels_min =         1,
        .channels_max =         2,
        .buffer_bytes_max =     (256*1024),
@@ -836,8 +962,13 @@ static int snd_saa7134_capsrc_get(struct snd_kcontrol * kcontrol,
        int addr = kcontrol->private_value;
 
        spin_lock_irq(&chip->mixer_lock);
-       ucontrol->value.integer.value[0] = chip->capture_source[addr][0];
-       ucontrol->value.integer.value[1] = chip->capture_source[addr][1];
+       if (chip->capture_source_addr == addr) {
+               ucontrol->value.integer.value[0] = chip->capture_source[0];
+               ucontrol->value.integer.value[1] = chip->capture_source[1];
+       } else {
+               ucontrol->value.integer.value[0] = 0;
+               ucontrol->value.integer.value[1] = 0;
+       }
        spin_unlock_irq(&chip->mixer_lock);
 
        return 0;
@@ -846,87 +977,22 @@ static int snd_saa7134_capsrc_get(struct snd_kcontrol * kcontrol,
 static int snd_saa7134_capsrc_put(struct snd_kcontrol * kcontrol,
                                  struct snd_ctl_elem_value * ucontrol)
 {
-       snd_card_saa7134_t *chip = snd_kcontrol_chip(kcontrol);
-       int change, addr = kcontrol->private_value;
        int left, right;
-       u32 anabar, xbarin;
-       int analog_io, rate;
-       struct saa7134_dev *dev;
-
-       dev = chip->dev;
-
        left = ucontrol->value.integer.value[0] & 1;
        right = ucontrol->value.integer.value[1] & 1;
-       spin_lock_irq(&chip->mixer_lock);
-
-       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_irq(&chip->mixer_lock);
-
-
-       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;
+       return snd_saa7134_capsrc_set(kcontrol, left, right, false);
 }
 
-static struct snd_kcontrol_new snd_saa7134_controls[] = {
+static struct snd_kcontrol_new snd_saa7134_volume_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),
+};
+
+static struct snd_kcontrol_new snd_saa7134_capture_controls[] = {
+SAA713x_CAPSRC("Video Capture Switch", 0, MIXER_ADDR_TVTUNER),
+SAA713x_CAPSRC("Line Capture Switch", 1, MIXER_ADDR_LINE1),
 SAA713x_CAPSRC("Line Capture Switch", 2, MIXER_ADDR_LINE2),
 };
 
@@ -941,17 +1007,33 @@ SAA713x_CAPSRC("Line Capture Switch", 2, MIXER_ADDR_LINE2),
 static int snd_card_saa7134_new_mixer(snd_card_saa7134_t * chip)
 {
        struct snd_card *card = chip->card;
+       struct snd_kcontrol *kcontrol;
        unsigned int idx;
-       int err;
+       int err, addr;
 
        if (snd_BUG_ON(!chip))
                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)
+       for (idx = 0; idx < ARRAY_SIZE(snd_saa7134_volume_controls); idx++) {
+               kcontrol = snd_ctl_new1(&snd_saa7134_volume_controls[idx],
+                                       chip);
+               err = snd_ctl_add(card, kcontrol);
+               if (err < 0)
                        return err;
        }
+
+       for (idx = 0; idx < ARRAY_SIZE(snd_saa7134_capture_controls); idx++) {
+               kcontrol = snd_ctl_new1(&snd_saa7134_capture_controls[idx],
+                                       chip);
+               addr = snd_saa7134_capture_controls[idx].private_value;
+               chip->capture_ctl[addr] = kcontrol;
+               err = snd_ctl_add(card, kcontrol);
+               if (err < 0)
+                       return err;
+       }
+
+       chip->capture_source_addr = MIXER_ADDR_UNSELECTED;
        return 0;
 }
 
index 6eebe3ef97d37efa9f8375eafa53e6b75420f79a..1b29487fd2544ad36231acaf4789e3a9ab3eaaf3 100644 (file)
@@ -32,6 +32,7 @@
 #include <media/tveeprom.h>
 #include "tea5767.h"
 #include "tda18271.h"
+#include "xc5000.h"
 
 /* commly used strings */
 static char name_mute[]    = "mute";
@@ -265,6 +266,56 @@ struct saa7134_board saa7134_boards[] = {
                        .gpio = 0x10000,
                },
        },
+       [SAA7134_BOARD_ROVERMEDIA_LINK_PRO_FM] = {
+               /* RoverMedia TV Link Pro FM (LR138 REV:I) */
+               /* Eugene Yudin <Eugene.Yudin@gmail.com> */
+               .name           = "RoverMedia TV Link Pro FM",
+               .audio_clock    = 0x00200000,
+               .tuner_type     = TUNER_PHILIPS_FM1216ME_MK3, /* TCL MFPE05 2 */
+               .radio_type     = UNSET,
+               .tuner_addr     = ADDR_UNSET,
+               .radio_addr     = ADDR_UNSET,
+               .tda9887_conf   = TDA9887_PRESENT,
+               .gpiomask       = 0xe000,
+               .inputs         = { {
+                       .name = name_tv,
+                       .vmux = 1,
+                       .amux = TV,
+                       .gpio = 0x8000,
+                       .tv   = 1,
+               }, {
+                       .name = name_tv_mono,
+                       .vmux = 1,
+                       .amux = LINE2,
+                       .gpio = 0x0000,
+                       .tv   = 1,
+               }, {
+                       .name = name_comp1,
+                       .vmux = 0,
+                       .amux = LINE2,
+                       .gpio = 0x4000,
+               }, {
+                       .name = name_comp2,
+                       .vmux = 3,
+                       .amux = LINE2,
+                       .gpio = 0x4000,
+               }, {
+                       .name = name_svideo,
+                       .vmux = 8,
+                       .amux = LINE2,
+                       .gpio = 0x4000,
+               } },
+               .radio = {
+                       .name = name_radio,
+                       .amux = LINE2,
+                       .gpio = 0x2000,
+               },
+               .mute = {
+                       .name = name_mute,
+                       .amux = TV,
+                       .gpio = 0x8000,
+               },
+       },
        [SAA7134_BOARD_EMPRESS] = {
                /* "Gert Vervoort" <gert.vervoort@philips.com> */
                .name           = "EMPRESS",
@@ -1364,6 +1415,42 @@ struct saa7134_board saa7134_boards[] = {
                        .amux = LINE1,
                },
        },
+       [SAA7134_BOARD_AVERMEDIA_STUDIO_505] = {
+               /* Vasiliy Temnikov <vaka@newmail.ru> */
+               .name           = "AverMedia AverTV Studio 505",
+               .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 = 1,
+                       .amux = LINE2,
+                       .tv   = 1,
+               }, {
+                       .name = name_comp1,
+                       .vmux = 0,
+                       .amux = LINE2,
+               }, {
+                       .name = name_comp2,
+                       .vmux = 3,
+                       .amux = LINE2,
+               },{
+                       .name = name_svideo,
+                       .vmux = 8,
+                       .amux = LINE2,
+               } },
+               .radio = {
+                       .name = name_radio,
+                       .amux = LINE2,
+               },
+               .mute = {
+                       .name = name_mute,
+                       .amux = LINE1,
+               },
+       },
        [SAA7134_BOARD_UPMOST_PURPLE_TV] = {
                .name           = "UPMOST PURPLE TV",
                .audio_clock    = 0x00187de7,
@@ -1633,7 +1720,7 @@ struct saa7134_board saa7134_boards[] = {
                }},
                .radio = {
                        .name = name_radio,
-                       .amux = LINE1,
+                       .amux = TV,
                        .gpio = 0x00300001,
                },
                .mute = {
@@ -3663,8 +3750,8 @@ struct saa7134_board saa7134_boards[] = {
                        .amux = TV,
                        .gpio = 0x0200000,
                },
-       },
-       [SAA7134_BOARD_ASUSTeK_P7131_ANALOG] = {
+       },
+       [SAA7134_BOARD_ASUSTeK_P7131_ANALOG] = {
               .name           = "ASUSTeK P7131 Analog",
               .audio_clock    = 0x00187de7,
               .tuner_type     = TUNER_PHILIPS_TDA8290,
@@ -4081,6 +4168,7 @@ struct saa7134_board saa7134_boards[] = {
                .radio_type     = UNSET,
                .tuner_addr     = ADDR_UNSET,
                .radio_addr     = ADDR_UNSET,
+               .rds_addr       = 0x10,
                .tda9887_conf   = TDA9887_PRESENT,
                .gpiomask       = 0x00008000,
                .inputs         = {{
@@ -4145,6 +4233,7 @@ struct saa7134_board saa7134_boards[] = {
                .radio_type     = UNSET,
                .tuner_addr     = ADDR_UNSET,
                .radio_addr     = ADDR_UNSET,
+               .rds_addr       = 0x10,
                .tda9887_conf   = TDA9887_PRESENT,
                .gpiomask       = 0x00008000,
                .inputs         = {{
@@ -4175,6 +4264,7 @@ struct saa7134_board saa7134_boards[] = {
                .radio_type     = UNSET,
                .tuner_addr     = ADDR_UNSET,
                .radio_addr     = ADDR_UNSET,
+               .rds_addr       = 0x10,
                .tda9887_conf   = TDA9887_PRESENT,
                .gpiomask       = 0x00008000,
                .inputs         = {{
@@ -4350,6 +4440,7 @@ struct saa7134_board saa7134_boards[] = {
                .radio_type     = UNSET,
                .tuner_addr     = ADDR_UNSET,
                .radio_addr     = ADDR_UNSET,
+               .rds_addr       = 0x10,
                .tda9887_conf   = TDA9887_PRESENT,
                .inputs         = {{
                        .name = name_tv,
@@ -4378,6 +4469,7 @@ struct saa7134_board saa7134_boards[] = {
                .radio_type     = UNSET,
                .tuner_addr     = ADDR_UNSET,
                .radio_addr     = ADDR_UNSET,
+               .rds_addr       = 0x10,
                .tda9887_conf   = TDA9887_PRESENT,
                .inputs         = {{
                        .name = name_tv,
@@ -4406,6 +4498,7 @@ struct saa7134_board saa7134_boards[] = {
                .radio_type     = UNSET,
                .tuner_addr     = ADDR_UNSET,
                .radio_addr     = ADDR_UNSET,
+               .rds_addr       = 0x10,
                .tda9887_conf   = TDA9887_PRESENT,
                .inputs         = {{
                        .name = name_tv,
@@ -4434,6 +4527,7 @@ struct saa7134_board saa7134_boards[] = {
                .radio_type     = UNSET,
                .tuner_addr     = ADDR_UNSET,
                .radio_addr     = ADDR_UNSET,
+               .rds_addr       = 0x10,
                .tda9887_conf   = TDA9887_PRESENT,
                .inputs         = {{
                        .name = name_tv,
@@ -4540,6 +4634,7 @@ struct saa7134_board saa7134_boards[] = {
                .radio_type     = UNSET,
                .tuner_addr     = ADDR_UNSET,
                .radio_addr     = ADDR_UNSET,
+               .rds_addr       = 0x10,
                .empress_addr   = 0x20,
                .tda9887_conf   = TDA9887_PRESENT,
                .inputs         = { {
@@ -4861,7 +4956,7 @@ struct saa7134_board saa7134_boards[] = {
                /* Igor Kuznetsov <igk@igk.ru> */
                .name           = "Beholder BeholdTV H6",
                .audio_clock    = 0x00187de7,
-               .tuner_type     = TUNER_PHILIPS_FMD1216ME_MK3,
+               .tuner_type     = TUNER_PHILIPS_FMD1216MEX_MK3,
                .radio_type     = UNSET,
                .tuner_addr     = ADDR_UNSET,
                .radio_addr     = ADDR_UNSET,
@@ -5116,6 +5211,53 @@ struct saa7134_board saa7134_boards[] = {
                        .gpio = 0x00,
                },
        },
+       [SAA7134_BOARD_VIDEOMATE_S350] = {
+               /* Jan D. Louw <jd.louw@mweb.co.za */
+               .name           = "Compro VideoMate S350/S300",
+               .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   = 0,
+                       .amux   = LINE1,
+               }, {
+                       .name   = name_svideo,
+                       .vmux   = 8, /* Not tested */
+                       .amux   = LINE1
+               } },
+       },
+       [SAA7134_BOARD_BEHOLD_X7] = {
+               /* Beholder Intl. Ltd. Dmitry Belimov <d.belimov@gmail.com> */
+               .name           = "Beholder BeholdTV X7",
+               .audio_clock    = 0x00187de7,
+               .tuner_type     = TUNER_XC5000,
+               .radio_type     = UNSET,
+               .tuner_addr     = ADDR_UNSET,
+               .radio_addr     = ADDR_UNSET,
+               .inputs         = { {
+                       .name = name_tv,
+                       .vmux = 2,
+                       .amux = TV,
+                       .tv   = 1,
+               }, {
+                       .name = name_comp1,
+                       .vmux = 0,
+                       .amux = LINE1,
+               }, {
+                       .name = name_svideo,
+                       .vmux = 9,
+                       .amux = LINE1,
+               } },
+               .radio = {
+                       .name = name_radio,
+                       .amux = TV,
+               },
+       },
+
 };
 
 const unsigned int saa7134_bcount = ARRAY_SIZE(saa7134_boards);
@@ -5371,6 +5513,12 @@ struct pci_device_id saa7134_pci_tbl[] = {
                .subdevice    = 0x2115,
                .driver_data  = SAA7134_BOARD_AVERMEDIA_STUDIO_305,
        },{
+               .vendor       = PCI_VENDOR_ID_PHILIPS,
+               .device       = PCI_DEVICE_ID_PHILIPS_SAA7130,
+               .subvendor    = 0x1461, /* Avermedia Technologies Inc */
+               .subdevice    = 0xa115,
+               .driver_data  = SAA7134_BOARD_AVERMEDIA_STUDIO_505,
+       }, {
                .vendor       = PCI_VENDOR_ID_PHILIPS,
                .device       = PCI_DEVICE_ID_PHILIPS_SAA7130,
                .subvendor    = 0x1461, /* Avermedia Technologies Inc */
@@ -6223,7 +6371,24 @@ struct pci_device_id saa7134_pci_tbl[] = {
                .subvendor    = 0x1461, /* Avermedia Technologies Inc */
                .subdevice    = 0xf31d,
                .driver_data  = SAA7134_BOARD_AVERMEDIA_GO_007_FM_PLUS,
-
+       }, {
+               .vendor       = PCI_VENDOR_ID_PHILIPS,
+               .device       = PCI_DEVICE_ID_PHILIPS_SAA7130,
+               .subvendor    = 0x185b,
+               .subdevice    = 0xc900,
+               .driver_data  = SAA7134_BOARD_VIDEOMATE_S350,
+       }, {
+               .vendor       = PCI_VENDOR_ID_PHILIPS,
+               .device       = PCI_DEVICE_ID_PHILIPS_SAA7133,
+               .subvendor    = 0x5ace, /* Beholder Intl. Ltd. */
+               .subdevice    = 0x7595,
+               .driver_data  = SAA7134_BOARD_BEHOLD_X7,
+       }, {
+               .vendor       = PCI_VENDOR_ID_PHILIPS,
+               .device       = PCI_DEVICE_ID_PHILIPS_SAA7134,
+               .subvendor    = 0x19d1, /* RoverMedia */
+               .subdevice    = 0x0138, /* LifeView FlyTV Prime30 OEM */
+               .driver_data  = SAA7134_BOARD_ROVERMEDIA_LINK_PRO_FM,
        }, {
                /* --- boards without eeprom + subsystem ID --- */
                .vendor       = PCI_VENDOR_ID_PHILIPS,
@@ -6310,6 +6475,32 @@ static int saa7134_xc2028_callback(struct saa7134_dev *dev,
        return -EINVAL;
 }
 
+static int saa7134_xc5000_callback(struct saa7134_dev *dev,
+                                  int command, int arg)
+{
+       switch (dev->board) {
+       case SAA7134_BOARD_BEHOLD_X7:
+               if (command == XC5000_TUNER_RESET) {
+               /* Down and UP pheripherial RESET pin for reset all chips */
+                       saa_writeb(SAA7134_SPECIAL_MODE, 0x00);
+                       msleep(10);
+                       saa_writeb(SAA7134_SPECIAL_MODE, 0x01);
+                       msleep(10);
+               }
+               break;
+       default:
+               saa_andorl(SAA7134_GPIO_GPMODE0 >> 2, 0x06e20000, 0x06e20000);
+               saa_andorl(SAA7134_GPIO_GPSTATUS0 >> 2, 0x06a20000, 0x06a20000);
+               saa_andorl(SAA7133_ANALOG_IO_SELECT >> 2, 0x02, 0x02);
+               saa_andorl(SAA7134_ANALOG_IN_CTRL1 >> 2, 0x81, 0x81);
+               saa_andorl(SAA7134_AUDIO_CLOCK0 >> 2, 0x03187de7, 0x03187de7);
+               saa_andorl(SAA7134_AUDIO_PLL_CTRL >> 2, 0x03, 0x03);
+               saa_andorl(SAA7134_AUDIO_CLOCKS_PER_FIELD0 >> 2,
+                          0x0001e000, 0x0001e000);
+               break;
+       }
+       return 0;
+}
 
 static int saa7134_tda8290_827x_callback(struct saa7134_dev *dev,
                                         int command, int arg)
@@ -6406,6 +6597,8 @@ int saa7134_tuner_callback(void *priv, int component, int command, int arg)
                        return saa7134_tda8290_callback(dev, command, arg);
                case TUNER_XC2028:
                        return saa7134_xc2028_callback(dev, command, arg);
+               case TUNER_XC5000:
+                       return saa7134_xc5000_callback(dev, command, arg);
                }
        } else {
                printk(KERN_ERR "saa7134: Error - device struct undefined.\n");
@@ -6476,6 +6669,7 @@ int saa7134_board_init1(struct saa7134_dev *dev)
        case SAA7134_BOARD_KWORLD_VSTREAM_XPERT:
        case SAA7134_BOARD_KWORLD_XPERT:
        case SAA7134_BOARD_AVERMEDIA_STUDIO_305:
+       case SAA7134_BOARD_AVERMEDIA_STUDIO_505:
        case SAA7134_BOARD_AVERMEDIA_305:
        case SAA7134_BOARD_AVERMEDIA_STUDIO_307:
        case SAA7134_BOARD_AVERMEDIA_307:
@@ -6500,7 +6694,7 @@ int saa7134_board_init1(struct saa7134_dev *dev)
        case SAA7134_BOARD_FLYDVBT_LR301:
        case SAA7134_BOARD_ASUSTeK_P7131_DUAL:
        case SAA7134_BOARD_ASUSTeK_P7131_HYBRID_LNA:
-       case SAA7134_BOARD_ASUSTeK_P7131_ANALOG:
+       case SAA7134_BOARD_ASUSTeK_P7131_ANALOG:
        case SAA7134_BOARD_FLYDVBTDUO:
        case SAA7134_BOARD_PROTEUS_2309:
        case SAA7134_BOARD_AVERMEDIA_A16AR:
@@ -6525,6 +6719,7 @@ int saa7134_board_init1(struct saa7134_dev *dev)
        case SAA7134_BOARD_REAL_ANGEL_220:
        case SAA7134_BOARD_KWORLD_PLUS_TV_ANALOG:
        case SAA7134_BOARD_AVERMEDIA_GO_007_FM_PLUS:
+       case SAA7134_BOARD_ROVERMEDIA_LINK_PRO_FM:
                dev->has_remote = SAA7134_REMOTE_GPIO;
                break;
        case SAA7134_BOARD_FLYDVBS_LR300:
@@ -6653,6 +6848,7 @@ int saa7134_board_init1(struct saa7134_dev *dev)
        case SAA7134_BOARD_BEHOLD_M63:
        case SAA7134_BOARD_BEHOLD_M6_EXTRA:
        case SAA7134_BOARD_BEHOLD_H6:
+       case SAA7134_BOARD_BEHOLD_X7:
                dev->has_remote = SAA7134_REMOTE_I2C;
                break;
        case SAA7134_BOARD_AVERMEDIA_A169_B:
@@ -6673,6 +6869,11 @@ int saa7134_board_init1(struct saa7134_dev *dev)
                saa_andorl(SAA7134_GPIO_GPMODE0 >> 2,   0x80040100, 0x80040100);
                saa_andorl(SAA7134_GPIO_GPSTATUS0 >> 2, 0x80040100, 0x00040100);
                break;
+       case SAA7134_BOARD_VIDEOMATE_S350:
+               dev->has_remote = SAA7134_REMOTE_GPIO;
+               saa_andorl(SAA7134_GPIO_GPMODE0 >> 2,   0x00008000, 0x00008000);
+               saa_andorl(SAA7134_GPIO_GPSTATUS0 >> 2, 0x00008000, 0x00008000);
+               break;
        }
        return 0;
 }
index 94a023a14bbc7109843cd7ebae941204d9659604..cb78c956d810fc1c83fdce543f95ba568f15b603 100644 (file)
@@ -1012,8 +1012,10 @@ static int __devinit saa7134_initdev(struct pci_dev *pci_dev,
                sd = v4l2_i2c_new_probed_subdev_addr(&dev->v4l2_dev,
                                &dev->i2c_adap, "saa6588", "saa6588",
                                saa7134_boards[dev->board].rds_addr);
-               if (sd)
+               if (sd) {
                        printk(KERN_INFO "%s: found RDS decoder\n", dev->name);
+                       dev->has_rds = 1;
+               }
        }
 
        request_submodules(dev);
index 98f3efd1e944defe96509f6b6dcb8b79ef00a47c..ebde21dba7e3bfe9d78c0e459b1f9833dc0eb7df 100644 (file)
@@ -56,6 +56,7 @@
 #include "zl10353.h"
 
 #include "zl10036.h"
+#include "zl10039.h"
 #include "mt312.h"
 
 MODULE_AUTHOR("Gerd Knorr <kraxel@bytesex.org> [SuSE Labs]");
@@ -968,6 +969,10 @@ static struct zl10036_config avertv_a700_tuner = {
        .tuner_address = 0x60,
 };
 
+static struct mt312_config zl10313_compro_s350_config = {
+       .demod_address = 0x0e,
+};
+
 static struct lgdt3305_config hcw_lgdt3305_config = {
        .i2c_addr           = 0x0e,
        .mpeg_mode          = LGDT3305_MPEG_SERIAL,
@@ -1457,7 +1462,7 @@ static int dvb_init(struct saa7134_dev *dev)
                if (fe0->dvb.frontend) {
                        dvb_attach(simple_tuner_attach, fe0->dvb.frontend,
                                   &dev->i2c_adap, 0x61,
-                                  TUNER_PHILIPS_FMD1216ME_MK3);
+                                  TUNER_PHILIPS_FMD1216MEX_MK3);
                }
                break;
        case SAA7134_BOARD_AVERMEDIA_A700_PRO:
@@ -1472,6 +1477,16 @@ static int dvb_init(struct saa7134_dev *dev)
                                        __func__);
                        }
                }
+               break;
+       case SAA7134_BOARD_VIDEOMATE_S350:
+               fe0->dvb.frontend = dvb_attach(mt312_attach,
+                               &zl10313_compro_s350_config, &dev->i2c_adap);
+               if (fe0->dvb.frontend)
+                       if (dvb_attach(zl10039_attach, fe0->dvb.frontend,
+                                       0x60, &dev->i2c_adap) == NULL)
+                               wprintk("%s: No zl10039 found!\n",
+                                       __func__);
+
                break;
        default:
                wprintk("Huh? unknown DVB card?\n");
index 6e219c2db8419013ab3ced30470ad1c19431974a..e1e83c7b966ed47844f3c6612f6ccb1cc32bbc85 100644 (file)
@@ -394,7 +394,7 @@ int saa7134_input_init1(struct saa7134_dev *dev)
 {
        struct card_ir *ir;
        struct input_dev *input_dev;
-       IR_KEYTAB_TYPE *ir_codes = NULL;
+       struct ir_scancode_table *ir_codes = NULL;
        u32 mask_keycode = 0;
        u32 mask_keydown = 0;
        u32 mask_keyup   = 0;
@@ -415,27 +415,28 @@ int saa7134_input_init1(struct saa7134_dev *dev)
        case SAA7134_BOARD_FLYVIDEO3000:
        case SAA7134_BOARD_FLYTVPLATINUM_FM:
        case SAA7134_BOARD_FLYTVPLATINUM_MINI2:
-               ir_codes     = ir_codes_flyvideo;
+       case SAA7134_BOARD_ROVERMEDIA_LINK_PRO_FM:
+               ir_codes     = &ir_codes_flyvideo_table;
                mask_keycode = 0xEC00000;
                mask_keydown = 0x0040000;
                break;
        case SAA7134_BOARD_CINERGY400:
        case SAA7134_BOARD_CINERGY600:
        case SAA7134_BOARD_CINERGY600_MK3:
-               ir_codes     = ir_codes_cinergy;
+               ir_codes     = &ir_codes_cinergy_table;
                mask_keycode = 0x00003f;
                mask_keyup   = 0x040000;
                break;
        case SAA7134_BOARD_ECS_TVP3XP:
        case SAA7134_BOARD_ECS_TVP3XP_4CB5:
-               ir_codes     = ir_codes_eztv;
+               ir_codes     = &ir_codes_eztv_table;
                mask_keycode = 0x00017c;
                mask_keyup   = 0x000002;
                polling      = 50; // ms
                break;
        case SAA7134_BOARD_KWORLD_XPERT:
        case SAA7134_BOARD_AVACSSMARTTV:
-               ir_codes     = ir_codes_pixelview;
+               ir_codes     = &ir_codes_pixelview_table;
                mask_keycode = 0x00001F;
                mask_keyup   = 0x000020;
                polling      = 50; // ms
@@ -445,13 +446,14 @@ int saa7134_input_init1(struct saa7134_dev *dev)
        case SAA7134_BOARD_AVERMEDIA_305:
        case SAA7134_BOARD_AVERMEDIA_307:
        case SAA7134_BOARD_AVERMEDIA_STUDIO_305:
+       case SAA7134_BOARD_AVERMEDIA_STUDIO_505:
        case SAA7134_BOARD_AVERMEDIA_STUDIO_307:
        case SAA7134_BOARD_AVERMEDIA_STUDIO_507:
        case SAA7134_BOARD_AVERMEDIA_STUDIO_507UA:
        case SAA7134_BOARD_AVERMEDIA_GO_007_FM:
        case SAA7134_BOARD_AVERMEDIA_M102:
        case SAA7134_BOARD_AVERMEDIA_GO_007_FM_PLUS:
-               ir_codes     = ir_codes_avermedia;
+               ir_codes     = &ir_codes_avermedia_table;
                mask_keycode = 0x0007C8;
                mask_keydown = 0x000010;
                polling      = 50; // ms
@@ -460,14 +462,14 @@ int saa7134_input_init1(struct saa7134_dev *dev)
                saa_setb(SAA7134_GPIO_GPSTATUS0, 0x4);
                break;
        case SAA7134_BOARD_AVERMEDIA_M135A:
-               ir_codes     = ir_codes_avermedia_m135a;
+               ir_codes     = &ir_codes_avermedia_m135a_table;
                mask_keydown = 0x0040000;
                mask_keycode = 0x00013f;
                nec_gpio     = 1;
                break;
        case SAA7134_BOARD_AVERMEDIA_777:
        case SAA7134_BOARD_AVERMEDIA_A16AR:
-               ir_codes     = ir_codes_avermedia;
+               ir_codes     = &ir_codes_avermedia_table;
                mask_keycode = 0x02F200;
                mask_keydown = 0x000400;
                polling      = 50; // ms
@@ -476,7 +478,7 @@ int saa7134_input_init1(struct saa7134_dev *dev)
                saa_setb(SAA7134_GPIO_GPSTATUS1, 0x1);
                break;
        case SAA7134_BOARD_AVERMEDIA_A16D:
-               ir_codes     = ir_codes_avermedia_a16d;
+               ir_codes     = &ir_codes_avermedia_a16d_table;
                mask_keycode = 0x02F200;
                mask_keydown = 0x000400;
                polling      = 50; /* ms */
@@ -485,14 +487,14 @@ int saa7134_input_init1(struct saa7134_dev *dev)
                saa_setb(SAA7134_GPIO_GPSTATUS1, 0x1);
                break;
        case SAA7134_BOARD_KWORLD_TERMINATOR:
-               ir_codes     = ir_codes_pixelview;
+               ir_codes     = &ir_codes_pixelview_table;
                mask_keycode = 0x00001f;
                mask_keyup   = 0x000060;
                polling      = 50; // ms
                break;
        case SAA7134_BOARD_MANLI_MTV001:
        case SAA7134_BOARD_MANLI_MTV002:
-               ir_codes     = ir_codes_manli;
+               ir_codes     = &ir_codes_manli_table;
                mask_keycode = 0x001f00;
                mask_keyup   = 0x004000;
                polling      = 50; /* ms */
@@ -511,25 +513,25 @@ int saa7134_input_init1(struct saa7134_dev *dev)
        case SAA7134_BOARD_BEHOLD_507_9FM:
        case SAA7134_BOARD_BEHOLD_507RDS_MK3:
        case SAA7134_BOARD_BEHOLD_507RDS_MK5:
-               ir_codes     = ir_codes_manli;
+               ir_codes     = &ir_codes_manli_table;
                mask_keycode = 0x003f00;
                mask_keyup   = 0x004000;
                polling      = 50; /* ms */
                break;
        case SAA7134_BOARD_BEHOLD_COLUMBUS_TVFM:
-               ir_codes     = ir_codes_behold_columbus;
+               ir_codes     = &ir_codes_behold_columbus_table;
                mask_keycode = 0x003f00;
                mask_keyup   = 0x004000;
                polling      = 50; // ms
                break;
        case SAA7134_BOARD_SEDNA_PC_TV_CARDBUS:
-               ir_codes     = ir_codes_pctv_sedna;
+               ir_codes     = &ir_codes_pctv_sedna_table;
                mask_keycode = 0x001f00;
                mask_keyup   = 0x004000;
                polling      = 50; // ms
                break;
        case SAA7134_BOARD_GOTVIEW_7135:
-               ir_codes     = ir_codes_gotview7135;
+               ir_codes     = &ir_codes_gotview7135_table;
                mask_keycode = 0x0003CC;
                mask_keydown = 0x000010;
                polling      = 5; /* ms */
@@ -538,73 +540,78 @@ int saa7134_input_init1(struct saa7134_dev *dev)
        case SAA7134_BOARD_VIDEOMATE_TV_PVR:
        case SAA7134_BOARD_VIDEOMATE_GOLD_PLUS:
        case SAA7134_BOARD_VIDEOMATE_TV_GOLD_PLUSII:
-               ir_codes     = ir_codes_videomate_tv_pvr;
+               ir_codes     = &ir_codes_videomate_tv_pvr_table;
                mask_keycode = 0x00003F;
                mask_keyup   = 0x400000;
                polling      = 50; // ms
                break;
        case SAA7134_BOARD_PROTEUS_2309:
-               ir_codes     = ir_codes_proteus_2309;
+               ir_codes     = &ir_codes_proteus_2309_table;
                mask_keycode = 0x00007F;
                mask_keyup   = 0x000080;
                polling      = 50; // ms
                break;
        case SAA7134_BOARD_VIDEOMATE_DVBT_300:
        case SAA7134_BOARD_VIDEOMATE_DVBT_200:
-               ir_codes     = ir_codes_videomate_tv_pvr;
+               ir_codes     = &ir_codes_videomate_tv_pvr_table;
                mask_keycode = 0x003F00;
                mask_keyup   = 0x040000;
                break;
        case SAA7134_BOARD_FLYDVBS_LR300:
        case SAA7134_BOARD_FLYDVBT_LR301:
        case SAA7134_BOARD_FLYDVBTDUO:
-               ir_codes     = ir_codes_flydvb;
+               ir_codes     = &ir_codes_flydvb_table;
                mask_keycode = 0x0001F00;
                mask_keydown = 0x0040000;
                break;
        case SAA7134_BOARD_ASUSTeK_P7131_DUAL:
        case SAA7134_BOARD_ASUSTeK_P7131_HYBRID_LNA:
-       case SAA7134_BOARD_ASUSTeK_P7131_ANALOG:
-               ir_codes     = ir_codes_asus_pc39;
+       case SAA7134_BOARD_ASUSTeK_P7131_ANALOG:
+               ir_codes     = &ir_codes_asus_pc39_table;
                mask_keydown = 0x0040000;
                rc5_gpio = 1;
                break;
        case SAA7134_BOARD_ENCORE_ENLTV:
        case SAA7134_BOARD_ENCORE_ENLTV_FM:
-               ir_codes     = ir_codes_encore_enltv;
+               ir_codes     = &ir_codes_encore_enltv_table;
                mask_keycode = 0x00007f;
                mask_keyup   = 0x040000;
                polling      = 50; // ms
                break;
        case SAA7134_BOARD_ENCORE_ENLTV_FM53:
-               ir_codes     = ir_codes_encore_enltv_fm53;
+               ir_codes     = &ir_codes_encore_enltv_fm53_table;
                mask_keydown = 0x0040000;
                mask_keycode = 0x00007f;
                nec_gpio = 1;
                break;
        case SAA7134_BOARD_10MOONSTVMASTER3:
-               ir_codes     = ir_codes_encore_enltv;
+               ir_codes     = &ir_codes_encore_enltv_table;
                mask_keycode = 0x5f80000;
                mask_keyup   = 0x8000000;
                polling      = 50; //ms
                break;
        case SAA7134_BOARD_GENIUS_TVGO_A11MCE:
-               ir_codes     = ir_codes_genius_tvgo_a11mce;
+               ir_codes     = &ir_codes_genius_tvgo_a11mce_table;
                mask_keycode = 0xff;
                mask_keydown = 0xf00000;
                polling = 50; /* ms */
                break;
        case SAA7134_BOARD_REAL_ANGEL_220:
-               ir_codes     = ir_codes_real_audio_220_32_keys;
+               ir_codes     = &ir_codes_real_audio_220_32_keys_table;
                mask_keycode = 0x3f00;
                mask_keyup   = 0x4000;
                polling = 50; /* ms */
                break;
        case SAA7134_BOARD_KWORLD_PLUS_TV_ANALOG:
-               ir_codes     = ir_codes_kworld_plus_tv_analog;
+               ir_codes     = &ir_codes_kworld_plus_tv_analog_table;
                mask_keycode = 0x7f;
                polling = 40; /* ms */
                break;
+       case SAA7134_BOARD_VIDEOMATE_S350:
+               ir_codes     = &ir_codes_videomate_s350_table;
+               mask_keycode = 0x003f00;
+               mask_keydown = 0x040000;
+               break;
        }
        if (NULL == ir_codes) {
                printk("%s: Oops: IR config error [card=%d]\n",
@@ -684,8 +691,6 @@ void saa7134_input_fini(struct saa7134_dev *dev)
 
 void saa7134_probe_i2c_ir(struct saa7134_dev *dev)
 {
-       struct i2c_board_info info;
-       struct IR_i2c_init_data init_data;
        const unsigned short addr_list[] = {
                0x7a, 0x47, 0x71, 0x2d,
                I2C_CLIENT_END
@@ -705,32 +710,34 @@ void saa7134_probe_i2c_ir(struct saa7134_dev *dev)
                return;
        }
 
-       memset(&info, 0, sizeof(struct i2c_board_info));
-       memset(&init_data, 0, sizeof(struct IR_i2c_init_data));
-       strlcpy(info.type, "ir_video", I2C_NAME_SIZE);
+       memset(&dev->info, 0, sizeof(dev->info));
+       memset(&dev->init_data, 0, sizeof(dev->init_data));
+       strlcpy(dev->info.type, "ir_video", I2C_NAME_SIZE);
 
        switch (dev->board) {
        case SAA7134_BOARD_PINNACLE_PCTV_110i:
        case SAA7134_BOARD_PINNACLE_PCTV_310i:
-               init_data.name = "Pinnacle PCTV";
+               dev->init_data.name = "Pinnacle PCTV";
                if (pinnacle_remote == 0) {
-                       init_data.get_key = get_key_pinnacle_color;
-                       init_data.ir_codes = ir_codes_pinnacle_color;
+                       dev->init_data.get_key = get_key_pinnacle_color;
+                       dev->init_data.ir_codes = &ir_codes_pinnacle_color_table;
+                       dev->info.addr = 0x47;
                } else {
-                       init_data.get_key = get_key_pinnacle_grey;
-                       init_data.ir_codes = ir_codes_pinnacle_grey;
+                       dev->init_data.get_key = get_key_pinnacle_grey;
+                       dev->init_data.ir_codes = &ir_codes_pinnacle_grey_table;
+                       dev->info.addr = 0x47;
                }
                break;
        case SAA7134_BOARD_UPMOST_PURPLE_TV:
-               init_data.name = "Purple TV";
-               init_data.get_key = get_key_purpletv;
-               init_data.ir_codes = ir_codes_purpletv;
+               dev->init_data.name = "Purple TV";
+               dev->init_data.get_key = get_key_purpletv;
+               dev->init_data.ir_codes = &ir_codes_purpletv_table;
                break;
        case SAA7134_BOARD_MSI_TVATANYWHERE_PLUS:
-               init_data.name = "MSI TV@nywhere Plus";
-               init_data.get_key = get_key_msi_tvanywhere_plus;
-               init_data.ir_codes = ir_codes_msi_tvanywhere_plus;
-               info.addr = 0x30;
+               dev->init_data.name = "MSI TV@nywhere Plus";
+               dev->init_data.get_key = get_key_msi_tvanywhere_plus;
+               dev->init_data.ir_codes = &ir_codes_msi_tvanywhere_plus_table;
+               dev->info.addr = 0x30;
                /* MSI TV@nywhere Plus controller doesn't seem to
                   respond to probes unless we read something from
                   an existing device. Weird...
@@ -741,9 +748,9 @@ void saa7134_probe_i2c_ir(struct saa7134_dev *dev)
                        (1 == rc) ? "yes" : "no");
                break;
        case SAA7134_BOARD_HAUPPAUGE_HVR1110:
-               init_data.name = "HVR 1110";
-               init_data.get_key = get_key_hvr1110;
-               init_data.ir_codes = ir_codes_hauppauge_new;
+               dev->init_data.name = "HVR 1110";
+               dev->init_data.get_key = get_key_hvr1110;
+               dev->init_data.ir_codes = &ir_codes_hauppauge_new_table;
                break;
        case SAA7134_BOARD_BEHOLD_607FM_MK3:
        case SAA7134_BOARD_BEHOLD_607FM_MK5:
@@ -757,26 +764,27 @@ void saa7134_probe_i2c_ir(struct saa7134_dev *dev)
        case SAA7134_BOARD_BEHOLD_M63:
        case SAA7134_BOARD_BEHOLD_M6_EXTRA:
        case SAA7134_BOARD_BEHOLD_H6:
-               init_data.name = "BeholdTV";
-               init_data.get_key = get_key_beholdm6xx;
-               init_data.ir_codes = ir_codes_behold;
+       case SAA7134_BOARD_BEHOLD_X7:
+               dev->init_data.name = "BeholdTV";
+               dev->init_data.get_key = get_key_beholdm6xx;
+               dev->init_data.ir_codes = &ir_codes_behold_table;
                break;
        case SAA7134_BOARD_AVERMEDIA_CARDBUS_501:
        case SAA7134_BOARD_AVERMEDIA_CARDBUS_506:
-               info.addr = 0x40;
+               dev->info.addr = 0x40;
                break;
        }
 
-       if (init_data.name)
-               info.platform_data = &init_data;
+       if (dev->init_data.name)
+               dev->info.platform_data = &dev->init_data;
        /* No need to probe if address is known */
-       if (info.addr) {
-               i2c_new_device(&dev->i2c_adap, &info);
+       if (dev->info.addr) {
+               i2c_new_device(&dev->i2c_adap, &dev->info);
                return;
        }
 
        /* Address not known, fallback to probing */
-       i2c_new_probed_device(&dev->i2c_adap, &info, addr_list);
+       i2c_new_probed_device(&dev->i2c_adap, &dev->info, addr_list);
 }
 
 static int saa7134_rc5_irq(struct saa7134_dev *dev)
index ba87128542e03254aa27e5ab3f55dbcca869cffa..da26f476a302f9282e37213e59ff5885e1ee2a28 100644 (file)
@@ -1444,7 +1444,6 @@ video_poll(struct file *file, struct poll_table_struct *wait)
                        fh->cap.ops->buf_queue(&fh->cap,fh->cap.read_buf);
                        fh->cap.read_off = 0;
                }
-               mutex_unlock(&fh->cap.vb_lock);
                buf = fh->cap.read_buf;
        }
 
@@ -1790,7 +1789,7 @@ static int saa7134_s_input(struct file *file, void *priv, unsigned int i)
        if (0 != err)
                return err;
 
-       if (i < 0  ||  i >= SAA7134_INPUT_MAX)
+       if (i >= SAA7134_INPUT_MAX)
                return -EINVAL;
        if (NULL == card_in(dev, i).name)
                return -EINVAL;
@@ -1819,6 +1818,8 @@ static int saa7134_querycap(struct file *file, void  *priv,
                V4L2_CAP_READWRITE |
                V4L2_CAP_STREAMING |
                V4L2_CAP_TUNER;
+       if (dev->has_rds)
+               cap->capabilities |= V4L2_CAP_RDS_CAPTURE;
        if (saa7134_no_overlay <= 0)
                cap->capabilities |= V4L2_CAP_VIDEO_OVERLAY;
 
index fb564f14887cc0e814f0adcb29a738595cea937c..d18bb96438561c6c8cc0bf73a7ddf7a57c4906f1 100644 (file)
@@ -292,6 +292,10 @@ struct saa7134_format {
 #define SAA7134_BOARD_BEHOLD_607RDS_MK5     166
 #define SAA7134_BOARD_BEHOLD_609RDS_MK3     167
 #define SAA7134_BOARD_BEHOLD_609RDS_MK5     168
+#define SAA7134_BOARD_VIDEOMATE_S350        169
+#define SAA7134_BOARD_AVERMEDIA_STUDIO_505  170
+#define SAA7134_BOARD_BEHOLD_X7             171
+#define SAA7134_BOARD_ROVERMEDIA_LINK_PRO_FM 172
 
 #define SAA7134_MAXBOARDS 32
 #define SAA7134_INPUT_MAX 8
@@ -539,6 +543,7 @@ struct saa7134_dev {
        struct i2c_adapter         i2c_adap;
        struct i2c_client          i2c_client;
        unsigned char              eedata[256];
+       int                        has_rds;
 
        /* video overlay */
        struct v4l2_framebuffer    ovbuf;
@@ -584,6 +589,10 @@ struct saa7134_dev {
        int                        nosignal;
        unsigned int               insuspend;
 
+       /* I2C keyboard data */
+       struct i2c_board_info      info;
+       struct IR_i2c_init_data    init_data;
+
        /* SAA7134_MPEG_* */
        struct saa7134_ts          ts;
        struct saa7134_dmaqueue    ts_q;
index 38a716020d7f46daa6dace7cebce7a60811580d3..36ee43a9ee95a4b400383183ac2ac1159ed1e933 100644 (file)
@@ -123,8 +123,8 @@ static const struct usb_device_id sn9c102_id_table[] = {
        { SN9C102_USB_DEVICE(0x0c45, 0x613b, BRIDGE_SN9C120), },
 #if !defined CONFIG_USB_GSPCA && !defined CONFIG_USB_GSPCA_MODULE
        { SN9C102_USB_DEVICE(0x0c45, 0x613c, BRIDGE_SN9C120), },
-#endif
        { SN9C102_USB_DEVICE(0x0c45, 0x613e, BRIDGE_SN9C120), },
+#endif
        { }
 };
 
index b154bd961e3b74472d7efccf367c8447004d0f84..0b996ea4134eeac750bb14cb21d068f7c72d0b14 100644 (file)
@@ -1400,7 +1400,6 @@ static int stk_camera_probe(struct usb_interface *interface,
        }
 
        stk_create_sysfs_files(&dev->vdev);
-       usb_autopm_enable(dev->interface);
 
        return 0;
 
index 8b4e7dafce7b9d155c254a802282daa0f25f1570..6a91714125d27dd2fc054a9f953656f24a9cc4ab 100644 (file)
@@ -734,10 +734,6 @@ static int stv680_start_stream (struct usb_stv *stv680)
        return 0;
 
  nomem_err:
-       for (i = 0; i < STV680_NUMSCRATCH; i++) {
-               kfree(stv680->scratch[i].data);
-               stv680->scratch[i].data = NULL;
-       }
        for (i = 0; i < STV680_NUMSBUF; i++) {
                usb_kill_urb(stv680->urb[i]);
                usb_free_urb(stv680->urb[i]);
@@ -745,6 +741,11 @@ static int stv680_start_stream (struct usb_stv *stv680)
                kfree(stv680->sbuf[i].data);
                stv680->sbuf[i].data = NULL;
        }
+       /* used in irq, free only as all URBs are dead */
+       for (i = 0; i < STV680_NUMSCRATCH; i++) {
+               kfree(stv680->scratch[i].data);
+               stv680->scratch[i].data = NULL;
+       }
        return -ENOMEM;
 
 }
index 537594211a90e1ccb6fa49b74e188b642ae0c6ae..2816f1839230c1131aef1298d5e5b3157dc75ae9 100644 (file)
@@ -819,8 +819,8 @@ static int tuner_g_frequency(struct v4l2_subdev *sd, struct v4l2_frequency *f)
 
                fe_tuner_ops->get_frequency(&t->fe, &abs_freq);
                f->frequency = (V4L2_TUNER_RADIO == t->mode) ?
-                       (abs_freq * 2 + 125/2) / 125 :
-                       (abs_freq + 62500/2) / 62500;
+                       DIV_ROUND_CLOSEST(abs_freq * 2, 125) :
+                       DIV_ROUND_CLOSEST(abs_freq, 62500);
                return 0;
        }
        f->frequency = (V4L2_TUNER_RADIO == t->mode) ?
index ac02808106c145120fbb49c72eecc85d5a54ac9c..d533ea57e7b10e89529bfa2029fb58056a1791b4 100644 (file)
@@ -646,14 +646,14 @@ void tveeprom_hauppauge_analog(struct i2c_client *c, struct tveeprom *tvee,
                tvee->has_radio = 1;
        }
 
-       if (tuner1 < sizeof(hauppauge_tuner)/sizeof(struct HAUPPAUGE_TUNER)) {
+       if (tuner1 < ARRAY_SIZE(hauppauge_tuner)) {
                tvee->tuner_type = hauppauge_tuner[tuner1].id;
                t_name1 = hauppauge_tuner[tuner1].name;
        } else {
                t_name1 = "unknown";
        }
 
-       if (tuner2 < sizeof(hauppauge_tuner)/sizeof(struct HAUPPAUGE_TUNER)) {
+       if (tuner2 < ARRAY_SIZE(hauppauge_tuner)) {
                tvee->tuner2_type = hauppauge_tuner[tuner2].id;
                t_name2 = hauppauge_tuner[tuner2].name;
        } else {
index 36a6ba92df2700710746db302c152dc61ea14842..c3225a561748bec3794af79d354cf2ede22a852b 100644 (file)
@@ -34,7 +34,7 @@
 static struct uvc_control_info uvc_ctrls[] = {
        {
                .entity         = UVC_GUID_UVC_PROCESSING,
-               .selector       = PU_BRIGHTNESS_CONTROL,
+               .selector       = UVC_PU_BRIGHTNESS_CONTROL,
                .index          = 0,
                .size           = 2,
                .flags          = UVC_CONTROL_SET_CUR | UVC_CONTROL_GET_RANGE
@@ -42,7 +42,7 @@ static struct uvc_control_info uvc_ctrls[] = {
        },
        {
                .entity         = UVC_GUID_UVC_PROCESSING,
-               .selector       = PU_CONTRAST_CONTROL,
+               .selector       = UVC_PU_CONTRAST_CONTROL,
                .index          = 1,
                .size           = 2,
                .flags          = UVC_CONTROL_SET_CUR | UVC_CONTROL_GET_RANGE
@@ -50,7 +50,7 @@ static struct uvc_control_info uvc_ctrls[] = {
        },
        {
                .entity         = UVC_GUID_UVC_PROCESSING,
-               .selector       = PU_HUE_CONTROL,
+               .selector       = UVC_PU_HUE_CONTROL,
                .index          = 2,
                .size           = 2,
                .flags          = UVC_CONTROL_SET_CUR | UVC_CONTROL_GET_RANGE
@@ -58,7 +58,7 @@ static struct uvc_control_info uvc_ctrls[] = {
        },
        {
                .entity         = UVC_GUID_UVC_PROCESSING,
-               .selector       = PU_SATURATION_CONTROL,
+               .selector       = UVC_PU_SATURATION_CONTROL,
                .index          = 3,
                .size           = 2,
                .flags          = UVC_CONTROL_SET_CUR | UVC_CONTROL_GET_RANGE
@@ -66,7 +66,7 @@ static struct uvc_control_info uvc_ctrls[] = {
        },
        {
                .entity         = UVC_GUID_UVC_PROCESSING,
-               .selector       = PU_SHARPNESS_CONTROL,
+               .selector       = UVC_PU_SHARPNESS_CONTROL,
                .index          = 4,
                .size           = 2,
                .flags          = UVC_CONTROL_SET_CUR | UVC_CONTROL_GET_RANGE
@@ -74,7 +74,7 @@ static struct uvc_control_info uvc_ctrls[] = {
        },
        {
                .entity         = UVC_GUID_UVC_PROCESSING,
-               .selector       = PU_GAMMA_CONTROL,
+               .selector       = UVC_PU_GAMMA_CONTROL,
                .index          = 5,
                .size           = 2,
                .flags          = UVC_CONTROL_SET_CUR | UVC_CONTROL_GET_RANGE
@@ -82,7 +82,7 @@ static struct uvc_control_info uvc_ctrls[] = {
        },
        {
                .entity         = UVC_GUID_UVC_PROCESSING,
-               .selector       = PU_WHITE_BALANCE_TEMPERATURE_CONTROL,
+               .selector       = UVC_PU_WHITE_BALANCE_TEMPERATURE_CONTROL,
                .index          = 6,
                .size           = 2,
                .flags          = UVC_CONTROL_SET_CUR | UVC_CONTROL_GET_RANGE
@@ -90,7 +90,7 @@ static struct uvc_control_info uvc_ctrls[] = {
        },
        {
                .entity         = UVC_GUID_UVC_PROCESSING,
-               .selector       = PU_WHITE_BALANCE_COMPONENT_CONTROL,
+               .selector       = UVC_PU_WHITE_BALANCE_COMPONENT_CONTROL,
                .index          = 7,
                .size           = 4,
                .flags          = UVC_CONTROL_SET_CUR | UVC_CONTROL_GET_RANGE
@@ -98,7 +98,7 @@ static struct uvc_control_info uvc_ctrls[] = {
        },
        {
                .entity         = UVC_GUID_UVC_PROCESSING,
-               .selector       = PU_BACKLIGHT_COMPENSATION_CONTROL,
+               .selector       = UVC_PU_BACKLIGHT_COMPENSATION_CONTROL,
                .index          = 8,
                .size           = 2,
                .flags          = UVC_CONTROL_SET_CUR | UVC_CONTROL_GET_RANGE
@@ -106,7 +106,7 @@ static struct uvc_control_info uvc_ctrls[] = {
        },
        {
                .entity         = UVC_GUID_UVC_PROCESSING,
-               .selector       = PU_GAIN_CONTROL,
+               .selector       = UVC_PU_GAIN_CONTROL,
                .index          = 9,
                .size           = 2,
                .flags          = UVC_CONTROL_SET_CUR | UVC_CONTROL_GET_RANGE
@@ -114,7 +114,7 @@ static struct uvc_control_info uvc_ctrls[] = {
        },
        {
                .entity         = UVC_GUID_UVC_PROCESSING,
-               .selector       = PU_POWER_LINE_FREQUENCY_CONTROL,
+               .selector       = UVC_PU_POWER_LINE_FREQUENCY_CONTROL,
                .index          = 10,
                .size           = 1,
                .flags          = UVC_CONTROL_SET_CUR | UVC_CONTROL_GET_RANGE
@@ -122,7 +122,7 @@ static struct uvc_control_info uvc_ctrls[] = {
        },
        {
                .entity         = UVC_GUID_UVC_PROCESSING,
-               .selector       = PU_HUE_AUTO_CONTROL,
+               .selector       = UVC_PU_HUE_AUTO_CONTROL,
                .index          = 11,
                .size           = 1,
                .flags          = UVC_CONTROL_SET_CUR | UVC_CONTROL_GET_CUR
@@ -130,7 +130,7 @@ static struct uvc_control_info uvc_ctrls[] = {
        },
        {
                .entity         = UVC_GUID_UVC_PROCESSING,
-               .selector       = PU_WHITE_BALANCE_TEMPERATURE_AUTO_CONTROL,
+               .selector       = UVC_PU_WHITE_BALANCE_TEMPERATURE_AUTO_CONTROL,
                .index          = 12,
                .size           = 1,
                .flags          = UVC_CONTROL_SET_CUR | UVC_CONTROL_GET_CUR
@@ -138,7 +138,7 @@ static struct uvc_control_info uvc_ctrls[] = {
        },
        {
                .entity         = UVC_GUID_UVC_PROCESSING,
-               .selector       = PU_WHITE_BALANCE_COMPONENT_AUTO_CONTROL,
+               .selector       = UVC_PU_WHITE_BALANCE_COMPONENT_AUTO_CONTROL,
                .index          = 13,
                .size           = 1,
                .flags          = UVC_CONTROL_SET_CUR | UVC_CONTROL_GET_CUR
@@ -146,7 +146,7 @@ static struct uvc_control_info uvc_ctrls[] = {
        },
        {
                .entity         = UVC_GUID_UVC_PROCESSING,
-               .selector       = PU_DIGITAL_MULTIPLIER_CONTROL,
+               .selector       = UVC_PU_DIGITAL_MULTIPLIER_CONTROL,
                .index          = 14,
                .size           = 2,
                .flags          = UVC_CONTROL_SET_CUR | UVC_CONTROL_GET_RANGE
@@ -154,7 +154,7 @@ static struct uvc_control_info uvc_ctrls[] = {
        },
        {
                .entity         = UVC_GUID_UVC_PROCESSING,
-               .selector       = PU_DIGITAL_MULTIPLIER_LIMIT_CONTROL,
+               .selector       = UVC_PU_DIGITAL_MULTIPLIER_LIMIT_CONTROL,
                .index          = 15,
                .size           = 2,
                .flags          = UVC_CONTROL_SET_CUR | UVC_CONTROL_GET_RANGE
@@ -162,21 +162,21 @@ static struct uvc_control_info uvc_ctrls[] = {
        },
        {
                .entity         = UVC_GUID_UVC_PROCESSING,
-               .selector       = PU_ANALOG_VIDEO_STANDARD_CONTROL,
+               .selector       = UVC_PU_ANALOG_VIDEO_STANDARD_CONTROL,
                .index          = 16,
                .size           = 1,
                .flags          = UVC_CONTROL_GET_CUR,
        },
        {
                .entity         = UVC_GUID_UVC_PROCESSING,
-               .selector       = PU_ANALOG_LOCK_STATUS_CONTROL,
+               .selector       = UVC_PU_ANALOG_LOCK_STATUS_CONTROL,
                .index          = 17,
                .size           = 1,
                .flags          = UVC_CONTROL_GET_CUR,
        },
        {
                .entity         = UVC_GUID_UVC_CAMERA,
-               .selector       = CT_SCANNING_MODE_CONTROL,
+               .selector       = UVC_CT_SCANNING_MODE_CONTROL,
                .index          = 0,
                .size           = 1,
                .flags          = UVC_CONTROL_SET_CUR | UVC_CONTROL_GET_CUR
@@ -184,7 +184,7 @@ static struct uvc_control_info uvc_ctrls[] = {
        },
        {
                .entity         = UVC_GUID_UVC_CAMERA,
-               .selector       = CT_AE_MODE_CONTROL,
+               .selector       = UVC_CT_AE_MODE_CONTROL,
                .index          = 1,
                .size           = 1,
                .flags          = UVC_CONTROL_SET_CUR | UVC_CONTROL_GET_CUR
@@ -193,7 +193,7 @@ static struct uvc_control_info uvc_ctrls[] = {
        },
        {
                .entity         = UVC_GUID_UVC_CAMERA,
-               .selector       = CT_AE_PRIORITY_CONTROL,
+               .selector       = UVC_CT_AE_PRIORITY_CONTROL,
                .index          = 2,
                .size           = 1,
                .flags          = UVC_CONTROL_SET_CUR | UVC_CONTROL_GET_CUR
@@ -201,7 +201,7 @@ static struct uvc_control_info uvc_ctrls[] = {
        },
        {
                .entity         = UVC_GUID_UVC_CAMERA,
-               .selector       = CT_EXPOSURE_TIME_ABSOLUTE_CONTROL,
+               .selector       = UVC_CT_EXPOSURE_TIME_ABSOLUTE_CONTROL,
                .index          = 3,
                .size           = 4,
                .flags          = UVC_CONTROL_SET_CUR | UVC_CONTROL_GET_RANGE
@@ -209,7 +209,7 @@ static struct uvc_control_info uvc_ctrls[] = {
        },
        {
                .entity         = UVC_GUID_UVC_CAMERA,
-               .selector       = CT_EXPOSURE_TIME_RELATIVE_CONTROL,
+               .selector       = UVC_CT_EXPOSURE_TIME_RELATIVE_CONTROL,
                .index          = 4,
                .size           = 1,
                .flags          = UVC_CONTROL_SET_CUR | UVC_CONTROL_GET_CUR
@@ -217,7 +217,7 @@ static struct uvc_control_info uvc_ctrls[] = {
        },
        {
                .entity         = UVC_GUID_UVC_CAMERA,
-               .selector       = CT_FOCUS_ABSOLUTE_CONTROL,
+               .selector       = UVC_CT_FOCUS_ABSOLUTE_CONTROL,
                .index          = 5,
                .size           = 2,
                .flags          = UVC_CONTROL_SET_CUR | UVC_CONTROL_GET_RANGE
@@ -225,7 +225,7 @@ static struct uvc_control_info uvc_ctrls[] = {
        },
        {
                .entity         = UVC_GUID_UVC_CAMERA,
-               .selector       = CT_FOCUS_RELATIVE_CONTROL,
+               .selector       = UVC_CT_FOCUS_RELATIVE_CONTROL,
                .index          = 6,
                .size           = 2,
                .flags          = UVC_CONTROL_SET_CUR | UVC_CONTROL_GET_RANGE
@@ -233,7 +233,7 @@ static struct uvc_control_info uvc_ctrls[] = {
        },
        {
                .entity         = UVC_GUID_UVC_CAMERA,
-               .selector       = CT_IRIS_ABSOLUTE_CONTROL,
+               .selector       = UVC_CT_IRIS_ABSOLUTE_CONTROL,
                .index          = 7,
                .size           = 2,
                .flags          = UVC_CONTROL_SET_CUR | UVC_CONTROL_GET_RANGE
@@ -241,7 +241,7 @@ static struct uvc_control_info uvc_ctrls[] = {
        },
        {
                .entity         = UVC_GUID_UVC_CAMERA,
-               .selector       = CT_IRIS_RELATIVE_CONTROL,
+               .selector       = UVC_CT_IRIS_RELATIVE_CONTROL,
                .index          = 8,
                .size           = 1,
                .flags          = UVC_CONTROL_SET_CUR | UVC_CONTROL_GET_CUR
@@ -249,7 +249,7 @@ static struct uvc_control_info uvc_ctrls[] = {
        },
        {
                .entity         = UVC_GUID_UVC_CAMERA,
-               .selector       = CT_ZOOM_ABSOLUTE_CONTROL,
+               .selector       = UVC_CT_ZOOM_ABSOLUTE_CONTROL,
                .index          = 9,
                .size           = 2,
                .flags          = UVC_CONTROL_SET_CUR | UVC_CONTROL_GET_RANGE
@@ -257,7 +257,7 @@ static struct uvc_control_info uvc_ctrls[] = {
        },
        {
                .entity         = UVC_GUID_UVC_CAMERA,
-               .selector       = CT_ZOOM_RELATIVE_CONTROL,
+               .selector       = UVC_CT_ZOOM_RELATIVE_CONTROL,
                .index          = 10,
                .size           = 3,
                .flags          = UVC_CONTROL_SET_CUR | UVC_CONTROL_GET_RANGE
@@ -265,7 +265,7 @@ static struct uvc_control_info uvc_ctrls[] = {
        },
        {
                .entity         = UVC_GUID_UVC_CAMERA,
-               .selector       = CT_PANTILT_ABSOLUTE_CONTROL,
+               .selector       = UVC_CT_PANTILT_ABSOLUTE_CONTROL,
                .index          = 11,
                .size           = 8,
                .flags          = UVC_CONTROL_SET_CUR | UVC_CONTROL_GET_RANGE
@@ -273,7 +273,7 @@ static struct uvc_control_info uvc_ctrls[] = {
        },
        {
                .entity         = UVC_GUID_UVC_CAMERA,
-               .selector       = CT_PANTILT_RELATIVE_CONTROL,
+               .selector       = UVC_CT_PANTILT_RELATIVE_CONTROL,
                .index          = 12,
                .size           = 4,
                .flags          = UVC_CONTROL_SET_CUR | UVC_CONTROL_GET_RANGE
@@ -281,7 +281,7 @@ static struct uvc_control_info uvc_ctrls[] = {
        },
        {
                .entity         = UVC_GUID_UVC_CAMERA,
-               .selector       = CT_ROLL_ABSOLUTE_CONTROL,
+               .selector       = UVC_CT_ROLL_ABSOLUTE_CONTROL,
                .index          = 13,
                .size           = 2,
                .flags          = UVC_CONTROL_SET_CUR | UVC_CONTROL_GET_RANGE
@@ -289,7 +289,7 @@ static struct uvc_control_info uvc_ctrls[] = {
        },
        {
                .entity         = UVC_GUID_UVC_CAMERA,
-               .selector       = CT_ROLL_RELATIVE_CONTROL,
+               .selector       = UVC_CT_ROLL_RELATIVE_CONTROL,
                .index          = 14,
                .size           = 2,
                .flags          = UVC_CONTROL_SET_CUR | UVC_CONTROL_GET_RANGE
@@ -297,7 +297,7 @@ static struct uvc_control_info uvc_ctrls[] = {
        },
        {
                .entity         = UVC_GUID_UVC_CAMERA,
-               .selector       = CT_FOCUS_AUTO_CONTROL,
+               .selector       = UVC_CT_FOCUS_AUTO_CONTROL,
                .index          = 17,
                .size           = 1,
                .flags          = UVC_CONTROL_SET_CUR | UVC_CONTROL_GET_CUR
@@ -305,7 +305,7 @@ static struct uvc_control_info uvc_ctrls[] = {
        },
        {
                .entity         = UVC_GUID_UVC_CAMERA,
-               .selector       = CT_PRIVACY_CONTROL,
+               .selector       = UVC_CT_PRIVACY_CONTROL,
                .index          = 18,
                .size           = 1,
                .flags          = UVC_CONTROL_SET_CUR | UVC_CONTROL_GET_CUR
@@ -332,13 +332,13 @@ static __s32 uvc_ctrl_get_zoom(struct uvc_control_mapping *mapping,
        __s8 zoom = (__s8)data[0];
 
        switch (query) {
-       case GET_CUR:
+       case UVC_GET_CUR:
                return (zoom == 0) ? 0 : (zoom > 0 ? data[2] : -data[2]);
 
-       case GET_MIN:
-       case GET_MAX:
-       case GET_RES:
-       case GET_DEF:
+       case UVC_GET_MIN:
+       case UVC_GET_MAX:
+       case UVC_GET_RES:
+       case UVC_GET_DEF:
        default:
                return data[2];
        }
@@ -356,7 +356,7 @@ static struct uvc_control_mapping uvc_ctrl_mappings[] = {
                .id             = V4L2_CID_BRIGHTNESS,
                .name           = "Brightness",
                .entity         = UVC_GUID_UVC_PROCESSING,
-               .selector       = PU_BRIGHTNESS_CONTROL,
+               .selector       = UVC_PU_BRIGHTNESS_CONTROL,
                .size           = 16,
                .offset         = 0,
                .v4l2_type      = V4L2_CTRL_TYPE_INTEGER,
@@ -366,7 +366,7 @@ static struct uvc_control_mapping uvc_ctrl_mappings[] = {
                .id             = V4L2_CID_CONTRAST,
                .name           = "Contrast",
                .entity         = UVC_GUID_UVC_PROCESSING,
-               .selector       = PU_CONTRAST_CONTROL,
+               .selector       = UVC_PU_CONTRAST_CONTROL,
                .size           = 16,
                .offset         = 0,
                .v4l2_type      = V4L2_CTRL_TYPE_INTEGER,
@@ -376,7 +376,7 @@ static struct uvc_control_mapping uvc_ctrl_mappings[] = {
                .id             = V4L2_CID_HUE,
                .name           = "Hue",
                .entity         = UVC_GUID_UVC_PROCESSING,
-               .selector       = PU_HUE_CONTROL,
+               .selector       = UVC_PU_HUE_CONTROL,
                .size           = 16,
                .offset         = 0,
                .v4l2_type      = V4L2_CTRL_TYPE_INTEGER,
@@ -386,7 +386,7 @@ static struct uvc_control_mapping uvc_ctrl_mappings[] = {
                .id             = V4L2_CID_SATURATION,
                .name           = "Saturation",
                .entity         = UVC_GUID_UVC_PROCESSING,
-               .selector       = PU_SATURATION_CONTROL,
+               .selector       = UVC_PU_SATURATION_CONTROL,
                .size           = 16,
                .offset         = 0,
                .v4l2_type      = V4L2_CTRL_TYPE_INTEGER,
@@ -396,7 +396,7 @@ static struct uvc_control_mapping uvc_ctrl_mappings[] = {
                .id             = V4L2_CID_SHARPNESS,
                .name           = "Sharpness",
                .entity         = UVC_GUID_UVC_PROCESSING,
-               .selector       = PU_SHARPNESS_CONTROL,
+               .selector       = UVC_PU_SHARPNESS_CONTROL,
                .size           = 16,
                .offset         = 0,
                .v4l2_type      = V4L2_CTRL_TYPE_INTEGER,
@@ -406,7 +406,7 @@ static struct uvc_control_mapping uvc_ctrl_mappings[] = {
                .id             = V4L2_CID_GAMMA,
                .name           = "Gamma",
                .entity         = UVC_GUID_UVC_PROCESSING,
-               .selector       = PU_GAMMA_CONTROL,
+               .selector       = UVC_PU_GAMMA_CONTROL,
                .size           = 16,
                .offset         = 0,
                .v4l2_type      = V4L2_CTRL_TYPE_INTEGER,
@@ -416,7 +416,7 @@ static struct uvc_control_mapping uvc_ctrl_mappings[] = {
                .id             = V4L2_CID_BACKLIGHT_COMPENSATION,
                .name           = "Backlight Compensation",
                .entity         = UVC_GUID_UVC_PROCESSING,
-               .selector       = PU_BACKLIGHT_COMPENSATION_CONTROL,
+               .selector       = UVC_PU_BACKLIGHT_COMPENSATION_CONTROL,
                .size           = 16,
                .offset         = 0,
                .v4l2_type      = V4L2_CTRL_TYPE_INTEGER,
@@ -426,7 +426,7 @@ static struct uvc_control_mapping uvc_ctrl_mappings[] = {
                .id             = V4L2_CID_GAIN,
                .name           = "Gain",
                .entity         = UVC_GUID_UVC_PROCESSING,
-               .selector       = PU_GAIN_CONTROL,
+               .selector       = UVC_PU_GAIN_CONTROL,
                .size           = 16,
                .offset         = 0,
                .v4l2_type      = V4L2_CTRL_TYPE_INTEGER,
@@ -436,7 +436,7 @@ static struct uvc_control_mapping uvc_ctrl_mappings[] = {
                .id             = V4L2_CID_POWER_LINE_FREQUENCY,
                .name           = "Power Line Frequency",
                .entity         = UVC_GUID_UVC_PROCESSING,
-               .selector       = PU_POWER_LINE_FREQUENCY_CONTROL,
+               .selector       = UVC_PU_POWER_LINE_FREQUENCY_CONTROL,
                .size           = 2,
                .offset         = 0,
                .v4l2_type      = V4L2_CTRL_TYPE_MENU,
@@ -448,7 +448,7 @@ static struct uvc_control_mapping uvc_ctrl_mappings[] = {
                .id             = V4L2_CID_HUE_AUTO,
                .name           = "Hue, Auto",
                .entity         = UVC_GUID_UVC_PROCESSING,
-               .selector       = PU_HUE_AUTO_CONTROL,
+               .selector       = UVC_PU_HUE_AUTO_CONTROL,
                .size           = 1,
                .offset         = 0,
                .v4l2_type      = V4L2_CTRL_TYPE_BOOLEAN,
@@ -458,7 +458,7 @@ static struct uvc_control_mapping uvc_ctrl_mappings[] = {
                .id             = V4L2_CID_EXPOSURE_AUTO,
                .name           = "Exposure, Auto",
                .entity         = UVC_GUID_UVC_CAMERA,
-               .selector       = CT_AE_MODE_CONTROL,
+               .selector       = UVC_CT_AE_MODE_CONTROL,
                .size           = 4,
                .offset         = 0,
                .v4l2_type      = V4L2_CTRL_TYPE_MENU,
@@ -470,7 +470,7 @@ static struct uvc_control_mapping uvc_ctrl_mappings[] = {
                .id             = V4L2_CID_EXPOSURE_AUTO_PRIORITY,
                .name           = "Exposure, Auto Priority",
                .entity         = UVC_GUID_UVC_CAMERA,
-               .selector       = CT_AE_PRIORITY_CONTROL,
+               .selector       = UVC_CT_AE_PRIORITY_CONTROL,
                .size           = 1,
                .offset         = 0,
                .v4l2_type      = V4L2_CTRL_TYPE_BOOLEAN,
@@ -480,7 +480,7 @@ static struct uvc_control_mapping uvc_ctrl_mappings[] = {
                .id             = V4L2_CID_EXPOSURE_ABSOLUTE,
                .name           = "Exposure (Absolute)",
                .entity         = UVC_GUID_UVC_CAMERA,
-               .selector       = CT_EXPOSURE_TIME_ABSOLUTE_CONTROL,
+               .selector       = UVC_CT_EXPOSURE_TIME_ABSOLUTE_CONTROL,
                .size           = 32,
                .offset         = 0,
                .v4l2_type      = V4L2_CTRL_TYPE_INTEGER,
@@ -490,7 +490,7 @@ static struct uvc_control_mapping uvc_ctrl_mappings[] = {
                .id             = V4L2_CID_AUTO_WHITE_BALANCE,
                .name           = "White Balance Temperature, Auto",
                .entity         = UVC_GUID_UVC_PROCESSING,
-               .selector       = PU_WHITE_BALANCE_TEMPERATURE_AUTO_CONTROL,
+               .selector       = UVC_PU_WHITE_BALANCE_TEMPERATURE_AUTO_CONTROL,
                .size           = 1,
                .offset         = 0,
                .v4l2_type      = V4L2_CTRL_TYPE_BOOLEAN,
@@ -500,7 +500,7 @@ static struct uvc_control_mapping uvc_ctrl_mappings[] = {
                .id             = V4L2_CID_WHITE_BALANCE_TEMPERATURE,
                .name           = "White Balance Temperature",
                .entity         = UVC_GUID_UVC_PROCESSING,
-               .selector       = PU_WHITE_BALANCE_TEMPERATURE_CONTROL,
+               .selector       = UVC_PU_WHITE_BALANCE_TEMPERATURE_CONTROL,
                .size           = 16,
                .offset         = 0,
                .v4l2_type      = V4L2_CTRL_TYPE_INTEGER,
@@ -510,7 +510,7 @@ static struct uvc_control_mapping uvc_ctrl_mappings[] = {
                .id             = V4L2_CID_AUTO_WHITE_BALANCE,
                .name           = "White Balance Component, Auto",
                .entity         = UVC_GUID_UVC_PROCESSING,
-               .selector       = PU_WHITE_BALANCE_COMPONENT_AUTO_CONTROL,
+               .selector       = UVC_PU_WHITE_BALANCE_COMPONENT_AUTO_CONTROL,
                .size           = 1,
                .offset         = 0,
                .v4l2_type      = V4L2_CTRL_TYPE_BOOLEAN,
@@ -520,7 +520,7 @@ static struct uvc_control_mapping uvc_ctrl_mappings[] = {
                .id             = V4L2_CID_BLUE_BALANCE,
                .name           = "White Balance Blue Component",
                .entity         = UVC_GUID_UVC_PROCESSING,
-               .selector       = PU_WHITE_BALANCE_COMPONENT_CONTROL,
+               .selector       = UVC_PU_WHITE_BALANCE_COMPONENT_CONTROL,
                .size           = 16,
                .offset         = 0,
                .v4l2_type      = V4L2_CTRL_TYPE_INTEGER,
@@ -530,7 +530,7 @@ static struct uvc_control_mapping uvc_ctrl_mappings[] = {
                .id             = V4L2_CID_RED_BALANCE,
                .name           = "White Balance Red Component",
                .entity         = UVC_GUID_UVC_PROCESSING,
-               .selector       = PU_WHITE_BALANCE_COMPONENT_CONTROL,
+               .selector       = UVC_PU_WHITE_BALANCE_COMPONENT_CONTROL,
                .size           = 16,
                .offset         = 16,
                .v4l2_type      = V4L2_CTRL_TYPE_INTEGER,
@@ -540,7 +540,7 @@ static struct uvc_control_mapping uvc_ctrl_mappings[] = {
                .id             = V4L2_CID_FOCUS_ABSOLUTE,
                .name           = "Focus (absolute)",
                .entity         = UVC_GUID_UVC_CAMERA,
-               .selector       = CT_FOCUS_ABSOLUTE_CONTROL,
+               .selector       = UVC_CT_FOCUS_ABSOLUTE_CONTROL,
                .size           = 16,
                .offset         = 0,
                .v4l2_type      = V4L2_CTRL_TYPE_INTEGER,
@@ -550,7 +550,7 @@ static struct uvc_control_mapping uvc_ctrl_mappings[] = {
                .id             = V4L2_CID_FOCUS_AUTO,
                .name           = "Focus, Auto",
                .entity         = UVC_GUID_UVC_CAMERA,
-               .selector       = CT_FOCUS_AUTO_CONTROL,
+               .selector       = UVC_CT_FOCUS_AUTO_CONTROL,
                .size           = 1,
                .offset         = 0,
                .v4l2_type      = V4L2_CTRL_TYPE_BOOLEAN,
@@ -560,7 +560,7 @@ static struct uvc_control_mapping uvc_ctrl_mappings[] = {
                .id             = V4L2_CID_ZOOM_ABSOLUTE,
                .name           = "Zoom, Absolute",
                .entity         = UVC_GUID_UVC_CAMERA,
-               .selector       = CT_ZOOM_ABSOLUTE_CONTROL,
+               .selector       = UVC_CT_ZOOM_ABSOLUTE_CONTROL,
                .size           = 16,
                .offset         = 0,
                .v4l2_type      = V4L2_CTRL_TYPE_INTEGER,
@@ -570,7 +570,7 @@ static struct uvc_control_mapping uvc_ctrl_mappings[] = {
                .id             = V4L2_CID_ZOOM_CONTINUOUS,
                .name           = "Zoom, Continuous",
                .entity         = UVC_GUID_UVC_CAMERA,
-               .selector       = CT_ZOOM_RELATIVE_CONTROL,
+               .selector       = UVC_CT_ZOOM_RELATIVE_CONTROL,
                .size           = 0,
                .offset         = 0,
                .v4l2_type      = V4L2_CTRL_TYPE_INTEGER,
@@ -582,7 +582,7 @@ static struct uvc_control_mapping uvc_ctrl_mappings[] = {
                .id             = V4L2_CID_PRIVACY,
                .name           = "Privacy",
                .entity         = UVC_GUID_UVC_CAMERA,
-               .selector       = CT_PRIVACY_CONTROL,
+               .selector       = UVC_CT_PRIVACY_CONTROL,
                .size           = 1,
                .offset         = 0,
                .v4l2_type      = V4L2_CTRL_TYPE_BOOLEAN,
@@ -675,16 +675,16 @@ static const __u8 uvc_media_transport_input_guid[16] =
 static int uvc_entity_match_guid(struct uvc_entity *entity, __u8 guid[16])
 {
        switch (UVC_ENTITY_TYPE(entity)) {
-       case ITT_CAMERA:
+       case UVC_ITT_CAMERA:
                return memcmp(uvc_camera_guid, guid, 16) == 0;
 
-       case ITT_MEDIA_TRANSPORT_INPUT:
+       case UVC_ITT_MEDIA_TRANSPORT_INPUT:
                return memcmp(uvc_media_transport_input_guid, guid, 16) == 0;
 
-       case VC_PROCESSING_UNIT:
+       case UVC_VC_PROCESSING_UNIT:
                return memcmp(uvc_processing_guid, guid, 16) == 0;
 
-       case VC_EXTENSION_UNIT:
+       case UVC_VC_EXTENSION_UNIT:
                return memcmp(entity->extension.guidExtensionCode,
                              guid, 16) == 0;
 
@@ -729,7 +729,7 @@ static void __uvc_find_control(struct uvc_entity *entity, __u32 v4l2_id,
        }
 }
 
-struct uvc_control *uvc_find_control(struct uvc_video_device *video,
+struct uvc_control *uvc_find_control(struct uvc_video_chain *chain,
        __u32 v4l2_id, struct uvc_control_mapping **mapping)
 {
        struct uvc_control *ctrl = NULL;
@@ -742,17 +742,17 @@ struct uvc_control *uvc_find_control(struct uvc_video_device *video,
        v4l2_id &= V4L2_CTRL_ID_MASK;
 
        /* Find the control. */
-       __uvc_find_control(video->processing, v4l2_id, mapping, &ctrl, next);
+       __uvc_find_control(chain->processing, v4l2_id, mapping, &ctrl, next);
        if (ctrl && !next)
                return ctrl;
 
-       list_for_each_entry(entity, &video->iterms, chain) {
+       list_for_each_entry(entity, &chain->iterms, chain) {
                __uvc_find_control(entity, v4l2_id, mapping, &ctrl, next);
                if (ctrl && !next)
                        return ctrl;
        }
 
-       list_for_each_entry(entity, &video->extensions, chain) {
+       list_for_each_entry(entity, &chain->extensions, chain) {
                __uvc_find_control(entity, v4l2_id, mapping, &ctrl, next);
                if (ctrl && !next)
                        return ctrl;
@@ -765,7 +765,7 @@ struct uvc_control *uvc_find_control(struct uvc_video_device *video,
        return ctrl;
 }
 
-int uvc_query_v4l2_ctrl(struct uvc_video_device *video,
+int uvc_query_v4l2_ctrl(struct uvc_video_chain *chain,
        struct v4l2_queryctrl *v4l2_ctrl)
 {
        struct uvc_control *ctrl;
@@ -775,7 +775,7 @@ int uvc_query_v4l2_ctrl(struct uvc_video_device *video,
        __u8 *data;
        int ret;
 
-       ctrl = uvc_find_control(video, v4l2_ctrl->id, &mapping);
+       ctrl = uvc_find_control(chain, v4l2_ctrl->id, &mapping);
        if (ctrl == NULL)
                return -EINVAL;
 
@@ -793,11 +793,13 @@ int uvc_query_v4l2_ctrl(struct uvc_video_device *video,
                v4l2_ctrl->flags |= V4L2_CTRL_FLAG_READ_ONLY;
 
        if (ctrl->info->flags & UVC_CONTROL_GET_DEF) {
-               if ((ret = uvc_query_ctrl(video->dev, GET_DEF, ctrl->entity->id,
-                               video->dev->intfnum, ctrl->info->selector,
-                               data, ctrl->info->size)) < 0)
+               ret = uvc_query_ctrl(chain->dev, UVC_GET_DEF, ctrl->entity->id,
+                                    chain->dev->intfnum, ctrl->info->selector,
+                                    data, ctrl->info->size);
+               if (ret < 0)
                        goto out;
-               v4l2_ctrl->default_value = mapping->get(mapping, GET_DEF, data);
+               v4l2_ctrl->default_value =
+                       mapping->get(mapping, UVC_GET_DEF, data);
        }
 
        switch (mapping->v4l2_type) {
@@ -829,25 +831,28 @@ int uvc_query_v4l2_ctrl(struct uvc_video_device *video,
        }
 
        if (ctrl->info->flags & UVC_CONTROL_GET_MIN) {
-               if ((ret = uvc_query_ctrl(video->dev, GET_MIN, ctrl->entity->id,
-                               video->dev->intfnum, ctrl->info->selector,
-                               data, ctrl->info->size)) < 0)
+               ret = uvc_query_ctrl(chain->dev, UVC_GET_MIN, ctrl->entity->id,
+                                    chain->dev->intfnum, ctrl->info->selector,
+                                    data, ctrl->info->size);
+               if (ret < 0)
                        goto out;
-               v4l2_ctrl->minimum = mapping->get(mapping, GET_MIN, data);
+               v4l2_ctrl->minimum = mapping->get(mapping, UVC_GET_MIN, data);
        }
        if (ctrl->info->flags & UVC_CONTROL_GET_MAX) {
-               if ((ret = uvc_query_ctrl(video->dev, GET_MAX, ctrl->entity->id,
-                               video->dev->intfnum, ctrl->info->selector,
-                               data, ctrl->info->size)) < 0)
+               ret = uvc_query_ctrl(chain->dev, UVC_GET_MAX, ctrl->entity->id,
+                                    chain->dev->intfnum, ctrl->info->selector,
+                                    data, ctrl->info->size);
+               if (ret < 0)
                        goto out;
-               v4l2_ctrl->maximum = mapping->get(mapping, GET_MAX, data);
+               v4l2_ctrl->maximum = mapping->get(mapping, UVC_GET_MAX, data);
        }
        if (ctrl->info->flags & UVC_CONTROL_GET_RES) {
-               if ((ret = uvc_query_ctrl(video->dev, GET_RES, ctrl->entity->id,
-                               video->dev->intfnum, ctrl->info->selector,
-                               data, ctrl->info->size)) < 0)
+               ret = uvc_query_ctrl(chain->dev, UVC_GET_RES, ctrl->entity->id,
+                                    chain->dev->intfnum, ctrl->info->selector,
+                                    data, ctrl->info->size);
+               if (ret < 0)
                        goto out;
-               v4l2_ctrl->step = mapping->get(mapping, GET_RES, data);
+               v4l2_ctrl->step = mapping->get(mapping, UVC_GET_RES, data);
        }
 
        ret = 0;
@@ -881,9 +886,9 @@ out:
  * (UVC_CTRL_DATA_BACKUP) for all dirty controls. Both functions release the
  * control lock.
  */
-int uvc_ctrl_begin(struct uvc_video_device *video)
+int uvc_ctrl_begin(struct uvc_video_chain *chain)
 {
-       return mutex_lock_interruptible(&video->ctrl_mutex) ? -ERESTARTSYS : 0;
+       return mutex_lock_interruptible(&chain->ctrl_mutex) ? -ERESTARTSYS : 0;
 }
 
 static int uvc_ctrl_commit_entity(struct uvc_device *dev,
@@ -912,7 +917,7 @@ static int uvc_ctrl_commit_entity(struct uvc_device *dev,
                        continue;
 
                if (!rollback)
-                       ret = uvc_query_ctrl(dev, SET_CUR, ctrl->entity->id,
+                       ret = uvc_query_ctrl(dev, UVC_SET_CUR, ctrl->entity->id,
                                dev->intfnum, ctrl->info->selector,
                                uvc_ctrl_data(ctrl, UVC_CTRL_DATA_CURRENT),
                                ctrl->info->size);
@@ -933,34 +938,34 @@ static int uvc_ctrl_commit_entity(struct uvc_device *dev,
        return 0;
 }
 
-int __uvc_ctrl_commit(struct uvc_video_device *video, int rollback)
+int __uvc_ctrl_commit(struct uvc_video_chain *chain, int rollback)
 {
        struct uvc_entity *entity;
        int ret = 0;
 
        /* Find the control. */
-       ret = uvc_ctrl_commit_entity(video->dev, video->processing, rollback);
+       ret = uvc_ctrl_commit_entity(chain->dev, chain->processing, rollback);
        if (ret < 0)
                goto done;
 
-       list_for_each_entry(entity, &video->iterms, chain) {
-               ret = uvc_ctrl_commit_entity(video->dev, entity, rollback);
+       list_for_each_entry(entity, &chain->iterms, chain) {
+               ret = uvc_ctrl_commit_entity(chain->dev, entity, rollback);
                if (ret < 0)
                        goto done;
        }
 
-       list_for_each_entry(entity, &video->extensions, chain) {
-               ret = uvc_ctrl_commit_entity(video->dev, entity, rollback);
+       list_for_each_entry(entity, &chain->extensions, chain) {
+               ret = uvc_ctrl_commit_entity(chain->dev, entity, rollback);
                if (ret < 0)
                        goto done;
        }
 
 done:
-       mutex_unlock(&video->ctrl_mutex);
+       mutex_unlock(&chain->ctrl_mutex);
        return ret;
 }
 
-int uvc_ctrl_get(struct uvc_video_device *video,
+int uvc_ctrl_get(struct uvc_video_chain *chain,
        struct v4l2_ext_control *xctrl)
 {
        struct uvc_control *ctrl;
@@ -969,13 +974,13 @@ int uvc_ctrl_get(struct uvc_video_device *video,
        unsigned int i;
        int ret;
 
-       ctrl = uvc_find_control(video, xctrl->id, &mapping);
+       ctrl = uvc_find_control(chain, xctrl->id, &mapping);
        if (ctrl == NULL || (ctrl->info->flags & UVC_CONTROL_GET_CUR) == 0)
                return -EINVAL;
 
        if (!ctrl->loaded) {
-               ret = uvc_query_ctrl(video->dev, GET_CUR, ctrl->entity->id,
-                               video->dev->intfnum, ctrl->info->selector,
+               ret = uvc_query_ctrl(chain->dev, UVC_GET_CUR, ctrl->entity->id,
+                               chain->dev->intfnum, ctrl->info->selector,
                                uvc_ctrl_data(ctrl, UVC_CTRL_DATA_CURRENT),
                                ctrl->info->size);
                if (ret < 0)
@@ -984,7 +989,7 @@ int uvc_ctrl_get(struct uvc_video_device *video,
                ctrl->loaded = 1;
        }
 
-       xctrl->value = mapping->get(mapping, GET_CUR,
+       xctrl->value = mapping->get(mapping, UVC_GET_CUR,
                uvc_ctrl_data(ctrl, UVC_CTRL_DATA_CURRENT));
 
        if (mapping->v4l2_type == V4L2_CTRL_TYPE_MENU) {
@@ -1000,7 +1005,7 @@ int uvc_ctrl_get(struct uvc_video_device *video,
        return 0;
 }
 
-int uvc_ctrl_set(struct uvc_video_device *video,
+int uvc_ctrl_set(struct uvc_video_chain *chain,
        struct v4l2_ext_control *xctrl)
 {
        struct uvc_control *ctrl;
@@ -1008,7 +1013,7 @@ int uvc_ctrl_set(struct uvc_video_device *video,
        s32 value = xctrl->value;
        int ret;
 
-       ctrl = uvc_find_control(video, xctrl->id, &mapping);
+       ctrl = uvc_find_control(chain, xctrl->id, &mapping);
        if (ctrl == NULL || (ctrl->info->flags & UVC_CONTROL_SET_CUR) == 0)
                return -EINVAL;
 
@@ -1023,8 +1028,8 @@ int uvc_ctrl_set(struct uvc_video_device *video,
                        memset(uvc_ctrl_data(ctrl, UVC_CTRL_DATA_CURRENT),
                                0, ctrl->info->size);
                } else {
-                       ret = uvc_query_ctrl(video->dev, GET_CUR,
-                               ctrl->entity->id, video->dev->intfnum,
+                       ret = uvc_query_ctrl(chain->dev, UVC_GET_CUR,
+                               ctrl->entity->id, chain->dev->intfnum,
                                ctrl->info->selector,
                                uvc_ctrl_data(ctrl, UVC_CTRL_DATA_CURRENT),
                                ctrl->info->size);
@@ -1053,7 +1058,7 @@ int uvc_ctrl_set(struct uvc_video_device *video,
  * Dynamic controls
  */
 
-int uvc_xu_ctrl_query(struct uvc_video_device *video,
+int uvc_xu_ctrl_query(struct uvc_video_chain *chain,
        struct uvc_xu_control *xctrl, int set)
 {
        struct uvc_entity *entity;
@@ -1063,7 +1068,7 @@ int uvc_xu_ctrl_query(struct uvc_video_device *video,
        int ret;
 
        /* Find the extension unit. */
-       list_for_each_entry(entity, &video->extensions, chain) {
+       list_for_each_entry(entity, &chain->extensions, chain) {
                if (entity->id == xctrl->unit)
                        break;
        }
@@ -1102,7 +1107,7 @@ int uvc_xu_ctrl_query(struct uvc_video_device *video,
            (!set && !(ctrl->info->flags & UVC_CONTROL_GET_CUR)))
                return -EINVAL;
 
-       if (mutex_lock_interruptible(&video->ctrl_mutex))
+       if (mutex_lock_interruptible(&chain->ctrl_mutex))
                return -ERESTARTSYS;
 
        memcpy(uvc_ctrl_data(ctrl, UVC_CTRL_DATA_BACKUP),
@@ -1115,9 +1120,9 @@ int uvc_xu_ctrl_query(struct uvc_video_device *video,
                goto out;
        }
 
-       ret = uvc_query_ctrl(video->dev, set ? SET_CUR : GET_CUR, xctrl->unit,
-                            video->dev->intfnum, xctrl->selector, data,
-                            xctrl->size);
+       ret = uvc_query_ctrl(chain->dev, set ? UVC_SET_CUR : UVC_GET_CUR,
+                            xctrl->unit, chain->dev->intfnum, xctrl->selector,
+                            data, xctrl->size);
        if (ret < 0)
                goto out;
 
@@ -1132,7 +1137,7 @@ out:
                       uvc_ctrl_data(ctrl, UVC_CTRL_DATA_BACKUP),
                       xctrl->size);
 
-       mutex_unlock(&video->ctrl_mutex);
+       mutex_unlock(&chain->ctrl_mutex);
        return ret;
 }
 
@@ -1211,7 +1216,7 @@ static void uvc_ctrl_add_ctrl(struct uvc_device *dev,
        if (!found)
                return;
 
-       if (UVC_ENTITY_TYPE(entity) == VC_EXTENSION_UNIT) {
+       if (UVC_ENTITY_TYPE(entity) == UVC_VC_EXTENSION_UNIT) {
                /* Check if the device control information and length match
                 * the user supplied information.
                 */
@@ -1219,8 +1224,9 @@ static void uvc_ctrl_add_ctrl(struct uvc_device *dev,
                __le16 size;
                __u8 inf;
 
-               if ((ret = uvc_query_ctrl(dev, GET_LEN, ctrl->entity->id,
-                       dev->intfnum, info->selector, (__u8 *)&size, 2)) < 0) {
+               ret = uvc_query_ctrl(dev, UVC_GET_LEN, ctrl->entity->id,
+                       dev->intfnum, info->selector, (__u8 *)&size, 2);
+               if (ret < 0) {
                        uvc_trace(UVC_TRACE_CONTROL, "GET_LEN failed on "
                                "control " UVC_GUID_FORMAT "/%u (%d).\n",
                                UVC_GUID_ARGS(info->entity), info->selector,
@@ -1236,8 +1242,9 @@ static void uvc_ctrl_add_ctrl(struct uvc_device *dev,
                        return;
                }
 
-               if ((ret = uvc_query_ctrl(dev, GET_INFO, ctrl->entity->id,
-                       dev->intfnum, info->selector, &inf, 1)) < 0) {
+               ret = uvc_query_ctrl(dev, UVC_GET_INFO, ctrl->entity->id,
+                       dev->intfnum, info->selector, &inf, 1);
+               if (ret < 0) {
                        uvc_trace(UVC_TRACE_CONTROL, "GET_INFO failed on "
                                "control " UVC_GUID_FORMAT "/%u (%d).\n",
                                UVC_GUID_ARGS(info->entity), info->selector,
@@ -1391,7 +1398,7 @@ uvc_ctrl_prune_entity(struct uvc_device *dev, struct uvc_entity *entity)
        unsigned int size;
        unsigned int i;
 
-       if (UVC_ENTITY_TYPE(entity) != VC_PROCESSING_UNIT)
+       if (UVC_ENTITY_TYPE(entity) != UVC_VC_PROCESSING_UNIT)
                return;
 
        controls = entity->processing.bmControls;
@@ -1427,13 +1434,13 @@ int uvc_ctrl_init_device(struct uvc_device *dev)
                unsigned int bControlSize = 0, ncontrols = 0;
                __u8 *bmControls = NULL;
 
-               if (UVC_ENTITY_TYPE(entity) == VC_EXTENSION_UNIT) {
+               if (UVC_ENTITY_TYPE(entity) == UVC_VC_EXTENSION_UNIT) {
                        bmControls = entity->extension.bmControls;
                        bControlSize = entity->extension.bControlSize;
-               } else if (UVC_ENTITY_TYPE(entity) == VC_PROCESSING_UNIT) {
+               } else if (UVC_ENTITY_TYPE(entity) == UVC_VC_PROCESSING_UNIT) {
                        bmControls = entity->processing.bmControls;
                        bControlSize = entity->processing.bControlSize;
-               } else if (UVC_ENTITY_TYPE(entity) == ITT_CAMERA) {
+               } else if (UVC_ENTITY_TYPE(entity) == UVC_ITT_CAMERA) {
                        bmControls = entity->camera.bmControls;
                        bControlSize = entity->camera.bControlSize;
                }
index 04b47832fa0a5d1d416cdf429cf9e320a69fc59f..8756be5691544d6c496dcf2803bc24adeed8c3d5 100644 (file)
@@ -249,23 +249,23 @@ static struct uvc_entity *uvc_entity_by_reference(struct uvc_device *dev,
 
        list_for_each_entry_continue(entity, &dev->entities, list) {
                switch (UVC_ENTITY_TYPE(entity)) {
-               case TT_STREAMING:
+               case UVC_TT_STREAMING:
                        if (entity->output.bSourceID == id)
                                return entity;
                        break;
 
-               case VC_PROCESSING_UNIT:
+               case UVC_VC_PROCESSING_UNIT:
                        if (entity->processing.bSourceID == id)
                                return entity;
                        break;
 
-               case VC_SELECTOR_UNIT:
+               case UVC_VC_SELECTOR_UNIT:
                        for (i = 0; i < entity->selector.bNrInPins; ++i)
                                if (entity->selector.baSourceID[i] == id)
                                        return entity;
                        break;
 
-               case VC_EXTENSION_UNIT:
+               case UVC_VC_EXTENSION_UNIT:
                        for (i = 0; i < entity->extension.bNrInPins; ++i)
                                if (entity->extension.baSourceID[i] == id)
                                        return entity;
@@ -276,8 +276,20 @@ static struct uvc_entity *uvc_entity_by_reference(struct uvc_device *dev,
        return NULL;
 }
 
+static struct uvc_streaming *uvc_stream_by_id(struct uvc_device *dev, int id)
+{
+       struct uvc_streaming *stream;
+
+       list_for_each_entry(stream, &dev->streams, list) {
+               if (stream->header.bTerminalLink == id)
+                       return stream;
+       }
+
+       return NULL;
+}
+
 /* ------------------------------------------------------------------------
- * Descriptors handling
+ * Descriptors parsing
  */
 
 static int uvc_parse_format(struct uvc_device *dev,
@@ -297,9 +309,9 @@ static int uvc_parse_format(struct uvc_device *dev,
        format->index = buffer[3];
 
        switch (buffer[2]) {
-       case VS_FORMAT_UNCOMPRESSED:
-       case VS_FORMAT_FRAME_BASED:
-               n = buffer[2] == VS_FORMAT_UNCOMPRESSED ? 27 : 28;
+       case UVC_VS_FORMAT_UNCOMPRESSED:
+       case UVC_VS_FORMAT_FRAME_BASED:
+               n = buffer[2] == UVC_VS_FORMAT_UNCOMPRESSED ? 27 : 28;
                if (buflen < n) {
                        uvc_trace(UVC_TRACE_DESCR, "device %d videostreaming "
                               "interface %d FORMAT error\n",
@@ -325,16 +337,16 @@ static int uvc_parse_format(struct uvc_device *dev,
                }
 
                format->bpp = buffer[21];
-               if (buffer[2] == VS_FORMAT_UNCOMPRESSED) {
-                       ftype = VS_FRAME_UNCOMPRESSED;
+               if (buffer[2] == UVC_VS_FORMAT_UNCOMPRESSED) {
+                       ftype = UVC_VS_FRAME_UNCOMPRESSED;
                } else {
-                       ftype = VS_FRAME_FRAME_BASED;
+                       ftype = UVC_VS_FRAME_FRAME_BASED;
                        if (buffer[27])
                                format->flags = UVC_FMT_FLAG_COMPRESSED;
                }
                break;
 
-       case VS_FORMAT_MJPEG:
+       case UVC_VS_FORMAT_MJPEG:
                if (buflen < 11) {
                        uvc_trace(UVC_TRACE_DESCR, "device %d videostreaming "
                               "interface %d FORMAT error\n",
@@ -347,10 +359,10 @@ static int uvc_parse_format(struct uvc_device *dev,
                format->fcc = V4L2_PIX_FMT_MJPEG;
                format->flags = UVC_FMT_FLAG_COMPRESSED;
                format->bpp = 0;
-               ftype = VS_FRAME_MJPEG;
+               ftype = UVC_VS_FRAME_MJPEG;
                break;
 
-       case VS_FORMAT_DV:
+       case UVC_VS_FORMAT_DV:
                if (buflen < 9) {
                        uvc_trace(UVC_TRACE_DESCR, "device %d videostreaming "
                               "interface %d FORMAT error\n",
@@ -395,8 +407,8 @@ static int uvc_parse_format(struct uvc_device *dev,
                format->nframes = 1;
                break;
 
-       case VS_FORMAT_MPEG2TS:
-       case VS_FORMAT_STREAM_BASED:
+       case UVC_VS_FORMAT_MPEG2TS:
+       case UVC_VS_FORMAT_STREAM_BASED:
                /* Not supported yet. */
        default:
                uvc_trace(UVC_TRACE_DESCR, "device %d videostreaming "
@@ -416,7 +428,7 @@ static int uvc_parse_format(struct uvc_device *dev,
         */
        while (buflen > 2 && buffer[2] == ftype) {
                frame = &format->frame[format->nframes];
-               if (ftype != VS_FRAME_FRAME_BASED)
+               if (ftype != UVC_VS_FRAME_FRAME_BASED)
                        n = buflen > 25 ? buffer[25] : 0;
                else
                        n = buflen > 21 ? buffer[21] : 0;
@@ -436,7 +448,7 @@ static int uvc_parse_format(struct uvc_device *dev,
                frame->wHeight = get_unaligned_le16(&buffer[7]);
                frame->dwMinBitRate = get_unaligned_le32(&buffer[9]);
                frame->dwMaxBitRate = get_unaligned_le32(&buffer[13]);
-               if (ftype != VS_FRAME_FRAME_BASED) {
+               if (ftype != UVC_VS_FRAME_FRAME_BASED) {
                        frame->dwMaxVideoFrameBufferSize =
                                get_unaligned_le32(&buffer[17]);
                        frame->dwDefaultFrameInterval =
@@ -491,12 +503,12 @@ static int uvc_parse_format(struct uvc_device *dev,
                buffer += buffer[0];
        }
 
-       if (buflen > 2 && buffer[2] == VS_STILL_IMAGE_FRAME) {
+       if (buflen > 2 && buffer[2] == UVC_VS_STILL_IMAGE_FRAME) {
                buflen -= buffer[0];
                buffer += buffer[0];
        }
 
-       if (buflen > 2 && buffer[2] == VS_COLORFORMAT) {
+       if (buflen > 2 && buffer[2] == UVC_VS_COLORFORMAT) {
                if (buflen < 6) {
                        uvc_trace(UVC_TRACE_DESCR, "device %d videostreaming "
                               "interface %d COLORFORMAT error\n",
@@ -530,7 +542,7 @@ static int uvc_parse_streaming(struct uvc_device *dev,
        int ret = -EINVAL;
 
        if (intf->cur_altsetting->desc.bInterfaceSubClass
-               != SC_VIDEOSTREAMING) {
+               != UVC_SC_VIDEOSTREAMING) {
                uvc_trace(UVC_TRACE_DESCR, "device %d interface %d isn't a "
                        "video streaming interface\n", dev->udev->devnum,
                        intf->altsetting[0].desc.bInterfaceNumber);
@@ -551,6 +563,7 @@ static int uvc_parse_streaming(struct uvc_device *dev,
        }
 
        mutex_init(&streaming->mutex);
+       streaming->dev = dev;
        streaming->intf = usb_get_intf(intf);
        streaming->intfnum = intf->cur_altsetting->desc.bInterfaceNumber;
 
@@ -589,12 +602,12 @@ static int uvc_parse_streaming(struct uvc_device *dev,
 
        /* Parse the header descriptor. */
        switch (buffer[2]) {
-       case VS_OUTPUT_HEADER:
+       case UVC_VS_OUTPUT_HEADER:
                streaming->type = V4L2_BUF_TYPE_VIDEO_OUTPUT;
                size = 9;
                break;
 
-       case VS_INPUT_HEADER:
+       case UVC_VS_INPUT_HEADER:
                streaming->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
                size = 13;
                break;
@@ -618,7 +631,7 @@ static int uvc_parse_streaming(struct uvc_device *dev,
 
        streaming->header.bNumFormats = p;
        streaming->header.bEndpointAddress = buffer[6];
-       if (buffer[2] == VS_INPUT_HEADER) {
+       if (buffer[2] == UVC_VS_INPUT_HEADER) {
                streaming->header.bmInfo = buffer[7];
                streaming->header.bTerminalLink = buffer[8];
                streaming->header.bStillCaptureMethod = buffer[9];
@@ -644,15 +657,15 @@ static int uvc_parse_streaming(struct uvc_device *dev,
        _buflen = buflen;
 
        /* Count the format and frame descriptors. */
-       while (_buflen > 2 && _buffer[1] == CS_INTERFACE) {
+       while (_buflen > 2 && _buffer[1] == USB_DT_CS_INTERFACE) {
                switch (_buffer[2]) {
-               case VS_FORMAT_UNCOMPRESSED:
-               case VS_FORMAT_MJPEG:
-               case VS_FORMAT_FRAME_BASED:
+               case UVC_VS_FORMAT_UNCOMPRESSED:
+               case UVC_VS_FORMAT_MJPEG:
+               case UVC_VS_FORMAT_FRAME_BASED:
                        nformats++;
                        break;
 
-               case VS_FORMAT_DV:
+               case UVC_VS_FORMAT_DV:
                        /* DV format has no frame descriptor. We will create a
                         * dummy frame descriptor with a dummy frame interval.
                         */
@@ -661,22 +674,22 @@ static int uvc_parse_streaming(struct uvc_device *dev,
                        nintervals++;
                        break;
 
-               case VS_FORMAT_MPEG2TS:
-               case VS_FORMAT_STREAM_BASED:
+               case UVC_VS_FORMAT_MPEG2TS:
+               case UVC_VS_FORMAT_STREAM_BASED:
                        uvc_trace(UVC_TRACE_DESCR, "device %d videostreaming "
                                "interface %d FORMAT %u is not supported.\n",
                                dev->udev->devnum,
                                alts->desc.bInterfaceNumber, _buffer[2]);
                        break;
 
-               case VS_FRAME_UNCOMPRESSED:
-               case VS_FRAME_MJPEG:
+               case UVC_VS_FRAME_UNCOMPRESSED:
+               case UVC_VS_FRAME_MJPEG:
                        nframes++;
                        if (_buflen > 25)
                                nintervals += _buffer[25] ? _buffer[25] : 3;
                        break;
 
-               case VS_FRAME_FRAME_BASED:
+               case UVC_VS_FRAME_FRAME_BASED:
                        nframes++;
                        if (_buflen > 21)
                                nintervals += _buffer[21] ? _buffer[21] : 3;
@@ -709,12 +722,12 @@ static int uvc_parse_streaming(struct uvc_device *dev,
        streaming->nformats = nformats;
 
        /* Parse the format descriptors. */
-       while (buflen > 2 && buffer[1] == CS_INTERFACE) {
+       while (buflen > 2 && buffer[1] == USB_DT_CS_INTERFACE) {
                switch (buffer[2]) {
-               case VS_FORMAT_UNCOMPRESSED:
-               case VS_FORMAT_MJPEG:
-               case VS_FORMAT_DV:
-               case VS_FORMAT_FRAME_BASED:
+               case UVC_VS_FORMAT_UNCOMPRESSED:
+               case UVC_VS_FORMAT_MJPEG:
+               case UVC_VS_FORMAT_DV:
+               case UVC_VS_FORMAT_FRAME_BASED:
                        format->frame = frame;
                        ret = uvc_parse_format(dev, streaming, format,
                                &interval, buffer, buflen);
@@ -751,7 +764,7 @@ static int uvc_parse_streaming(struct uvc_device *dev,
                        streaming->maxpsize = psize;
        }
 
-       list_add_tail(&streaming->list, &dev->streaming);
+       list_add_tail(&streaming->list, &dev->streams);
        return 0;
 
 error:
@@ -819,7 +832,7 @@ static int uvc_parse_vendor_control(struct uvc_device *dev,
                        return -ENOMEM;
 
                unit->id = buffer[3];
-               unit->type = VC_EXTENSION_UNIT;
+               unit->type = UVC_VC_EXTENSION_UNIT;
                memcpy(unit->extension.guidExtensionCode, &buffer[4], 16);
                unit->extension.bNumControls = buffer[20];
                unit->extension.bNrInPins = get_unaligned_le16(&buffer[21]);
@@ -856,7 +869,7 @@ static int uvc_parse_standard_control(struct uvc_device *dev,
        __u16 type;
 
        switch (buffer[2]) {
-       case VC_HEADER:
+       case UVC_VC_HEADER:
                n = buflen >= 12 ? buffer[11] : 0;
 
                if (buflen < 12 || buflen < 12 + n) {
@@ -883,7 +896,7 @@ static int uvc_parse_standard_control(struct uvc_device *dev,
                }
                break;
 
-       case VC_INPUT_TERMINAL:
+       case UVC_VC_INPUT_TERMINAL:
                if (buflen < 8) {
                        uvc_trace(UVC_TRACE_DESCR, "device %d videocontrol "
                                "interface %d INPUT_TERMINAL error\n",
@@ -908,11 +921,11 @@ static int uvc_parse_standard_control(struct uvc_device *dev,
                p = 0;
                len = 8;
 
-               if (type == ITT_CAMERA) {
+               if (type == UVC_ITT_CAMERA) {
                        n = buflen >= 15 ? buffer[14] : 0;
                        len = 15;
 
-               } else if (type == ITT_MEDIA_TRANSPORT_INPUT) {
+               } else if (type == UVC_ITT_MEDIA_TRANSPORT_INPUT) {
                        n = buflen >= 9 ? buffer[8] : 0;
                        p = buflen >= 10 + n ? buffer[9+n] : 0;
                        len = 10;
@@ -932,7 +945,7 @@ static int uvc_parse_standard_control(struct uvc_device *dev,
                term->id = buffer[3];
                term->type = type | UVC_TERM_INPUT;
 
-               if (UVC_ENTITY_TYPE(term) == ITT_CAMERA) {
+               if (UVC_ENTITY_TYPE(term) == UVC_ITT_CAMERA) {
                        term->camera.bControlSize = n;
                        term->camera.bmControls = (__u8 *)term + sizeof *term;
                        term->camera.wObjectiveFocalLengthMin =
@@ -942,7 +955,8 @@ static int uvc_parse_standard_control(struct uvc_device *dev,
                        term->camera.wOcularFocalLength =
                                get_unaligned_le16(&buffer[12]);
                        memcpy(term->camera.bmControls, &buffer[15], n);
-               } else if (UVC_ENTITY_TYPE(term) == ITT_MEDIA_TRANSPORT_INPUT) {
+               } else if (UVC_ENTITY_TYPE(term) ==
+                          UVC_ITT_MEDIA_TRANSPORT_INPUT) {
                        term->media.bControlSize = n;
                        term->media.bmControls = (__u8 *)term + sizeof *term;
                        term->media.bTransportModeSize = p;
@@ -955,9 +969,9 @@ static int uvc_parse_standard_control(struct uvc_device *dev,
                if (buffer[7] != 0)
                        usb_string(udev, buffer[7], term->name,
                                   sizeof term->name);
-               else if (UVC_ENTITY_TYPE(term) == ITT_CAMERA)
+               else if (UVC_ENTITY_TYPE(term) == UVC_ITT_CAMERA)
                        sprintf(term->name, "Camera %u", buffer[3]);
-               else if (UVC_ENTITY_TYPE(term) == ITT_MEDIA_TRANSPORT_INPUT)
+               else if (UVC_ENTITY_TYPE(term) == UVC_ITT_MEDIA_TRANSPORT_INPUT)
                        sprintf(term->name, "Media %u", buffer[3]);
                else
                        sprintf(term->name, "Input %u", buffer[3]);
@@ -965,7 +979,7 @@ static int uvc_parse_standard_control(struct uvc_device *dev,
                list_add_tail(&term->list, &dev->entities);
                break;
 
-       case VC_OUTPUT_TERMINAL:
+       case UVC_VC_OUTPUT_TERMINAL:
                if (buflen < 9) {
                        uvc_trace(UVC_TRACE_DESCR, "device %d videocontrol "
                                "interface %d OUTPUT_TERMINAL error\n",
@@ -1002,7 +1016,7 @@ static int uvc_parse_standard_control(struct uvc_device *dev,
                list_add_tail(&term->list, &dev->entities);
                break;
 
-       case VC_SELECTOR_UNIT:
+       case UVC_VC_SELECTOR_UNIT:
                p = buflen >= 5 ? buffer[4] : 0;
 
                if (buflen < 5 || buflen < 6 + p) {
@@ -1031,7 +1045,7 @@ static int uvc_parse_standard_control(struct uvc_device *dev,
                list_add_tail(&unit->list, &dev->entities);
                break;
 
-       case VC_PROCESSING_UNIT:
+       case UVC_VC_PROCESSING_UNIT:
                n = buflen >= 8 ? buffer[7] : 0;
                p = dev->uvc_version >= 0x0110 ? 10 : 9;
 
@@ -1066,7 +1080,7 @@ static int uvc_parse_standard_control(struct uvc_device *dev,
                list_add_tail(&unit->list, &dev->entities);
                break;
 
-       case VC_EXTENSION_UNIT:
+       case UVC_VC_EXTENSION_UNIT:
                p = buflen >= 22 ? buffer[21] : 0;
                n = buflen >= 24 + p ? buffer[22+p] : 0;
 
@@ -1158,43 +1172,40 @@ next_descriptor:
 }
 
 /* ------------------------------------------------------------------------
- * USB probe and disconnect
+ * UVC device scan
  */
 
-/*
- * Unregister the video devices.
- */
-static void uvc_unregister_video(struct uvc_device *dev)
-{
-       if (dev->video.vdev) {
-               if (dev->video.vdev->minor == -1)
-                       video_device_release(dev->video.vdev);
-               else
-                       video_unregister_device(dev->video.vdev);
-               dev->video.vdev = NULL;
-       }
-}
-
 /*
  * Scan the UVC descriptors to locate a chain starting at an Output Terminal
  * and containing the following units:
  *
- * - one Output Terminal (USB Streaming or Display)
+ * - one or more Output Terminals (USB Streaming or Display)
  * - zero or one Processing Unit
- * - zero, one or mode single-input Selector Units
+ * - zero, one or more single-input Selector Units
  * - zero or one multiple-input Selector Units, provided all inputs are
  *   connected to input terminals
  * - zero, one or mode single-input Extension Units
  * - one or more Input Terminals (Camera, External or USB Streaming)
  *
- * A side forward scan is made on each detected entity to check for additional
- * extension units.
+ * The terminal and units must match on of the following structures:
+ *
+ * ITT_*(0) -> +---------+    +---------+    +---------+ -> TT_STREAMING(0)
+ * ...         | SU{0,1} | -> | PU{0,1} | -> | XU{0,n} |    ...
+ * ITT_*(n) -> +---------+    +---------+    +---------+ -> TT_STREAMING(n)
+ *
+ *                 +---------+    +---------+ -> OTT_*(0)
+ * TT_STREAMING -> | PU{0,1} | -> | XU{0,n} |    ...
+ *                 +---------+    +---------+ -> OTT_*(n)
+ *
+ * The Processing Unit and Extension Units can be in any order. Additional
+ * Extension Units connected to the main chain as single-unit branches are
+ * also supported. Single-input Selector Units are ignored.
  */
-static int uvc_scan_chain_entity(struct uvc_video_device *video,
+static int uvc_scan_chain_entity(struct uvc_video_chain *chain,
        struct uvc_entity *entity)
 {
        switch (UVC_ENTITY_TYPE(entity)) {
-       case VC_EXTENSION_UNIT:
+       case UVC_VC_EXTENSION_UNIT:
                if (uvc_trace_param & UVC_TRACE_PROBE)
                        printk(" <- XU %d", entity->id);
 
@@ -1204,23 +1215,23 @@ static int uvc_scan_chain_entity(struct uvc_video_device *video,
                        return -1;
                }
 
-               list_add_tail(&entity->chain, &video->extensions);
+               list_add_tail(&entity->chain, &chain->extensions);
                break;
 
-       case VC_PROCESSING_UNIT:
+       case UVC_VC_PROCESSING_UNIT:
                if (uvc_trace_param & UVC_TRACE_PROBE)
                        printk(" <- PU %d", entity->id);
 
-               if (video->processing != NULL) {
+               if (chain->processing != NULL) {
                        uvc_trace(UVC_TRACE_DESCR, "Found multiple "
                                "Processing Units in chain.\n");
                        return -1;
                }
 
-               video->processing = entity;
+               chain->processing = entity;
                break;
 
-       case VC_SELECTOR_UNIT:
+       case UVC_VC_SELECTOR_UNIT:
                if (uvc_trace_param & UVC_TRACE_PROBE)
                        printk(" <- SU %d", entity->id);
 
@@ -1228,25 +1239,25 @@ static int uvc_scan_chain_entity(struct uvc_video_device *video,
                if (entity->selector.bNrInPins == 1)
                        break;
 
-               if (video->selector != NULL) {
+               if (chain->selector != NULL) {
                        uvc_trace(UVC_TRACE_DESCR, "Found multiple Selector "
                                "Units in chain.\n");
                        return -1;
                }
 
-               video->selector = entity;
+               chain->selector = entity;
                break;
 
-       case ITT_VENDOR_SPECIFIC:
-       case ITT_CAMERA:
-       case ITT_MEDIA_TRANSPORT_INPUT:
+       case UVC_ITT_VENDOR_SPECIFIC:
+       case UVC_ITT_CAMERA:
+       case UVC_ITT_MEDIA_TRANSPORT_INPUT:
                if (uvc_trace_param & UVC_TRACE_PROBE)
                        printk(" <- IT %d\n", entity->id);
 
-               list_add_tail(&entity->chain, &video->iterms);
+               list_add_tail(&entity->chain, &chain->iterms);
                break;
 
-       case TT_STREAMING:
+       case UVC_TT_STREAMING:
                if (uvc_trace_param & UVC_TRACE_PROBE)
                        printk(" <- IT %d\n", entity->id);
 
@@ -1256,14 +1267,7 @@ static int uvc_scan_chain_entity(struct uvc_video_device *video,
                        return -1;
                }
 
-               if (video->sterm != NULL) {
-                       uvc_trace(UVC_TRACE_DESCR, "Found multiple streaming "
-                               "entities in chain.\n");
-                       return -1;
-               }
-
-               list_add_tail(&entity->chain, &video->iterms);
-               video->sterm = entity;
+               list_add_tail(&entity->chain, &chain->iterms);
                break;
 
        default:
@@ -1275,7 +1279,7 @@ static int uvc_scan_chain_entity(struct uvc_video_device *video,
        return 0;
 }
 
-static int uvc_scan_chain_forward(struct uvc_video_device *video,
+static int uvc_scan_chain_forward(struct uvc_video_chain *chain,
        struct uvc_entity *entity, struct uvc_entity *prev)
 {
        struct uvc_entity *forward;
@@ -1286,28 +1290,51 @@ static int uvc_scan_chain_forward(struct uvc_video_device *video,
        found = 0;
 
        while (1) {
-               forward = uvc_entity_by_reference(video->dev, entity->id,
+               forward = uvc_entity_by_reference(chain->dev, entity->id,
                        forward);
                if (forward == NULL)
                        break;
-
-               if (UVC_ENTITY_TYPE(forward) != VC_EXTENSION_UNIT ||
-                   forward == prev)
+               if (forward == prev)
                        continue;
 
-               if (forward->extension.bNrInPins != 1) {
-                       uvc_trace(UVC_TRACE_DESCR, "Extension unit %d has "
-                               "more than 1 input pin.\n", entity->id);
-                       return -1;
-               }
+               switch (UVC_ENTITY_TYPE(forward)) {
+               case UVC_VC_EXTENSION_UNIT:
+                       if (forward->extension.bNrInPins != 1) {
+                               uvc_trace(UVC_TRACE_DESCR, "Extension unit %d "
+                                         "has more than 1 input pin.\n",
+                                         entity->id);
+                               return -EINVAL;
+                       }
+
+                       list_add_tail(&forward->chain, &chain->extensions);
+                       if (uvc_trace_param & UVC_TRACE_PROBE) {
+                               if (!found)
+                                       printk(" (->");
 
-               list_add_tail(&forward->chain, &video->extensions);
-               if (uvc_trace_param & UVC_TRACE_PROBE) {
-                       if (!found)
-                               printk(" (-> XU");
+                               printk(" XU %d", forward->id);
+                               found = 1;
+                       }
+                       break;
+
+               case UVC_OTT_VENDOR_SPECIFIC:
+               case UVC_OTT_DISPLAY:
+               case UVC_OTT_MEDIA_TRANSPORT_OUTPUT:
+               case UVC_TT_STREAMING:
+                       if (UVC_ENTITY_IS_ITERM(forward)) {
+                               uvc_trace(UVC_TRACE_DESCR, "Unsupported input "
+                                       "terminal %u.\n", forward->id);
+                               return -EINVAL;
+                       }
 
-                       printk(" %d", forward->id);
-                       found = 1;
+                       list_add_tail(&forward->chain, &chain->oterms);
+                       if (uvc_trace_param & UVC_TRACE_PROBE) {
+                               if (!found)
+                                       printk(" (->");
+
+                               printk(" OT %d", forward->id);
+                               found = 1;
+                       }
+                       break;
                }
        }
        if (found)
@@ -1316,22 +1343,22 @@ static int uvc_scan_chain_forward(struct uvc_video_device *video,
        return 0;
 }
 
-static int uvc_scan_chain_backward(struct uvc_video_device *video,
+static int uvc_scan_chain_backward(struct uvc_video_chain *chain,
        struct uvc_entity *entity)
 {
        struct uvc_entity *term;
        int id = -1, i;
 
        switch (UVC_ENTITY_TYPE(entity)) {
-       case VC_EXTENSION_UNIT:
+       case UVC_VC_EXTENSION_UNIT:
                id = entity->extension.baSourceID[0];
                break;
 
-       case VC_PROCESSING_UNIT:
+       case UVC_VC_PROCESSING_UNIT:
                id = entity->processing.bSourceID;
                break;
 
-       case VC_SELECTOR_UNIT:
+       case UVC_VC_SELECTOR_UNIT:
                /* Single-input selector units are ignored. */
                if (entity->selector.bNrInPins == 1) {
                        id = entity->selector.baSourceID[0];
@@ -1341,10 +1368,10 @@ static int uvc_scan_chain_backward(struct uvc_video_device *video,
                if (uvc_trace_param & UVC_TRACE_PROBE)
                        printk(" <- IT");
 
-               video->selector = entity;
+               chain->selector = entity;
                for (i = 0; i < entity->selector.bNrInPins; ++i) {
                        id = entity->selector.baSourceID[i];
-                       term = uvc_entity_by_id(video->dev, id);
+                       term = uvc_entity_by_id(chain->dev, id);
                        if (term == NULL || !UVC_ENTITY_IS_ITERM(term)) {
                                uvc_trace(UVC_TRACE_DESCR, "Selector unit %d "
                                        "input %d isn't connected to an "
@@ -1355,8 +1382,8 @@ static int uvc_scan_chain_backward(struct uvc_video_device *video,
                        if (uvc_trace_param & UVC_TRACE_PROBE)
                                printk(" %d", term->id);
 
-                       list_add_tail(&term->chain, &video->iterms);
-                       uvc_scan_chain_forward(video, term, entity);
+                       list_add_tail(&term->chain, &chain->iterms);
+                       uvc_scan_chain_forward(chain, term, entity);
                }
 
                if (uvc_trace_param & UVC_TRACE_PROBE)
@@ -1369,125 +1396,170 @@ static int uvc_scan_chain_backward(struct uvc_video_device *video,
        return id;
 }
 
-static int uvc_scan_chain(struct uvc_video_device *video)
+static int uvc_scan_chain(struct uvc_video_chain *chain,
+                         struct uvc_entity *oterm)
 {
        struct uvc_entity *entity, *prev;
        int id;
 
-       entity = video->oterm;
+       entity = oterm;
+       list_add_tail(&entity->chain, &chain->oterms);
        uvc_trace(UVC_TRACE_PROBE, "Scanning UVC chain: OT %d", entity->id);
 
-       if (UVC_ENTITY_TYPE(entity) == TT_STREAMING)
-               video->sterm = entity;
-
        id = entity->output.bSourceID;
        while (id != 0) {
                prev = entity;
-               entity = uvc_entity_by_id(video->dev, id);
+               entity = uvc_entity_by_id(chain->dev, id);
                if (entity == NULL) {
                        uvc_trace(UVC_TRACE_DESCR, "Found reference to "
                                "unknown entity %d.\n", id);
-                       return -1;
+                       return -EINVAL;
+               }
+
+               if (entity->chain.next || entity->chain.prev) {
+                       uvc_trace(UVC_TRACE_DESCR, "Found reference to "
+                               "entity %d already in chain.\n", id);
+                       return -EINVAL;
                }
 
                /* Process entity */
-               if (uvc_scan_chain_entity(video, entity) < 0)
-                       return -1;
+               if (uvc_scan_chain_entity(chain, entity) < 0)
+                       return -EINVAL;
 
                /* Forward scan */
-               if (uvc_scan_chain_forward(video, entity, prev) < 0)
-                       return -1;
+               if (uvc_scan_chain_forward(chain, entity, prev) < 0)
+                       return -EINVAL;
 
                /* Stop when a terminal is found. */
-               if (!UVC_ENTITY_IS_UNIT(entity))
+               if (UVC_ENTITY_IS_TERM(entity))
                        break;
 
                /* Backward scan */
-               id = uvc_scan_chain_backward(video, entity);
+               id = uvc_scan_chain_backward(chain, entity);
                if (id < 0)
                        return id;
        }
 
-       if (video->sterm == NULL) {
-               uvc_trace(UVC_TRACE_DESCR, "No streaming entity found in "
-                       "chain.\n");
-               return -1;
+       return 0;
+}
+
+static unsigned int uvc_print_terms(struct list_head *terms, char *buffer)
+{
+       struct uvc_entity *term;
+       unsigned int nterms = 0;
+       char *p = buffer;
+
+       list_for_each_entry(term, terms, chain) {
+               p += sprintf(p, "%u", term->id);
+               if (term->chain.next != terms) {
+                       p += sprintf(p, ",");
+                       if (++nterms >= 4) {
+                               p += sprintf(p, "...");
+                               break;
+                       }
+               }
        }
 
-       return 0;
+       return p - buffer;
+}
+
+static const char *uvc_print_chain(struct uvc_video_chain *chain)
+{
+       static char buffer[43];
+       char *p = buffer;
+
+       p += uvc_print_terms(&chain->iterms, p);
+       p += sprintf(p, " -> ");
+       uvc_print_terms(&chain->oterms, p);
+
+       return buffer;
 }
 
 /*
- * Register the video devices.
- *
- * The driver currently supports a single video device per control interface
- * only. The terminal and units must match the following structure:
+ * Scan the device for video chains and register video devices.
  *
- * ITT_* -> VC_PROCESSING_UNIT -> VC_EXTENSION_UNIT{0,n} -> TT_STREAMING
- * TT_STREAMING -> VC_PROCESSING_UNIT -> VC_EXTENSION_UNIT{0,n} -> OTT_*
- *
- * The Extension Units, if present, must have a single input pin. The
- * Processing Unit and Extension Units can be in any order. Additional
- * Extension Units connected to the main chain as single-unit branches are
- * also supported.
+ * Chains are scanned starting at their output terminals and walked backwards.
  */
-static int uvc_register_video(struct uvc_device *dev)
+static int uvc_scan_device(struct uvc_device *dev)
 {
-       struct video_device *vdev;
+       struct uvc_video_chain *chain;
        struct uvc_entity *term;
-       int found = 0, ret;
 
-       /* Check if the control interface matches the structure we expect. */
        list_for_each_entry(term, &dev->entities, list) {
-               struct uvc_streaming *streaming;
-
-               if (!UVC_ENTITY_IS_TERM(term) || !UVC_ENTITY_IS_OTERM(term))
+               if (!UVC_ENTITY_IS_OTERM(term))
                        continue;
 
-               memset(&dev->video, 0, sizeof dev->video);
-               mutex_init(&dev->video.ctrl_mutex);
-               INIT_LIST_HEAD(&dev->video.iterms);
-               INIT_LIST_HEAD(&dev->video.extensions);
-               dev->video.oterm = term;
-               dev->video.dev = dev;
-               if (uvc_scan_chain(&dev->video) < 0)
+               /* If the terminal is already included in a chain, skip it.
+                * This can happen for chains that have multiple output
+                * terminals, where all output terminals beside the first one
+                * will be inserted in the chain in forward scans.
+                */
+               if (term->chain.next || term->chain.prev)
                        continue;
 
-               list_for_each_entry(streaming, &dev->streaming, list) {
-                       if (streaming->header.bTerminalLink ==
-                           dev->video.sterm->id) {
-                               dev->video.streaming = streaming;
-                               found = 1;
-                               break;
-                       }
+               chain = kzalloc(sizeof(*chain), GFP_KERNEL);
+               if (chain == NULL)
+                       return -ENOMEM;
+
+               INIT_LIST_HEAD(&chain->iterms);
+               INIT_LIST_HEAD(&chain->oterms);
+               INIT_LIST_HEAD(&chain->extensions);
+               mutex_init(&chain->ctrl_mutex);
+               chain->dev = dev;
+
+               if (uvc_scan_chain(chain, term) < 0) {
+                       kfree(chain);
+                       continue;
                }
 
-               if (found)
-                       break;
+               uvc_trace(UVC_TRACE_PROBE, "Found a valid video chain (%s).\n",
+                         uvc_print_chain(chain));
+
+               list_add_tail(&chain->list, &dev->chains);
        }
 
-       if (!found) {
+       if (list_empty(&dev->chains)) {
                uvc_printk(KERN_INFO, "No valid video chain found.\n");
                return -1;
        }
 
-       if (uvc_trace_param & UVC_TRACE_PROBE) {
-               uvc_printk(KERN_INFO, "Found a valid video chain (");
-               list_for_each_entry(term, &dev->video.iterms, chain) {
-                       printk("%d", term->id);
-                       if (term->chain.next != &dev->video.iterms)
-                               printk(",");
-               }
-               printk(" -> %d).\n", dev->video.oterm->id);
+       return 0;
+}
+
+/* ------------------------------------------------------------------------
+ * Video device registration and unregistration
+ */
+
+/*
+ * Unregister the video devices.
+ */
+static void uvc_unregister_video(struct uvc_device *dev)
+{
+       struct uvc_streaming *stream;
+
+       list_for_each_entry(stream, &dev->streams, list) {
+               if (stream->vdev == NULL)
+                       continue;
+
+               if (stream->vdev->minor == -1)
+                       video_device_release(stream->vdev);
+               else
+                       video_unregister_device(stream->vdev);
+               stream->vdev = NULL;
        }
+}
 
-       /* Initialize the video buffers queue. */
-       uvc_queue_init(&dev->video.queue, dev->video.streaming->type);
+static int uvc_register_video(struct uvc_device *dev,
+               struct uvc_streaming *stream)
+{
+       struct video_device *vdev;
+       int ret;
 
        /* Initialize the streaming interface with default streaming
         * parameters.
         */
-       if ((ret = uvc_video_init(&dev->video)) < 0) {
+       ret = uvc_video_init(stream);
+       if (ret < 0) {
                uvc_printk(KERN_ERR, "Failed to initialize the device "
                        "(%d).\n", ret);
                return ret;
@@ -1495,8 +1567,11 @@ static int uvc_register_video(struct uvc_device *dev)
 
        /* Register the device with V4L. */
        vdev = video_device_alloc();
-       if (vdev == NULL)
-               return -1;
+       if (vdev == NULL) {
+               uvc_printk(KERN_ERR, "Failed to allocate video device (%d).\n",
+                          ret);
+               return -ENOMEM;
+       }
 
        /* We already hold a reference to dev->udev. The video device will be
         * unregistered before the reference is released, so we don't need to
@@ -1511,18 +1586,73 @@ static int uvc_register_video(struct uvc_device *dev)
        /* Set the driver data before calling video_register_device, otherwise
         * uvc_v4l2_open might race us.
         */
-       dev->video.vdev = vdev;
-       video_set_drvdata(vdev, &dev->video);
-
-       if (video_register_device(vdev, VFL_TYPE_GRABBER, -1) < 0) {
-               dev->video.vdev = NULL;
+       stream->vdev = vdev;
+       video_set_drvdata(vdev, stream);
+
+       ret = video_register_device(vdev, VFL_TYPE_GRABBER, -1);
+       if (ret < 0) {
+               uvc_printk(KERN_ERR, "Failed to register video device (%d).\n",
+                          ret);
+               stream->vdev = NULL;
                video_device_release(vdev);
-               return -1;
+               return ret;
        }
 
        return 0;
 }
 
+/*
+ * Register all video devices in all chains.
+ */
+static int uvc_register_terms(struct uvc_device *dev,
+       struct uvc_video_chain *chain, struct list_head *terms)
+{
+       struct uvc_streaming *stream;
+       struct uvc_entity *term;
+       int ret;
+
+       list_for_each_entry(term, terms, chain) {
+               if (UVC_ENTITY_TYPE(term) != UVC_TT_STREAMING)
+                       continue;
+
+               stream = uvc_stream_by_id(dev, term->id);
+               if (stream == NULL) {
+                       uvc_printk(KERN_INFO, "No streaming interface found "
+                                  "for terminal %u.", term->id);
+                       continue;
+               }
+
+               stream->chain = chain;
+               ret = uvc_register_video(dev, stream);
+               if (ret < 0)
+                       return ret;
+       }
+
+       return 0;
+}
+
+static int uvc_register_chains(struct uvc_device *dev)
+{
+       struct uvc_video_chain *chain;
+       int ret;
+
+       list_for_each_entry(chain, &dev->chains, list) {
+               ret = uvc_register_terms(dev, chain, &chain->iterms);
+               if (ret < 0)
+                       return ret;
+
+               ret = uvc_register_terms(dev, chain, &chain->oterms);
+               if (ret < 0)
+                       return ret;
+       }
+
+       return 0;
+}
+
+/* ------------------------------------------------------------------------
+ * USB probe, disconnect, suspend and resume
+ */
+
 /*
  * Delete the UVC device.
  *
@@ -1544,7 +1674,7 @@ void uvc_delete(struct kref *kref)
        struct uvc_device *dev = container_of(kref, struct uvc_device, kref);
        struct list_head *p, *n;
 
-       /* Unregister the video device. */
+       /* Unregister the video devices. */
        uvc_unregister_video(dev);
        usb_put_intf(dev->intf);
        usb_put_dev(dev->udev);
@@ -1552,13 +1682,19 @@ void uvc_delete(struct kref *kref)
        uvc_status_cleanup(dev);
        uvc_ctrl_cleanup_device(dev);
 
+       list_for_each_safe(p, n, &dev->chains) {
+               struct uvc_video_chain *chain;
+               chain = list_entry(p, struct uvc_video_chain, list);
+               kfree(chain);
+       }
+
        list_for_each_safe(p, n, &dev->entities) {
                struct uvc_entity *entity;
                entity = list_entry(p, struct uvc_entity, list);
                kfree(entity);
        }
 
-       list_for_each_safe(p, n, &dev->streaming) {
+       list_for_each_safe(p, n, &dev->streams) {
                struct uvc_streaming *streaming;
                streaming = list_entry(p, struct uvc_streaming, list);
                usb_driver_release_interface(&uvc_driver.driver,
@@ -1592,7 +1728,8 @@ static int uvc_probe(struct usb_interface *intf,
                return -ENOMEM;
 
        INIT_LIST_HEAD(&dev->entities);
-       INIT_LIST_HEAD(&dev->streaming);
+       INIT_LIST_HEAD(&dev->chains);
+       INIT_LIST_HEAD(&dev->streams);
        kref_init(&dev->kref);
        atomic_set(&dev->users, 0);
 
@@ -1633,8 +1770,12 @@ static int uvc_probe(struct usb_interface *intf,
        if (uvc_ctrl_init_device(dev) < 0)
                goto error;
 
-       /* Register the video devices. */
-       if (uvc_register_video(dev) < 0)
+       /* Scan the device for video chains. */
+       if (uvc_scan_device(dev) < 0)
+               goto error;
+
+       /* Register video devices. */
+       if (uvc_register_chains(dev) < 0)
                goto error;
 
        /* Save our data pointer in the interface data. */
@@ -1664,7 +1805,8 @@ static void uvc_disconnect(struct usb_interface *intf)
         */
        usb_set_intfdata(intf, NULL);
 
-       if (intf->cur_altsetting->desc.bInterfaceSubClass == SC_VIDEOSTREAMING)
+       if (intf->cur_altsetting->desc.bInterfaceSubClass ==
+           UVC_SC_VIDEOSTREAMING)
                return;
 
        /* uvc_v4l2_open() might race uvc_disconnect(). A static driver-wide
@@ -1687,31 +1829,36 @@ static void uvc_disconnect(struct usb_interface *intf)
 static int uvc_suspend(struct usb_interface *intf, pm_message_t message)
 {
        struct uvc_device *dev = usb_get_intfdata(intf);
+       struct uvc_streaming *stream;
 
        uvc_trace(UVC_TRACE_SUSPEND, "Suspending interface %u\n",
                intf->cur_altsetting->desc.bInterfaceNumber);
 
        /* Controls are cached on the fly so they don't need to be saved. */
-       if (intf->cur_altsetting->desc.bInterfaceSubClass == SC_VIDEOCONTROL)
+       if (intf->cur_altsetting->desc.bInterfaceSubClass ==
+           UVC_SC_VIDEOCONTROL)
                return uvc_status_suspend(dev);
 
-       if (dev->video.streaming->intf != intf) {
-               uvc_trace(UVC_TRACE_SUSPEND, "Suspend: video streaming USB "
-                               "interface mismatch.\n");
-               return -EINVAL;
+       list_for_each_entry(stream, &dev->streams, list) {
+               if (stream->intf == intf)
+                       return uvc_video_suspend(stream);
        }
 
-       return uvc_video_suspend(&dev->video);
+       uvc_trace(UVC_TRACE_SUSPEND, "Suspend: video streaming USB interface "
+                       "mismatch.\n");
+       return -EINVAL;
 }
 
 static int __uvc_resume(struct usb_interface *intf, int reset)
 {
        struct uvc_device *dev = usb_get_intfdata(intf);
+       struct uvc_streaming *stream;
 
        uvc_trace(UVC_TRACE_SUSPEND, "Resuming interface %u\n",
                intf->cur_altsetting->desc.bInterfaceNumber);
 
-       if (intf->cur_altsetting->desc.bInterfaceSubClass == SC_VIDEOCONTROL) {
+       if (intf->cur_altsetting->desc.bInterfaceSubClass ==
+           UVC_SC_VIDEOCONTROL) {
                if (reset) {
                        int ret = uvc_ctrl_resume_device(dev);
 
@@ -1722,13 +1869,14 @@ static int __uvc_resume(struct usb_interface *intf, int reset)
                return uvc_status_resume(dev);
        }
 
-       if (dev->video.streaming->intf != intf) {
-               uvc_trace(UVC_TRACE_SUSPEND, "Resume: video streaming USB "
-                               "interface mismatch.\n");
-               return -EINVAL;
+       list_for_each_entry(stream, &dev->streams, list) {
+               if (stream->intf == intf)
+                       return uvc_video_resume(stream);
        }
 
-       return uvc_video_resume(&dev->video);
+       uvc_trace(UVC_TRACE_SUSPEND, "Resume: video streaming USB interface "
+                       "mismatch.\n");
+       return -EINVAL;
 }
 
 static int uvc_resume(struct usb_interface *intf)
@@ -1880,7 +2028,8 @@ static struct usb_device_id uvc_ids[] = {
          .bInterfaceClass      = USB_CLASS_VIDEO,
          .bInterfaceSubClass   = 1,
          .bInterfaceProtocol   = 0,
-         .driver_info          = UVC_QUIRK_PROBE_MINMAX },
+         .driver_info          = UVC_QUIRK_PROBE_MINMAX
+                               | UVC_QUIRK_PROBE_DEF },
        /* Syntek (HP Spartan) */
        { .match_flags          = USB_DEVICE_ID_MATCH_DEVICE
                                | USB_DEVICE_ID_MATCH_INT_INFO,
@@ -1943,7 +2092,8 @@ static struct usb_device_id uvc_ids[] = {
          .bInterfaceClass      = USB_CLASS_VIDEO,
          .bInterfaceSubClass   = 1,
          .bInterfaceProtocol   = 0,
-         .driver_info          = UVC_QUIRK_PROBE_EXTRAFIELDS },
+         .driver_info          = UVC_QUIRK_PROBE_MINMAX
+                               | UVC_QUIRK_PROBE_EXTRAFIELDS },
        /* Ecamm Pico iMage */
        { .match_flags          = USB_DEVICE_ID_MATCH_DEVICE
                                | USB_DEVICE_ID_MATCH_INT_INFO,
index 436f462685a09adb3e959e1f92c5b5f3bb0ae9eb..a9285b570dbe0f1defaaef3d273c347ef36b60b3 100644 (file)
@@ -99,7 +99,7 @@ static int isight_decode(struct uvc_video_queue *queue, struct uvc_buffer *buf,
        return 0;
 }
 
-void uvc_video_decode_isight(struct urb *urb, struct uvc_video_device *video,
+void uvc_video_decode_isight(struct urb *urb, struct uvc_streaming *stream,
                struct uvc_buffer *buf)
 {
        int ret, i;
@@ -120,7 +120,7 @@ void uvc_video_decode_isight(struct urb *urb, struct uvc_video_device *video,
                 * processes the data of the first payload of the new frame.
                 */
                do {
-                       ret = isight_decode(&video->queue, buf,
+                       ret = isight_decode(&stream->queue, buf,
                                        urb->transfer_buffer +
                                        urb->iso_frame_desc[i].offset,
                                        urb->iso_frame_desc[i].actual_length);
@@ -130,7 +130,8 @@ void uvc_video_decode_isight(struct urb *urb, struct uvc_video_device *video,
 
                        if (buf->state == UVC_BUF_STATE_DONE ||
                            buf->state == UVC_BUF_STATE_ERROR)
-                               buf = uvc_queue_next_buffer(&video->queue, buf);
+                               buf = uvc_queue_next_buffer(&stream->queue,
+                                                       buf);
                } while (ret == -EAGAIN);
        }
 }
index 5e77cad29690112bb734486a62e8b766f0eebb6e..9e7351569b5dc63498dad2982dba5cddb0db6b41 100644 (file)
@@ -40,7 +40,7 @@
  * table for the controls that can be mapped directly, and handle the others
  * manually.
  */
-static int uvc_v4l2_query_menu(struct uvc_video_device *video,
+static int uvc_v4l2_query_menu(struct uvc_video_chain *chain,
        struct v4l2_querymenu *query_menu)
 {
        struct uvc_menu_info *menu_info;
@@ -49,7 +49,7 @@ static int uvc_v4l2_query_menu(struct uvc_video_device *video,
        u32 index = query_menu->index;
        u32 id = query_menu->id;
 
-       ctrl = uvc_find_control(video, query_menu->id, &mapping);
+       ctrl = uvc_find_control(chain, query_menu->id, &mapping);
        if (ctrl == NULL || mapping->v4l2_type != V4L2_CTRL_TYPE_MENU)
                return -EINVAL;
 
@@ -103,7 +103,7 @@ static __u32 uvc_try_frame_interval(struct uvc_frame *frame, __u32 interval)
        return interval;
 }
 
-static int uvc_v4l2_try_format(struct uvc_video_device *video,
+static int uvc_v4l2_try_format(struct uvc_streaming *stream,
        struct v4l2_format *fmt, struct uvc_streaming_control *probe,
        struct uvc_format **uvc_format, struct uvc_frame **uvc_frame)
 {
@@ -116,7 +116,7 @@ static int uvc_v4l2_try_format(struct uvc_video_device *video,
        int ret = 0;
        __u8 *fcc;
 
-       if (fmt->type != video->streaming->type)
+       if (fmt->type != stream->type)
                return -EINVAL;
 
        fcc = (__u8 *)&fmt->fmt.pix.pixelformat;
@@ -126,8 +126,8 @@ static int uvc_v4l2_try_format(struct uvc_video_device *video,
                        fmt->fmt.pix.width, fmt->fmt.pix.height);
 
        /* Check if the hardware supports the requested format. */
-       for (i = 0; i < video->streaming->nformats; ++i) {
-               format = &video->streaming->format[i];
+       for (i = 0; i < stream->nformats; ++i) {
+               format = &stream->format[i];
                if (format->fcc == fmt->fmt.pix.pixelformat)
                        break;
        }
@@ -191,12 +191,13 @@ static int uvc_v4l2_try_format(struct uvc_video_device *video,
         * developers test their webcams with the Linux driver as well as with
         * the Windows driver).
         */
-       if (video->dev->quirks & UVC_QUIRK_PROBE_EXTRAFIELDS)
+       if (stream->dev->quirks & UVC_QUIRK_PROBE_EXTRAFIELDS)
                probe->dwMaxVideoFrameSize =
-                       video->streaming->ctrl.dwMaxVideoFrameSize;
+                       stream->ctrl.dwMaxVideoFrameSize;
 
        /* Probe the device. */
-       if ((ret = uvc_probe_video(video, probe)) < 0)
+       ret = uvc_probe_video(stream, probe);
+       if (ret < 0)
                goto done;
 
        fmt->fmt.pix.width = frame->wWidth;
@@ -216,13 +217,13 @@ done:
        return ret;
 }
 
-static int uvc_v4l2_get_format(struct uvc_video_device *video,
+static int uvc_v4l2_get_format(struct uvc_streaming *stream,
        struct v4l2_format *fmt)
 {
-       struct uvc_format *format = video->streaming->cur_format;
-       struct uvc_frame *frame = video->streaming->cur_frame;
+       struct uvc_format *format = stream->cur_format;
+       struct uvc_frame *frame = stream->cur_frame;
 
-       if (fmt->type != video->streaming->type)
+       if (fmt->type != stream->type)
                return -EINVAL;
 
        if (format == NULL || frame == NULL)
@@ -233,14 +234,14 @@ static int uvc_v4l2_get_format(struct uvc_video_device *video,
        fmt->fmt.pix.height = frame->wHeight;
        fmt->fmt.pix.field = V4L2_FIELD_NONE;
        fmt->fmt.pix.bytesperline = format->bpp * frame->wWidth / 8;
-       fmt->fmt.pix.sizeimage = video->streaming->ctrl.dwMaxVideoFrameSize;
+       fmt->fmt.pix.sizeimage = stream->ctrl.dwMaxVideoFrameSize;
        fmt->fmt.pix.colorspace = format->colorspace;
        fmt->fmt.pix.priv = 0;
 
        return 0;
 }
 
-static int uvc_v4l2_set_format(struct uvc_video_device *video,
+static int uvc_v4l2_set_format(struct uvc_streaming *stream,
        struct v4l2_format *fmt)
 {
        struct uvc_streaming_control probe;
@@ -248,39 +249,39 @@ static int uvc_v4l2_set_format(struct uvc_video_device *video,
        struct uvc_frame *frame;
        int ret;
 
-       if (fmt->type != video->streaming->type)
+       if (fmt->type != stream->type)
                return -EINVAL;
 
-       if (uvc_queue_allocated(&video->queue))
+       if (uvc_queue_allocated(&stream->queue))
                return -EBUSY;
 
-       ret = uvc_v4l2_try_format(video, fmt, &probe, &format, &frame);
+       ret = uvc_v4l2_try_format(stream, fmt, &probe, &format, &frame);
        if (ret < 0)
                return ret;
 
-       memcpy(&video->streaming->ctrl, &probe, sizeof probe);
-       video->streaming->cur_format = format;
-       video->streaming->cur_frame = frame;
+       memcpy(&stream->ctrl, &probe, sizeof probe);
+       stream->cur_format = format;
+       stream->cur_frame = frame;
 
        return 0;
 }
 
-static int uvc_v4l2_get_streamparm(struct uvc_video_device *video,
+static int uvc_v4l2_get_streamparm(struct uvc_streaming *stream,
                struct v4l2_streamparm *parm)
 {
        uint32_t numerator, denominator;
 
-       if (parm->type != video->streaming->type)
+       if (parm->type != stream->type)
                return -EINVAL;
 
-       numerator = video->streaming->ctrl.dwFrameInterval;
+       numerator = stream->ctrl.dwFrameInterval;
        denominator = 10000000;
        uvc_simplify_fraction(&numerator, &denominator, 8, 333);
 
        memset(parm, 0, sizeof *parm);
-       parm->type = video->streaming->type;
+       parm->type = stream->type;
 
-       if (video->streaming->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) {
+       if (stream->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) {
                parm->parm.capture.capability = V4L2_CAP_TIMEPERFRAME;
                parm->parm.capture.capturemode = 0;
                parm->parm.capture.timeperframe.numerator = numerator;
@@ -297,19 +298,19 @@ static int uvc_v4l2_get_streamparm(struct uvc_video_device *video,
        return 0;
 }
 
-static int uvc_v4l2_set_streamparm(struct uvc_video_device *video,
+static int uvc_v4l2_set_streamparm(struct uvc_streaming *stream,
                struct v4l2_streamparm *parm)
 {
-       struct uvc_frame *frame = video->streaming->cur_frame;
+       struct uvc_frame *frame = stream->cur_frame;
        struct uvc_streaming_control probe;
        struct v4l2_fract timeperframe;
        uint32_t interval;
        int ret;
 
-       if (parm->type != video->streaming->type)
+       if (parm->type != stream->type)
                return -EINVAL;
 
-       if (uvc_queue_streaming(&video->queue))
+       if (uvc_queue_streaming(&stream->queue))
                return -EBUSY;
 
        if (parm->type == V4L2_BUF_TYPE_VIDEO_CAPTURE)
@@ -317,7 +318,7 @@ static int uvc_v4l2_set_streamparm(struct uvc_video_device *video,
        else
                timeperframe = parm->parm.output.timeperframe;
 
-       memcpy(&probe, &video->streaming->ctrl, sizeof probe);
+       memcpy(&probe, &stream->ctrl, sizeof probe);
        interval = uvc_fraction_to_interval(timeperframe.numerator,
                timeperframe.denominator);
 
@@ -326,10 +327,11 @@ static int uvc_v4l2_set_streamparm(struct uvc_video_device *video,
        probe.dwFrameInterval = uvc_try_frame_interval(frame, interval);
 
        /* Probe the device with the new settings. */
-       if ((ret = uvc_probe_video(video, &probe)) < 0)
+       ret = uvc_probe_video(stream, &probe);
+       if (ret < 0)
                return ret;
 
-       memcpy(&video->streaming->ctrl, &probe, sizeof probe);
+       memcpy(&stream->ctrl, &probe, sizeof probe);
 
        /* Return the actual frame period. */
        timeperframe.numerator = probe.dwFrameInterval;
@@ -382,8 +384,8 @@ static int uvc_acquire_privileges(struct uvc_fh *handle)
 
        /* Check if the device already has a privileged handle. */
        mutex_lock(&uvc_driver.open_mutex);
-       if (atomic_inc_return(&handle->device->active) != 1) {
-               atomic_dec(&handle->device->active);
+       if (atomic_inc_return(&handle->stream->active) != 1) {
+               atomic_dec(&handle->stream->active);
                ret = -EBUSY;
                goto done;
        }
@@ -398,7 +400,7 @@ done:
 static void uvc_dismiss_privileges(struct uvc_fh *handle)
 {
        if (handle->state == UVC_HANDLE_ACTIVE)
-               atomic_dec(&handle->device->active);
+               atomic_dec(&handle->stream->active);
 
        handle->state = UVC_HANDLE_PASSIVE;
 }
@@ -414,45 +416,47 @@ static int uvc_has_privileges(struct uvc_fh *handle)
 
 static int uvc_v4l2_open(struct file *file)
 {
-       struct uvc_video_device *video;
+       struct uvc_streaming *stream;
        struct uvc_fh *handle;
        int ret = 0;
 
        uvc_trace(UVC_TRACE_CALLS, "uvc_v4l2_open\n");
        mutex_lock(&uvc_driver.open_mutex);
-       video = video_drvdata(file);
+       stream = video_drvdata(file);
 
-       if (video->dev->state & UVC_DEV_DISCONNECTED) {
+       if (stream->dev->state & UVC_DEV_DISCONNECTED) {
                ret = -ENODEV;
                goto done;
        }
 
-       ret = usb_autopm_get_interface(video->dev->intf);
+       ret = usb_autopm_get_interface(stream->dev->intf);
        if (ret < 0)
                goto done;
 
        /* Create the device handle. */
        handle = kzalloc(sizeof *handle, GFP_KERNEL);
        if (handle == NULL) {
-               usb_autopm_put_interface(video->dev->intf);
+               usb_autopm_put_interface(stream->dev->intf);
                ret = -ENOMEM;
                goto done;
        }
 
-       if (atomic_inc_return(&video->dev->users) == 1) {
-               if ((ret = uvc_status_start(video->dev)) < 0) {
-                       usb_autopm_put_interface(video->dev->intf);
-                       atomic_dec(&video->dev->users);
+       if (atomic_inc_return(&stream->dev->users) == 1) {
+               ret = uvc_status_start(stream->dev);
+               if (ret < 0) {
+                       usb_autopm_put_interface(stream->dev->intf);
+                       atomic_dec(&stream->dev->users);
                        kfree(handle);
                        goto done;
                }
        }
 
-       handle->device = video;
+       handle->chain = stream->chain;
+       handle->stream = stream;
        handle->state = UVC_HANDLE_PASSIVE;
        file->private_data = handle;
 
-       kref_get(&video->dev->kref);
+       kref_get(&stream->dev->kref);
 
 done:
        mutex_unlock(&uvc_driver.open_mutex);
@@ -461,20 +465,20 @@ done:
 
 static int uvc_v4l2_release(struct file *file)
 {
-       struct uvc_video_device *video = video_drvdata(file);
        struct uvc_fh *handle = (struct uvc_fh *)file->private_data;
+       struct uvc_streaming *stream = handle->stream;
 
        uvc_trace(UVC_TRACE_CALLS, "uvc_v4l2_release\n");
 
        /* Only free resources if this is a privileged handle. */
        if (uvc_has_privileges(handle)) {
-               uvc_video_enable(video, 0);
+               uvc_video_enable(stream, 0);
 
-               mutex_lock(&video->queue.mutex);
-               if (uvc_free_buffers(&video->queue) < 0)
+               mutex_lock(&stream->queue.mutex);
+               if (uvc_free_buffers(&stream->queue) < 0)
                        uvc_printk(KERN_ERR, "uvc_v4l2_release: Unable to "
                                        "free buffers.\n");
-               mutex_unlock(&video->queue.mutex);
+               mutex_unlock(&stream->queue.mutex);
        }
 
        /* Release the file handle. */
@@ -482,19 +486,20 @@ static int uvc_v4l2_release(struct file *file)
        kfree(handle);
        file->private_data = NULL;
 
-       if (atomic_dec_return(&video->dev->users) == 0)
-               uvc_status_stop(video->dev);
+       if (atomic_dec_return(&stream->dev->users) == 0)
+               uvc_status_stop(stream->dev);
 
-       usb_autopm_put_interface(video->dev->intf);
-       kref_put(&video->dev->kref, uvc_delete);
+       usb_autopm_put_interface(stream->dev->intf);
+       kref_put(&stream->dev->kref, uvc_delete);
        return 0;
 }
 
 static long uvc_v4l2_do_ioctl(struct file *file, unsigned int cmd, void *arg)
 {
        struct video_device *vdev = video_devdata(file);
-       struct uvc_video_device *video = video_get_drvdata(vdev);
        struct uvc_fh *handle = (struct uvc_fh *)file->private_data;
+       struct uvc_video_chain *chain = handle->chain;
+       struct uvc_streaming *stream = handle->stream;
        long ret = 0;
 
        switch (cmd) {
@@ -506,10 +511,10 @@ static long uvc_v4l2_do_ioctl(struct file *file, unsigned int cmd, void *arg)
                memset(cap, 0, sizeof *cap);
                strlcpy(cap->driver, "uvcvideo", sizeof cap->driver);
                strlcpy(cap->card, vdev->name, sizeof cap->card);
-               usb_make_path(video->dev->udev,
+               usb_make_path(stream->dev->udev,
                              cap->bus_info, sizeof(cap->bus_info));
                cap->version = DRIVER_VERSION_NUMBER;
-               if (video->streaming->type == V4L2_BUF_TYPE_VIDEO_CAPTURE)
+               if (stream->type == V4L2_BUF_TYPE_VIDEO_CAPTURE)
                        cap->capabilities = V4L2_CAP_VIDEO_CAPTURE
                                          | V4L2_CAP_STREAMING;
                else
@@ -520,7 +525,7 @@ static long uvc_v4l2_do_ioctl(struct file *file, unsigned int cmd, void *arg)
 
        /* Get, Set & Query control */
        case VIDIOC_QUERYCTRL:
-               return uvc_query_v4l2_ctrl(video, arg);
+               return uvc_query_v4l2_ctrl(chain, arg);
 
        case VIDIOC_G_CTRL:
        {
@@ -530,12 +535,12 @@ static long uvc_v4l2_do_ioctl(struct file *file, unsigned int cmd, void *arg)
                memset(&xctrl, 0, sizeof xctrl);
                xctrl.id = ctrl->id;
 
-              ret = uvc_ctrl_begin(video);
-              if (ret < 0)
+               ret = uvc_ctrl_begin(chain);
+               if (ret < 0)
                        return ret;
 
-               ret = uvc_ctrl_get(video, &xctrl);
-               uvc_ctrl_rollback(video);
+               ret = uvc_ctrl_get(chain, &xctrl);
+               uvc_ctrl_rollback(chain);
                if (ret >= 0)
                        ctrl->value = xctrl.value;
                break;
@@ -550,21 +555,21 @@ static long uvc_v4l2_do_ioctl(struct file *file, unsigned int cmd, void *arg)
                xctrl.id = ctrl->id;
                xctrl.value = ctrl->value;
 
-              ret = uvc_ctrl_begin(video);
-              if (ret < 0)
+               uvc_ctrl_begin(chain);
+               if (ret < 0)
                        return ret;
 
-               ret = uvc_ctrl_set(video, &xctrl);
+               ret = uvc_ctrl_set(chain, &xctrl);
                if (ret < 0) {
-                       uvc_ctrl_rollback(video);
+                       uvc_ctrl_rollback(chain);
                        return ret;
                }
-               ret = uvc_ctrl_commit(video);
+               ret = uvc_ctrl_commit(chain);
                break;
        }
 
        case VIDIOC_QUERYMENU:
-               return uvc_v4l2_query_menu(video, arg);
+               return uvc_v4l2_query_menu(chain, arg);
 
        case VIDIOC_G_EXT_CTRLS:
        {
@@ -572,20 +577,20 @@ static long uvc_v4l2_do_ioctl(struct file *file, unsigned int cmd, void *arg)
                struct v4l2_ext_control *ctrl = ctrls->controls;
                unsigned int i;
 
-              ret = uvc_ctrl_begin(video);
-              if (ret < 0)
+               ret = uvc_ctrl_begin(chain);
+               if (ret < 0)
                        return ret;
 
                for (i = 0; i < ctrls->count; ++ctrl, ++i) {
-                       ret = uvc_ctrl_get(video, ctrl);
+                       ret = uvc_ctrl_get(chain, ctrl);
                        if (ret < 0) {
-                               uvc_ctrl_rollback(video);
+                               uvc_ctrl_rollback(chain);
                                ctrls->error_idx = i;
                                return ret;
                        }
                }
                ctrls->error_idx = 0;
-               ret = uvc_ctrl_rollback(video);
+               ret = uvc_ctrl_rollback(chain);
                break;
        }
 
@@ -596,14 +601,14 @@ static long uvc_v4l2_do_ioctl(struct file *file, unsigned int cmd, void *arg)
                struct v4l2_ext_control *ctrl = ctrls->controls;
                unsigned int i;
 
-               ret = uvc_ctrl_begin(video);
+               ret = uvc_ctrl_begin(chain);
                if (ret < 0)
                        return ret;
 
                for (i = 0; i < ctrls->count; ++ctrl, ++i) {
-                       ret = uvc_ctrl_set(video, ctrl);
+                       ret = uvc_ctrl_set(chain, ctrl);
                        if (ret < 0) {
-                               uvc_ctrl_rollback(video);
+                               uvc_ctrl_rollback(chain);
                                ctrls->error_idx = i;
                                return ret;
                        }
@@ -612,31 +617,31 @@ static long uvc_v4l2_do_ioctl(struct file *file, unsigned int cmd, void *arg)
                ctrls->error_idx = 0;
 
                if (cmd == VIDIOC_S_EXT_CTRLS)
-                       ret = uvc_ctrl_commit(video);
+                       ret = uvc_ctrl_commit(chain);
                else
-                       ret = uvc_ctrl_rollback(video);
+                       ret = uvc_ctrl_rollback(chain);
                break;
        }
 
        /* Get, Set & Enum input */
        case VIDIOC_ENUMINPUT:
        {
-               const struct uvc_entity *selector = video->selector;
+               const struct uvc_entity *selector = chain->selector;
                struct v4l2_input *input = arg;
                struct uvc_entity *iterm = NULL;
                u32 index = input->index;
                int pin = 0;
 
                if (selector == NULL ||
-                   (video->dev->quirks & UVC_QUIRK_IGNORE_SELECTOR_UNIT)) {
+                   (chain->dev->quirks & UVC_QUIRK_IGNORE_SELECTOR_UNIT)) {
                        if (index != 0)
                                return -EINVAL;
-                       iterm = list_first_entry(&video->iterms,
+                       iterm = list_first_entry(&chain->iterms,
                                        struct uvc_entity, chain);
                        pin = iterm->id;
                } else if (pin < selector->selector.bNrInPins) {
                        pin = selector->selector.baSourceID[index];
-                       list_for_each_entry(iterm, video->iterms.next, chain) {
+                       list_for_each_entry(iterm, chain->iterms.next, chain) {
                                if (iterm->id == pin)
                                        break;
                        }
@@ -648,7 +653,7 @@ static long uvc_v4l2_do_ioctl(struct file *file, unsigned int cmd, void *arg)
                memset(input, 0, sizeof *input);
                input->index = index;
                strlcpy(input->name, iterm->name, sizeof input->name);
-               if (UVC_ENTITY_TYPE(iterm) == ITT_CAMERA)
+               if (UVC_ENTITY_TYPE(iterm) == UVC_ITT_CAMERA)
                        input->type = V4L2_INPUT_TYPE_CAMERA;
                break;
        }
@@ -657,15 +662,15 @@ static long uvc_v4l2_do_ioctl(struct file *file, unsigned int cmd, void *arg)
        {
                u8 input;
 
-               if (video->selector == NULL ||
-                   (video->dev->quirks & UVC_QUIRK_IGNORE_SELECTOR_UNIT)) {
+               if (chain->selector == NULL ||
+                   (chain->dev->quirks & UVC_QUIRK_IGNORE_SELECTOR_UNIT)) {
                        *(int *)arg = 0;
                        break;
                }
 
-               ret = uvc_query_ctrl(video->dev, GET_CUR, video->selector->id,
-                       video->dev->intfnum, SU_INPUT_SELECT_CONTROL,
-                       &input, 1);
+               ret = uvc_query_ctrl(chain->dev, UVC_GET_CUR,
+                       chain->selector->id, chain->dev->intfnum,
+                       UVC_SU_INPUT_SELECT_CONTROL, &input, 1);
                if (ret < 0)
                        return ret;
 
@@ -680,19 +685,19 @@ static long uvc_v4l2_do_ioctl(struct file *file, unsigned int cmd, void *arg)
                if ((ret = uvc_acquire_privileges(handle)) < 0)
                        return ret;
 
-               if (video->selector == NULL ||
-                   (video->dev->quirks & UVC_QUIRK_IGNORE_SELECTOR_UNIT)) {
+               if (chain->selector == NULL ||
+                   (chain->dev->quirks & UVC_QUIRK_IGNORE_SELECTOR_UNIT)) {
                        if (input != 1)
                                return -EINVAL;
                        break;
                }
 
-               if (input == 0 || input > video->selector->selector.bNrInPins)
+               if (input == 0 || input > chain->selector->selector.bNrInPins)
                        return -EINVAL;
 
-               return uvc_query_ctrl(video->dev, SET_CUR, video->selector->id,
-                       video->dev->intfnum, SU_INPUT_SELECT_CONTROL,
-                       &input, 1);
+               return uvc_query_ctrl(chain->dev, UVC_SET_CUR,
+                       chain->selector->id, chain->dev->intfnum,
+                       UVC_SU_INPUT_SELECT_CONTROL, &input, 1);
        }
 
        /* Try, Get, Set & Enum format */
@@ -703,15 +708,15 @@ static long uvc_v4l2_do_ioctl(struct file *file, unsigned int cmd, void *arg)
                enum v4l2_buf_type type = fmt->type;
                __u32 index = fmt->index;
 
-               if (fmt->type != video->streaming->type ||
-                   fmt->index >= video->streaming->nformats)
+               if (fmt->type != stream->type ||
+                   fmt->index >= stream->nformats)
                        return -EINVAL;
 
                memset(fmt, 0, sizeof(*fmt));
                fmt->index = index;
                fmt->type = type;
 
-               format = &video->streaming->format[fmt->index];
+               format = &stream->format[fmt->index];
                fmt->flags = 0;
                if (format->flags & UVC_FMT_FLAG_COMPRESSED)
                        fmt->flags |= V4L2_FMT_FLAG_COMPRESSED;
@@ -729,17 +734,17 @@ static long uvc_v4l2_do_ioctl(struct file *file, unsigned int cmd, void *arg)
                if ((ret = uvc_acquire_privileges(handle)) < 0)
                        return ret;
 
-               return uvc_v4l2_try_format(video, arg, &probe, NULL, NULL);
+               return uvc_v4l2_try_format(stream, arg, &probe, NULL, NULL);
        }
 
        case VIDIOC_S_FMT:
                if ((ret = uvc_acquire_privileges(handle)) < 0)
                        return ret;
 
-               return uvc_v4l2_set_format(video, arg);
+               return uvc_v4l2_set_format(stream, arg);
 
        case VIDIOC_G_FMT:
-               return uvc_v4l2_get_format(video, arg);
+               return uvc_v4l2_get_format(stream, arg);
 
        /* Frame size enumeration */
        case VIDIOC_ENUM_FRAMESIZES:
@@ -750,10 +755,10 @@ static long uvc_v4l2_do_ioctl(struct file *file, unsigned int cmd, void *arg)
                int i;
 
                /* Look for the given pixel format */
-               for (i = 0; i < video->streaming->nformats; i++) {
-                       if (video->streaming->format[i].fcc ==
+               for (i = 0; i < stream->nformats; i++) {
+                       if (stream->format[i].fcc ==
                                        fsize->pixel_format) {
-                               format = &video->streaming->format[i];
+                               format = &stream->format[i];
                                break;
                        }
                }
@@ -779,10 +784,10 @@ static long uvc_v4l2_do_ioctl(struct file *file, unsigned int cmd, void *arg)
                int i;
 
                /* Look for the given pixel format and frame size */
-               for (i = 0; i < video->streaming->nformats; i++) {
-                       if (video->streaming->format[i].fcc ==
+               for (i = 0; i < stream->nformats; i++) {
+                       if (stream->format[i].fcc ==
                                        fival->pixel_format) {
-                               format = &video->streaming->format[i];
+                               format = &stream->format[i];
                                break;
                        }
                }
@@ -832,21 +837,21 @@ static long uvc_v4l2_do_ioctl(struct file *file, unsigned int cmd, void *arg)
 
        /* Get & Set streaming parameters */
        case VIDIOC_G_PARM:
-               return uvc_v4l2_get_streamparm(video, arg);
+               return uvc_v4l2_get_streamparm(stream, arg);
 
        case VIDIOC_S_PARM:
                if ((ret = uvc_acquire_privileges(handle)) < 0)
                        return ret;
 
-               return uvc_v4l2_set_streamparm(video, arg);
+               return uvc_v4l2_set_streamparm(stream, arg);
 
        /* Cropping and scaling */
        case VIDIOC_CROPCAP:
        {
                struct v4l2_cropcap *ccap = arg;
-               struct uvc_frame *frame = video->streaming->cur_frame;
+               struct uvc_frame *frame = stream->cur_frame;
 
-               if (ccap->type != video->streaming->type)
+               if (ccap->type != stream->type)
                        return -EINVAL;
 
                ccap->bounds.left = 0;
@@ -870,16 +875,16 @@ static long uvc_v4l2_do_ioctl(struct file *file, unsigned int cmd, void *arg)
        {
                struct v4l2_requestbuffers *rb = arg;
                unsigned int bufsize =
-                       video->streaming->ctrl.dwMaxVideoFrameSize;
+                       stream->ctrl.dwMaxVideoFrameSize;
 
-               if (rb->type != video->streaming->type ||
+               if (rb->type != stream->type ||
                    rb->memory != V4L2_MEMORY_MMAP)
                        return -EINVAL;
 
                if ((ret = uvc_acquire_privileges(handle)) < 0)
                        return ret;
 
-               ret = uvc_alloc_buffers(&video->queue, rb->count, bufsize);
+               ret = uvc_alloc_buffers(&stream->queue, rb->count, bufsize);
                if (ret < 0)
                        return ret;
 
@@ -892,39 +897,40 @@ static long uvc_v4l2_do_ioctl(struct file *file, unsigned int cmd, void *arg)
        {
                struct v4l2_buffer *buf = arg;
 
-               if (buf->type != video->streaming->type)
+               if (buf->type != stream->type)
                        return -EINVAL;
 
                if (!uvc_has_privileges(handle))
                        return -EBUSY;
 
-               return uvc_query_buffer(&video->queue, buf);
+               return uvc_query_buffer(&stream->queue, buf);
        }
 
        case VIDIOC_QBUF:
                if (!uvc_has_privileges(handle))
                        return -EBUSY;
 
-               return uvc_queue_buffer(&video->queue, arg);
+               return uvc_queue_buffer(&stream->queue, arg);
 
        case VIDIOC_DQBUF:
                if (!uvc_has_privileges(handle))
                        return -EBUSY;
 
-               return uvc_dequeue_buffer(&video->queue, arg,
+               return uvc_dequeue_buffer(&stream->queue, arg,
                        file->f_flags & O_NONBLOCK);
 
        case VIDIOC_STREAMON:
        {
                int *type = arg;
 
-               if (*type != video->streaming->type)
+               if (*type != stream->type)
                        return -EINVAL;
 
                if (!uvc_has_privileges(handle))
                        return -EBUSY;
 
-               if ((ret = uvc_video_enable(video, 1)) < 0)
+               ret = uvc_video_enable(stream, 1);
+               if (ret < 0)
                        return ret;
                break;
        }
@@ -933,13 +939,13 @@ static long uvc_v4l2_do_ioctl(struct file *file, unsigned int cmd, void *arg)
        {
                int *type = arg;
 
-               if (*type != video->streaming->type)
+               if (*type != stream->type)
                        return -EINVAL;
 
                if (!uvc_has_privileges(handle))
                        return -EBUSY;
 
-               return uvc_video_enable(video, 0);
+               return uvc_video_enable(stream, 0);
        }
 
        /* Analog video standards make no sense for digital cameras. */
@@ -1013,10 +1019,10 @@ static long uvc_v4l2_do_ioctl(struct file *file, unsigned int cmd, void *arg)
        }
 
        case UVCIOC_CTRL_GET:
-               return uvc_xu_ctrl_query(video, arg, 0);
+               return uvc_xu_ctrl_query(chain, arg, 0);
 
        case UVCIOC_CTRL_SET:
-               return uvc_xu_ctrl_query(video, arg, 1);
+               return uvc_xu_ctrl_query(chain, arg, 1);
 
        default:
                if ((ret = v4l_compat_translate_ioctl(file, cmd, arg,
@@ -1070,7 +1076,9 @@ static struct vm_operations_struct uvc_vm_ops = {
 
 static int uvc_v4l2_mmap(struct file *file, struct vm_area_struct *vma)
 {
-       struct uvc_video_device *video = video_drvdata(file);
+       struct uvc_fh *handle = (struct uvc_fh *)file->private_data;
+       struct uvc_streaming *stream = handle->stream;
+       struct uvc_video_queue *queue = &stream->queue;
        struct uvc_buffer *uninitialized_var(buffer);
        struct page *page;
        unsigned long addr, start, size;
@@ -1082,15 +1090,15 @@ static int uvc_v4l2_mmap(struct file *file, struct vm_area_struct *vma)
        start = vma->vm_start;
        size = vma->vm_end - vma->vm_start;
 
-       mutex_lock(&video->queue.mutex);
+       mutex_lock(&queue->mutex);
 
-       for (i = 0; i < video->queue.count; ++i) {
-               buffer = &video->queue.buffer[i];
+       for (i = 0; i < queue->count; ++i) {
+               buffer = &queue->buffer[i];
                if ((buffer->buf.m.offset >> PAGE_SHIFT) == vma->vm_pgoff)
                        break;
        }
 
-       if (i == video->queue.count || size != video->queue.buf_size) {
+       if (i == queue->count || size != queue->buf_size) {
                ret = -EINVAL;
                goto done;
        }
@@ -1101,7 +1109,7 @@ static int uvc_v4l2_mmap(struct file *file, struct vm_area_struct *vma)
         */
        vma->vm_flags |= VM_IO;
 
-       addr = (unsigned long)video->queue.mem + buffer->buf.m.offset;
+       addr = (unsigned long)queue->mem + buffer->buf.m.offset;
        while (size > 0) {
                page = vmalloc_to_page((void *)addr);
                if ((ret = vm_insert_page(vma, start, page)) < 0)
@@ -1117,17 +1125,18 @@ static int uvc_v4l2_mmap(struct file *file, struct vm_area_struct *vma)
        uvc_vm_open(vma);
 
 done:
-       mutex_unlock(&video->queue.mutex);
+       mutex_unlock(&queue->mutex);
        return ret;
 }
 
 static unsigned int uvc_v4l2_poll(struct file *file, poll_table *wait)
 {
-       struct uvc_video_device *video = video_drvdata(file);
+       struct uvc_fh *handle = (struct uvc_fh *)file->private_data;
+       struct uvc_streaming *stream = handle->stream;
 
        uvc_trace(UVC_TRACE_CALLS, "uvc_v4l2_poll\n");
 
-       return uvc_queue_poll(&video->queue, file, wait);
+       return uvc_queue_poll(&stream->queue, file, wait);
 }
 
 const struct v4l2_file_operations uvc_fops = {
index 01b633c734803ac3d4cf3b42a690cbedc51dc96f..5b757f32d997a237a1212623862332fa61cd8281 100644 (file)
@@ -61,7 +61,7 @@ int uvc_query_ctrl(struct uvc_device *dev, __u8 query, __u8 unit,
        return 0;
 }
 
-static void uvc_fixup_video_ctrl(struct uvc_video_device *video,
+static void uvc_fixup_video_ctrl(struct uvc_streaming *stream,
        struct uvc_streaming_control *ctrl)
 {
        struct uvc_format *format;
@@ -69,10 +69,10 @@ static void uvc_fixup_video_ctrl(struct uvc_video_device *video,
        unsigned int i;
 
        if (ctrl->bFormatIndex <= 0 ||
-           ctrl->bFormatIndex > video->streaming->nformats)
+           ctrl->bFormatIndex > stream->nformats)
                return;
 
-       format = &video->streaming->format[ctrl->bFormatIndex - 1];
+       format = &stream->format[ctrl->bFormatIndex - 1];
 
        for (i = 0; i < format->nframes; ++i) {
                if (format->frame[i].bFrameIndex == ctrl->bFrameIndex) {
@@ -86,12 +86,12 @@ static void uvc_fixup_video_ctrl(struct uvc_video_device *video,
 
        if (!(format->flags & UVC_FMT_FLAG_COMPRESSED) ||
             (ctrl->dwMaxVideoFrameSize == 0 &&
-             video->dev->uvc_version < 0x0110))
+             stream->dev->uvc_version < 0x0110))
                ctrl->dwMaxVideoFrameSize =
                        frame->dwMaxVideoFrameBufferSize;
 
-       if (video->dev->quirks & UVC_QUIRK_FIX_BANDWIDTH &&
-           video->streaming->intf->num_altsetting > 1) {
+       if (stream->dev->quirks & UVC_QUIRK_FIX_BANDWIDTH &&
+           stream->intf->num_altsetting > 1) {
                u32 interval;
                u32 bandwidth;
 
@@ -108,7 +108,7 @@ static void uvc_fixup_video_ctrl(struct uvc_video_device *video,
                bandwidth = frame->wWidth * frame->wHeight / 8 * format->bpp;
                bandwidth *= 10000000 / interval + 1;
                bandwidth /= 1000;
-               if (video->dev->udev->speed == USB_SPEED_HIGH)
+               if (stream->dev->udev->speed == USB_SPEED_HIGH)
                        bandwidth /= 8;
                bandwidth += 12;
 
@@ -116,40 +116,43 @@ static void uvc_fixup_video_ctrl(struct uvc_video_device *video,
        }
 }
 
-static int uvc_get_video_ctrl(struct uvc_video_device *video,
+static int uvc_get_video_ctrl(struct uvc_streaming *stream,
        struct uvc_streaming_control *ctrl, int probe, __u8 query)
 {
        __u8 *data;
        __u16 size;
        int ret;
 
-       size = video->dev->uvc_version >= 0x0110 ? 34 : 26;
+       size = stream->dev->uvc_version >= 0x0110 ? 34 : 26;
        data = kmalloc(size, GFP_KERNEL);
        if (data == NULL)
                return -ENOMEM;
 
-       ret = __uvc_query_ctrl(video->dev, query, 0, video->streaming->intfnum,
-               probe ? VS_PROBE_CONTROL : VS_COMMIT_CONTROL, data, size,
-               UVC_CTRL_STREAMING_TIMEOUT);
+       if ((stream->dev->quirks & UVC_QUIRK_PROBE_DEF) && query == UVC_GET_DEF)
+               return -EIO;
+
+       ret = __uvc_query_ctrl(stream->dev, query, 0, stream->intfnum,
+               probe ? UVC_VS_PROBE_CONTROL : UVC_VS_COMMIT_CONTROL, data,
+               size, UVC_CTRL_STREAMING_TIMEOUT);
 
-       if ((query == GET_MIN || query == GET_MAX) && ret == 2) {
+       if ((query == UVC_GET_MIN || query == UVC_GET_MAX) && ret == 2) {
                /* Some cameras, mostly based on Bison Electronics chipsets,
                 * answer a GET_MIN or GET_MAX request with the wCompQuality
                 * field only.
                 */
-               uvc_warn_once(video->dev, UVC_WARN_MINMAX, "UVC non "
+               uvc_warn_once(stream->dev, UVC_WARN_MINMAX, "UVC non "
                        "compliance - GET_MIN/MAX(PROBE) incorrectly "
                        "supported. Enabling workaround.\n");
                memset(ctrl, 0, sizeof ctrl);
                ctrl->wCompQuality = le16_to_cpup((__le16 *)data);
                ret = 0;
                goto out;
-       } else if (query == GET_DEF && probe == 1 && ret != size) {
+       } else if (query == UVC_GET_DEF && probe == 1 && ret != size) {
                /* Many cameras don't support the GET_DEF request on their
                 * video probe control. Warn once and return, the caller will
                 * fall back to GET_CUR.
                 */
-               uvc_warn_once(video->dev, UVC_WARN_PROBE_DEF, "UVC non "
+               uvc_warn_once(stream->dev, UVC_WARN_PROBE_DEF, "UVC non "
                        "compliance - GET_DEF(PROBE) not supported. "
                        "Enabling workaround.\n");
                ret = -EIO;
@@ -181,7 +184,7 @@ static int uvc_get_video_ctrl(struct uvc_video_device *video,
                ctrl->bMinVersion = data[32];
                ctrl->bMaxVersion = data[33];
        } else {
-               ctrl->dwClockFrequency = video->dev->clock_frequency;
+               ctrl->dwClockFrequency = stream->dev->clock_frequency;
                ctrl->bmFramingInfo = 0;
                ctrl->bPreferedVersion = 0;
                ctrl->bMinVersion = 0;
@@ -192,7 +195,7 @@ static int uvc_get_video_ctrl(struct uvc_video_device *video,
         * dwMaxPayloadTransferSize fields. Try to get the value from the
         * format and frame descriptors.
         */
-       uvc_fixup_video_ctrl(video, ctrl);
+       uvc_fixup_video_ctrl(stream, ctrl);
        ret = 0;
 
 out:
@@ -200,14 +203,14 @@ out:
        return ret;
 }
 
-static int uvc_set_video_ctrl(struct uvc_video_device *video,
+static int uvc_set_video_ctrl(struct uvc_streaming *stream,
        struct uvc_streaming_control *ctrl, int probe)
 {
        __u8 *data;
        __u16 size;
        int ret;
 
-       size = video->dev->uvc_version >= 0x0110 ? 34 : 26;
+       size = stream->dev->uvc_version >= 0x0110 ? 34 : 26;
        data = kzalloc(size, GFP_KERNEL);
        if (data == NULL)
                return -ENOMEM;
@@ -232,10 +235,9 @@ static int uvc_set_video_ctrl(struct uvc_video_device *video,
                data[33] = ctrl->bMaxVersion;
        }
 
-       ret = __uvc_query_ctrl(video->dev, SET_CUR, 0,
-               video->streaming->intfnum,
-               probe ? VS_PROBE_CONTROL : VS_COMMIT_CONTROL, data, size,
-               UVC_CTRL_STREAMING_TIMEOUT);
+       ret = __uvc_query_ctrl(stream->dev, UVC_SET_CUR, 0, stream->intfnum,
+               probe ? UVC_VS_PROBE_CONTROL : UVC_VS_COMMIT_CONTROL, data,
+               size, UVC_CTRL_STREAMING_TIMEOUT);
        if (ret != size) {
                uvc_printk(KERN_ERR, "Failed to set UVC %s control : "
                        "%d (exp. %u).\n", probe ? "probe" : "commit",
@@ -247,7 +249,7 @@ static int uvc_set_video_ctrl(struct uvc_video_device *video,
        return ret;
 }
 
-int uvc_probe_video(struct uvc_video_device *video,
+int uvc_probe_video(struct uvc_streaming *stream,
        struct uvc_streaming_control *probe)
 {
        struct uvc_streaming_control probe_min, probe_max;
@@ -255,7 +257,7 @@ int uvc_probe_video(struct uvc_video_device *video,
        unsigned int i;
        int ret;
 
-       mutex_lock(&video->streaming->mutex);
+       mutex_lock(&stream->mutex);
 
        /* Perform probing. The device should adjust the requested values
         * according to its capabilities. However, some devices, namely the
@@ -264,15 +266,16 @@ int uvc_probe_video(struct uvc_video_device *video,
         * that reason, if the needed bandwidth exceeds the maximum available
         * bandwidth, try to lower the quality.
         */
-       if ((ret = uvc_set_video_ctrl(video, probe, 1)) < 0)
+       ret = uvc_set_video_ctrl(stream, probe, 1);
+       if (ret < 0)
                goto done;
 
        /* Get the minimum and maximum values for compression settings. */
-       if (!(video->dev->quirks & UVC_QUIRK_PROBE_MINMAX)) {
-               ret = uvc_get_video_ctrl(video, &probe_min, 1, GET_MIN);
+       if (!(stream->dev->quirks & UVC_QUIRK_PROBE_MINMAX)) {
+               ret = uvc_get_video_ctrl(stream, &probe_min, 1, UVC_GET_MIN);
                if (ret < 0)
                        goto done;
-               ret = uvc_get_video_ctrl(video, &probe_max, 1, GET_MAX);
+               ret = uvc_get_video_ctrl(stream, &probe_max, 1, UVC_GET_MAX);
                if (ret < 0)
                        goto done;
 
@@ -280,18 +283,21 @@ int uvc_probe_video(struct uvc_video_device *video,
        }
 
        for (i = 0; i < 2; ++i) {
-               if ((ret = uvc_set_video_ctrl(video, probe, 1)) < 0 ||
-                   (ret = uvc_get_video_ctrl(video, probe, 1, GET_CUR)) < 0)
+               ret = uvc_set_video_ctrl(stream, probe, 1);
+               if (ret < 0)
+                       goto done;
+               ret = uvc_get_video_ctrl(stream, probe, 1, UVC_GET_CUR);
+               if (ret < 0)
                        goto done;
 
-               if (video->streaming->intf->num_altsetting == 1)
+               if (stream->intf->num_altsetting == 1)
                        break;
 
                bandwidth = probe->dwMaxPayloadTransferSize;
-               if (bandwidth <= video->streaming->maxpsize)
+               if (bandwidth <= stream->maxpsize)
                        break;
 
-               if (video->dev->quirks & UVC_QUIRK_PROBE_MINMAX) {
+               if (stream->dev->quirks & UVC_QUIRK_PROBE_MINMAX) {
                        ret = -ENOSPC;
                        goto done;
                }
@@ -304,14 +310,14 @@ int uvc_probe_video(struct uvc_video_device *video,
        }
 
 done:
-       mutex_unlock(&video->streaming->mutex);
+       mutex_unlock(&stream->mutex);
        return ret;
 }
 
-int uvc_commit_video(struct uvc_video_device *video,
+int uvc_commit_video(struct uvc_streaming *stream,
        struct uvc_streaming_control *probe)
 {
-       return uvc_set_video_ctrl(video, probe, 0);
+       return uvc_set_video_ctrl(stream, probe, 0);
 }
 
 /* ------------------------------------------------------------------------
@@ -363,7 +369,7 @@ int uvc_commit_video(struct uvc_video_device *video,
  * to be called with a NULL buf parameter. uvc_video_decode_data and
  * uvc_video_decode_end will never be called with a NULL buffer.
  */
-static int uvc_video_decode_start(struct uvc_video_device *video,
+static int uvc_video_decode_start(struct uvc_streaming *stream,
                struct uvc_buffer *buf, const __u8 *data, int len)
 {
        __u8 fid;
@@ -389,25 +395,25 @@ static int uvc_video_decode_start(struct uvc_video_device *video,
         * NULL.
         */
        if (buf == NULL) {
-               video->last_fid = fid;
+               stream->last_fid = fid;
                return -ENODATA;
        }
 
        /* Synchronize to the input stream by waiting for the FID bit to be
         * toggled when the the buffer state is not UVC_BUF_STATE_ACTIVE.
-        * video->last_fid is initialized to -1, so the first isochronous
+        * stream->last_fid is initialized to -1, so the first isochronous
         * frame will always be in sync.
         *
-        * If the device doesn't toggle the FID bit, invert video->last_fid
+        * If the device doesn't toggle the FID bit, invert stream->last_fid
         * when the EOF bit is set to force synchronisation on the next packet.
         */
        if (buf->state != UVC_BUF_STATE_ACTIVE) {
-               if (fid == video->last_fid) {
+               if (fid == stream->last_fid) {
                        uvc_trace(UVC_TRACE_FRAME, "Dropping payload (out of "
                                "sync).\n");
-                       if ((video->dev->quirks & UVC_QUIRK_STREAM_NO_FID) &&
+                       if ((stream->dev->quirks & UVC_QUIRK_STREAM_NO_FID) &&
                            (data[1] & UVC_STREAM_EOF))
-                               video->last_fid ^= UVC_STREAM_FID;
+                               stream->last_fid ^= UVC_STREAM_FID;
                        return -ENODATA;
                }
 
@@ -422,7 +428,7 @@ static int uvc_video_decode_start(struct uvc_video_device *video,
         * last payload can be lost anyway). We thus must check if the FID has
         * been toggled.
         *
-        * video->last_fid is initialized to -1, so the first isochronous
+        * stream->last_fid is initialized to -1, so the first isochronous
         * frame will never trigger an end of frame detection.
         *
         * Empty buffers (bytesused == 0) don't trigger end of frame detection
@@ -430,22 +436,22 @@ static int uvc_video_decode_start(struct uvc_video_device *video,
         * avoids detecting end of frame conditions at FID toggling if the
         * previous payload had the EOF bit set.
         */
-       if (fid != video->last_fid && buf->buf.bytesused != 0) {
+       if (fid != stream->last_fid && buf->buf.bytesused != 0) {
                uvc_trace(UVC_TRACE_FRAME, "Frame complete (FID bit "
                                "toggled).\n");
                buf->state = UVC_BUF_STATE_DONE;
                return -EAGAIN;
        }
 
-       video->last_fid = fid;
+       stream->last_fid = fid;
 
        return data[0];
 }
 
-static void uvc_video_decode_data(struct uvc_video_device *video,
+static void uvc_video_decode_data(struct uvc_streaming *stream,
                struct uvc_buffer *buf, const __u8 *data, int len)
 {
-       struct uvc_video_queue *queue = &video->queue;
+       struct uvc_video_queue *queue = &stream->queue;
        unsigned int maxlen, nbytes;
        void *mem;
 
@@ -466,7 +472,7 @@ static void uvc_video_decode_data(struct uvc_video_device *video,
        }
 }
 
-static void uvc_video_decode_end(struct uvc_video_device *video,
+static void uvc_video_decode_end(struct uvc_streaming *stream,
                struct uvc_buffer *buf, const __u8 *data, int len)
 {
        /* Mark the buffer as done if the EOF marker is set. */
@@ -475,8 +481,8 @@ static void uvc_video_decode_end(struct uvc_video_device *video,
                if (data[0] == len)
                        uvc_trace(UVC_TRACE_FRAME, "EOF in empty payload.\n");
                buf->state = UVC_BUF_STATE_DONE;
-               if (video->dev->quirks & UVC_QUIRK_STREAM_NO_FID)
-                       video->last_fid ^= UVC_STREAM_FID;
+               if (stream->dev->quirks & UVC_QUIRK_STREAM_NO_FID)
+                       stream->last_fid ^= UVC_STREAM_FID;
        }
 }
 
@@ -491,26 +497,26 @@ static void uvc_video_decode_end(struct uvc_video_device *video,
  * uvc_video_encode_data is called for every URB and copies the data from the
  * video buffer to the transfer buffer.
  */
-static int uvc_video_encode_header(struct uvc_video_device *video,
+static int uvc_video_encode_header(struct uvc_streaming *stream,
                struct uvc_buffer *buf, __u8 *data, int len)
 {
        data[0] = 2;    /* Header length */
        data[1] = UVC_STREAM_EOH | UVC_STREAM_EOF
-               | (video->last_fid & UVC_STREAM_FID);
+               | (stream->last_fid & UVC_STREAM_FID);
        return 2;
 }
 
-static int uvc_video_encode_data(struct uvc_video_device *video,
+static int uvc_video_encode_data(struct uvc_streaming *stream,
                struct uvc_buffer *buf, __u8 *data, int len)
 {
-       struct uvc_video_queue *queue = &video->queue;
+       struct uvc_video_queue *queue = &stream->queue;
        unsigned int nbytes;
        void *mem;
 
        /* Copy video data to the URB buffer. */
        mem = queue->mem + buf->buf.m.offset + queue->buf_used;
        nbytes = min((unsigned int)len, buf->buf.bytesused - queue->buf_used);
-       nbytes = min(video->bulk.max_payload_size - video->bulk.payload_size,
+       nbytes = min(stream->bulk.max_payload_size - stream->bulk.payload_size,
                        nbytes);
        memcpy(data, mem, nbytes);
 
@@ -526,8 +532,8 @@ static int uvc_video_encode_data(struct uvc_video_device *video,
 /*
  * Completion handler for video URBs.
  */
-static void uvc_video_decode_isoc(struct urb *urb,
-       struct uvc_video_device *video, struct uvc_buffer *buf)
+static void uvc_video_decode_isoc(struct urb *urb, struct uvc_streaming *stream,
+       struct uvc_buffer *buf)
 {
        u8 *mem;
        int ret, i;
@@ -542,31 +548,32 @@ static void uvc_video_decode_isoc(struct urb *urb,
                /* Decode the payload header. */
                mem = urb->transfer_buffer + urb->iso_frame_desc[i].offset;
                do {
-                       ret = uvc_video_decode_start(video, buf, mem,
+                       ret = uvc_video_decode_start(stream, buf, mem,
                                urb->iso_frame_desc[i].actual_length);
                        if (ret == -EAGAIN)
-                               buf = uvc_queue_next_buffer(&video->queue, buf);
+                               buf = uvc_queue_next_buffer(&stream->queue,
+                                                           buf);
                } while (ret == -EAGAIN);
 
                if (ret < 0)
                        continue;
 
                /* Decode the payload data. */
-               uvc_video_decode_data(video, buf, mem + ret,
+               uvc_video_decode_data(stream, buf, mem + ret,
                        urb->iso_frame_desc[i].actual_length - ret);
 
                /* Process the header again. */
-               uvc_video_decode_end(video, buf, mem,
+               uvc_video_decode_end(stream, buf, mem,
                        urb->iso_frame_desc[i].actual_length);
 
                if (buf->state == UVC_BUF_STATE_DONE ||
                    buf->state == UVC_BUF_STATE_ERROR)
-                       buf = uvc_queue_next_buffer(&video->queue, buf);
+                       buf = uvc_queue_next_buffer(&stream->queue, buf);
        }
 }
 
-static void uvc_video_decode_bulk(struct urb *urb,
-       struct uvc_video_device *video, struct uvc_buffer *buf)
+static void uvc_video_decode_bulk(struct urb *urb, struct uvc_streaming *stream,
+       struct uvc_buffer *buf)
 {
        u8 *mem;
        int len, ret;
@@ -576,24 +583,25 @@ static void uvc_video_decode_bulk(struct urb *urb,
 
        mem = urb->transfer_buffer;
        len = urb->actual_length;
-       video->bulk.payload_size += len;
+       stream->bulk.payload_size += len;
 
        /* If the URB is the first of its payload, decode and save the
         * header.
         */
-       if (video->bulk.header_size == 0 && !video->bulk.skip_payload) {
+       if (stream->bulk.header_size == 0 && !stream->bulk.skip_payload) {
                do {
-                       ret = uvc_video_decode_start(video, buf, mem, len);
+                       ret = uvc_video_decode_start(stream, buf, mem, len);
                        if (ret == -EAGAIN)
-                               buf = uvc_queue_next_buffer(&video->queue, buf);
+                               buf = uvc_queue_next_buffer(&stream->queue,
+                                                           buf);
                } while (ret == -EAGAIN);
 
                /* If an error occured skip the rest of the payload. */
                if (ret < 0 || buf == NULL) {
-                       video->bulk.skip_payload = 1;
+                       stream->bulk.skip_payload = 1;
                } else {
-                       memcpy(video->bulk.header, mem, ret);
-                       video->bulk.header_size = ret;
+                       memcpy(stream->bulk.header, mem, ret);
+                       stream->bulk.header_size = ret;
 
                        mem += ret;
                        len -= ret;
@@ -606,33 +614,34 @@ static void uvc_video_decode_bulk(struct urb *urb,
         */
 
        /* Process video data. */
-       if (!video->bulk.skip_payload && buf != NULL)
-               uvc_video_decode_data(video, buf, mem, len);
+       if (!stream->bulk.skip_payload && buf != NULL)
+               uvc_video_decode_data(stream, buf, mem, len);
 
        /* Detect the payload end by a URB smaller than the maximum size (or
         * a payload size equal to the maximum) and process the header again.
         */
        if (urb->actual_length < urb->transfer_buffer_length ||
-           video->bulk.payload_size >= video->bulk.max_payload_size) {
-               if (!video->bulk.skip_payload && buf != NULL) {
-                       uvc_video_decode_end(video, buf, video->bulk.header,
-                               video->bulk.payload_size);
+           stream->bulk.payload_size >= stream->bulk.max_payload_size) {
+               if (!stream->bulk.skip_payload && buf != NULL) {
+                       uvc_video_decode_end(stream, buf, stream->bulk.header,
+                               stream->bulk.payload_size);
                        if (buf->state == UVC_BUF_STATE_DONE ||
                            buf->state == UVC_BUF_STATE_ERROR)
-                               buf = uvc_queue_next_buffer(&video->queue, buf);
+                               buf = uvc_queue_next_buffer(&stream->queue,
+                                                           buf);
                }
 
-               video->bulk.header_size = 0;
-               video->bulk.skip_payload = 0;
-               video->bulk.payload_size = 0;
+               stream->bulk.header_size = 0;
+               stream->bulk.skip_payload = 0;
+               stream->bulk.payload_size = 0;
        }
 }
 
-static void uvc_video_encode_bulk(struct urb *urb,
-       struct uvc_video_device *video, struct uvc_buffer *buf)
+static void uvc_video_encode_bulk(struct urb *urb, struct uvc_streaming *stream,
+       struct uvc_buffer *buf)
 {
        u8 *mem = urb->transfer_buffer;
-       int len = video->urb_size, ret;
+       int len = stream->urb_size, ret;
 
        if (buf == NULL) {
                urb->transfer_buffer_length = 0;
@@ -640,40 +649,40 @@ static void uvc_video_encode_bulk(struct urb *urb,
        }
 
        /* If the URB is the first of its payload, add the header. */
-       if (video->bulk.header_size == 0) {
-               ret = uvc_video_encode_header(video, buf, mem, len);
-               video->bulk.header_size = ret;
-               video->bulk.payload_size += ret;
+       if (stream->bulk.header_size == 0) {
+               ret = uvc_video_encode_header(stream, buf, mem, len);
+               stream->bulk.header_size = ret;
+               stream->bulk.payload_size += ret;
                mem += ret;
                len -= ret;
        }
 
        /* Process video data. */
-       ret = uvc_video_encode_data(video, buf, mem, len);
+       ret = uvc_video_encode_data(stream, buf, mem, len);
 
-       video->bulk.payload_size += ret;
+       stream->bulk.payload_size += ret;
        len -= ret;
 
-       if (buf->buf.bytesused == video->queue.buf_used ||
-           video->bulk.payload_size == video->bulk.max_payload_size) {
-               if (buf->buf.bytesused == video->queue.buf_used) {
-                       video->queue.buf_used = 0;
+       if (buf->buf.bytesused == stream->queue.buf_used ||
+           stream->bulk.payload_size == stream->bulk.max_payload_size) {
+               if (buf->buf.bytesused == stream->queue.buf_used) {
+                       stream->queue.buf_used = 0;
                        buf->state = UVC_BUF_STATE_DONE;
-                       uvc_queue_next_buffer(&video->queue, buf);
-                       video->last_fid ^= UVC_STREAM_FID;
+                       uvc_queue_next_buffer(&stream->queue, buf);
+                       stream->last_fid ^= UVC_STREAM_FID;
                }
 
-               video->bulk.header_size = 0;
-               video->bulk.payload_size = 0;
+               stream->bulk.header_size = 0;
+               stream->bulk.payload_size = 0;
        }
 
-       urb->transfer_buffer_length = video->urb_size - len;
+       urb->transfer_buffer_length = stream->urb_size - len;
 }
 
 static void uvc_video_complete(struct urb *urb)
 {
-       struct uvc_video_device *video = urb->context;
-       struct uvc_video_queue *queue = &video->queue;
+       struct uvc_streaming *stream = urb->context;
+       struct uvc_video_queue *queue = &stream->queue;
        struct uvc_buffer *buf = NULL;
        unsigned long flags;
        int ret;
@@ -687,7 +696,7 @@ static void uvc_video_complete(struct urb *urb)
                        "completion handler.\n", urb->status);
 
        case -ENOENT:           /* usb_kill_urb() called. */
-               if (video->frozen)
+               if (stream->frozen)
                        return;
 
        case -ECONNRESET:       /* usb_unlink_urb() called. */
@@ -702,7 +711,7 @@ static void uvc_video_complete(struct urb *urb)
                                       queue);
        spin_unlock_irqrestore(&queue->irqlock, flags);
 
-       video->decode(urb, video, buf);
+       stream->decode(urb, stream, buf);
 
        if ((ret = usb_submit_urb(urb, GFP_ATOMIC)) < 0) {
                uvc_printk(KERN_ERR, "Failed to resubmit video URB (%d).\n",
@@ -713,19 +722,19 @@ static void uvc_video_complete(struct urb *urb)
 /*
  * Free transfer buffers.
  */
-static void uvc_free_urb_buffers(struct uvc_video_device *video)
+static void uvc_free_urb_buffers(struct uvc_streaming *stream)
 {
        unsigned int i;
 
        for (i = 0; i < UVC_URBS; ++i) {
-               if (video->urb_buffer[i]) {
-                       usb_buffer_free(video->dev->udev, video->urb_size,
-                               video->urb_buffer[i], video->urb_dma[i]);
-                       video->urb_buffer[i] = NULL;
+               if (stream->urb_buffer[i]) {
+                       usb_buffer_free(stream->dev->udev, stream->urb_size,
+                               stream->urb_buffer[i], stream->urb_dma[i]);
+                       stream->urb_buffer[i] = NULL;
                }
        }
 
-       video->urb_size = 0;
+       stream->urb_size = 0;
 }
 
 /*
@@ -739,15 +748,15 @@ static void uvc_free_urb_buffers(struct uvc_video_device *video)
  *
  * Return the number of allocated packets on success or 0 when out of memory.
  */
-static int uvc_alloc_urb_buffers(struct uvc_video_device *video,
+static int uvc_alloc_urb_buffers(struct uvc_streaming *stream,
        unsigned int size, unsigned int psize, gfp_t gfp_flags)
 {
        unsigned int npackets;
        unsigned int i;
 
        /* Buffers are already allocated, bail out. */
-       if (video->urb_size)
-               return video->urb_size / psize;
+       if (stream->urb_size)
+               return stream->urb_size / psize;
 
        /* Compute the number of packets. Bulk endpoints might transfer UVC
         * payloads accross multiple URBs.
@@ -759,17 +768,17 @@ static int uvc_alloc_urb_buffers(struct uvc_video_device *video,
        /* Retry allocations until one succeed. */
        for (; npackets > 1; npackets /= 2) {
                for (i = 0; i < UVC_URBS; ++i) {
-                       video->urb_buffer[i] = usb_buffer_alloc(
-                               video->dev->udev, psize * npackets,
-                               gfp_flags | __GFP_NOWARN, &video->urb_dma[i]);
-                       if (!video->urb_buffer[i]) {
-                               uvc_free_urb_buffers(video);
+                       stream->urb_buffer[i] = usb_buffer_alloc(
+                               stream->dev->udev, psize * npackets,
+                               gfp_flags | __GFP_NOWARN, &stream->urb_dma[i]);
+                       if (!stream->urb_buffer[i]) {
+                               uvc_free_urb_buffers(stream);
                                break;
                        }
                }
 
                if (i == UVC_URBS) {
-                       video->urb_size = psize * npackets;
+                       stream->urb_size = psize * npackets;
                        return npackets;
                }
        }
@@ -780,29 +789,30 @@ static int uvc_alloc_urb_buffers(struct uvc_video_device *video,
 /*
  * Uninitialize isochronous/bulk URBs and free transfer buffers.
  */
-static void uvc_uninit_video(struct uvc_video_device *video, int free_buffers)
+static void uvc_uninit_video(struct uvc_streaming *stream, int free_buffers)
 {
        struct urb *urb;
        unsigned int i;
 
        for (i = 0; i < UVC_URBS; ++i) {
-               if ((urb = video->urb[i]) == NULL)
+               urb = stream->urb[i];
+               if (urb == NULL)
                        continue;
 
                usb_kill_urb(urb);
                usb_free_urb(urb);
-               video->urb[i] = NULL;
+               stream->urb[i] = NULL;
        }
 
        if (free_buffers)
-               uvc_free_urb_buffers(video);
+               uvc_free_urb_buffers(stream);
 }
 
 /*
  * Initialize isochronous URBs and allocate transfer buffers. The packet size
  * is given by the endpoint.
  */
-static int uvc_init_video_isoc(struct uvc_video_device *video,
+static int uvc_init_video_isoc(struct uvc_streaming *stream,
        struct usb_host_endpoint *ep, gfp_t gfp_flags)
 {
        struct urb *urb;
@@ -812,9 +822,9 @@ static int uvc_init_video_isoc(struct uvc_video_device *video,
 
        psize = le16_to_cpu(ep->desc.wMaxPacketSize);
        psize = (psize & 0x07ff) * (1 + ((psize >> 11) & 3));
-       size = video->streaming->ctrl.dwMaxVideoFrameSize;
+       size = stream->ctrl.dwMaxVideoFrameSize;
 
-       npackets = uvc_alloc_urb_buffers(video, size, psize, gfp_flags);
+       npackets = uvc_alloc_urb_buffers(stream, size, psize, gfp_flags);
        if (npackets == 0)
                return -ENOMEM;
 
@@ -823,18 +833,18 @@ static int uvc_init_video_isoc(struct uvc_video_device *video,
        for (i = 0; i < UVC_URBS; ++i) {
                urb = usb_alloc_urb(npackets, gfp_flags);
                if (urb == NULL) {
-                       uvc_uninit_video(video, 1);
+                       uvc_uninit_video(stream, 1);
                        return -ENOMEM;
                }
 
-               urb->dev = video->dev->udev;
-               urb->context = video;
-               urb->pipe = usb_rcvisocpipe(video->dev->udev,
+               urb->dev = stream->dev->udev;
+               urb->context = stream;
+               urb->pipe = usb_rcvisocpipe(stream->dev->udev,
                                ep->desc.bEndpointAddress);
                urb->transfer_flags = URB_ISO_ASAP | URB_NO_TRANSFER_DMA_MAP;
                urb->interval = ep->desc.bInterval;
-               urb->transfer_buffer = video->urb_buffer[i];
-               urb->transfer_dma = video->urb_dma[i];
+               urb->transfer_buffer = stream->urb_buffer[i];
+               urb->transfer_dma = stream->urb_dma[i];
                urb->complete = uvc_video_complete;
                urb->number_of_packets = npackets;
                urb->transfer_buffer_length = size;
@@ -844,7 +854,7 @@ static int uvc_init_video_isoc(struct uvc_video_device *video,
                        urb->iso_frame_desc[j].length = psize;
                }
 
-               video->urb[i] = urb;
+               stream->urb[i] = urb;
        }
 
        return 0;
@@ -854,7 +864,7 @@ static int uvc_init_video_isoc(struct uvc_video_device *video,
  * Initialize bulk URBs and allocate transfer buffers. The packet size is
  * given by the endpoint.
  */
-static int uvc_init_video_bulk(struct uvc_video_device *video,
+static int uvc_init_video_bulk(struct uvc_streaming *stream,
        struct usb_host_endpoint *ep, gfp_t gfp_flags)
 {
        struct urb *urb;
@@ -863,39 +873,39 @@ static int uvc_init_video_bulk(struct uvc_video_device *video,
        u32 size;
 
        psize = le16_to_cpu(ep->desc.wMaxPacketSize) & 0x07ff;
-       size = video->streaming->ctrl.dwMaxPayloadTransferSize;
-       video->bulk.max_payload_size = size;
+       size = stream->ctrl.dwMaxPayloadTransferSize;
+       stream->bulk.max_payload_size = size;
 
-       npackets = uvc_alloc_urb_buffers(video, size, psize, gfp_flags);
+       npackets = uvc_alloc_urb_buffers(stream, size, psize, gfp_flags);
        if (npackets == 0)
                return -ENOMEM;
 
        size = npackets * psize;
 
        if (usb_endpoint_dir_in(&ep->desc))
-               pipe = usb_rcvbulkpipe(video->dev->udev,
+               pipe = usb_rcvbulkpipe(stream->dev->udev,
                                       ep->desc.bEndpointAddress);
        else
-               pipe = usb_sndbulkpipe(video->dev->udev,
+               pipe = usb_sndbulkpipe(stream->dev->udev,
                                       ep->desc.bEndpointAddress);
 
-       if (video->streaming->type == V4L2_BUF_TYPE_VIDEO_OUTPUT)
+       if (stream->type == V4L2_BUF_TYPE_VIDEO_OUTPUT)
                size = 0;
 
        for (i = 0; i < UVC_URBS; ++i) {
                urb = usb_alloc_urb(0, gfp_flags);
                if (urb == NULL) {
-                       uvc_uninit_video(video, 1);
+                       uvc_uninit_video(stream, 1);
                        return -ENOMEM;
                }
 
-               usb_fill_bulk_urb(urb, video->dev->udev, pipe,
-                       video->urb_buffer[i], size, uvc_video_complete,
-                       video);
+               usb_fill_bulk_urb(urb, stream->dev->udev, pipe,
+                       stream->urb_buffer[i], size, uvc_video_complete,
+                       stream);
                urb->transfer_flags = URB_NO_TRANSFER_DMA_MAP;
-               urb->transfer_dma = video->urb_dma[i];
+               urb->transfer_dma = stream->urb_dma[i];
 
-               video->urb[i] = urb;
+               stream->urb[i] = urb;
        }
 
        return 0;
@@ -904,35 +914,35 @@ static int uvc_init_video_bulk(struct uvc_video_device *video,
 /*
  * Initialize isochronous/bulk URBs and allocate transfer buffers.
  */
-static int uvc_init_video(struct uvc_video_device *video, gfp_t gfp_flags)
+static int uvc_init_video(struct uvc_streaming *stream, gfp_t gfp_flags)
 {
-       struct usb_interface *intf = video->streaming->intf;
+       struct usb_interface *intf = stream->intf;
        struct usb_host_interface *alts;
        struct usb_host_endpoint *ep = NULL;
-       int intfnum = video->streaming->intfnum;
+       int intfnum = stream->intfnum;
        unsigned int bandwidth, psize, i;
        int ret;
 
-       video->last_fid = -1;
-       video->bulk.header_size = 0;
-       video->bulk.skip_payload = 0;
-       video->bulk.payload_size = 0;
+       stream->last_fid = -1;
+       stream->bulk.header_size = 0;
+       stream->bulk.skip_payload = 0;
+       stream->bulk.payload_size = 0;
 
        if (intf->num_altsetting > 1) {
                /* Isochronous endpoint, select the alternate setting. */
-               bandwidth = video->streaming->ctrl.dwMaxPayloadTransferSize;
+               bandwidth = stream->ctrl.dwMaxPayloadTransferSize;
 
                if (bandwidth == 0) {
                        uvc_printk(KERN_WARNING, "device %s requested null "
                                "bandwidth, defaulting to lowest.\n",
-                               video->vdev->name);
+                               stream->dev->name);
                        bandwidth = 1;
                }
 
                for (i = 0; i < intf->num_altsetting; ++i) {
                        alts = &intf->altsetting[i];
                        ep = uvc_find_endpoint(alts,
-                               video->streaming->header.bEndpointAddress);
+                               stream->header.bEndpointAddress);
                        if (ep == NULL)
                                continue;
 
@@ -946,18 +956,19 @@ static int uvc_init_video(struct uvc_video_device *video, gfp_t gfp_flags)
                if (i >= intf->num_altsetting)
                        return -EIO;
 
-               if ((ret = usb_set_interface(video->dev->udev, intfnum, i)) < 0)
+               ret = usb_set_interface(stream->dev->udev, intfnum, i);
+               if (ret < 0)
                        return ret;
 
-               ret = uvc_init_video_isoc(video, ep, gfp_flags);
+               ret = uvc_init_video_isoc(stream, ep, gfp_flags);
        } else {
                /* Bulk endpoint, proceed to URB initialization. */
                ep = uvc_find_endpoint(&intf->altsetting[0],
-                               video->streaming->header.bEndpointAddress);
+                               stream->header.bEndpointAddress);
                if (ep == NULL)
                        return -EIO;
 
-               ret = uvc_init_video_bulk(video, ep, gfp_flags);
+               ret = uvc_init_video_bulk(stream, ep, gfp_flags);
        }
 
        if (ret < 0)
@@ -965,10 +976,11 @@ static int uvc_init_video(struct uvc_video_device *video, gfp_t gfp_flags)
 
        /* Submit the URBs. */
        for (i = 0; i < UVC_URBS; ++i) {
-               if ((ret = usb_submit_urb(video->urb[i], gfp_flags)) < 0) {
+               ret = usb_submit_urb(stream->urb[i], gfp_flags);
+               if (ret < 0) {
                        uvc_printk(KERN_ERR, "Failed to submit URB %u "
                                        "(%d).\n", i, ret);
-                       uvc_uninit_video(video, 1);
+                       uvc_uninit_video(stream, 1);
                        return ret;
                }
        }
@@ -987,14 +999,14 @@ static int uvc_init_video(struct uvc_video_device *video, gfp_t gfp_flags)
  * video buffers in any way. We mark the device as frozen to make sure the URB
  * completion handler won't try to cancel the queue when we kill the URBs.
  */
-int uvc_video_suspend(struct uvc_video_device *video)
+int uvc_video_suspend(struct uvc_streaming *stream)
 {
-       if (!uvc_queue_streaming(&video->queue))
+       if (!uvc_queue_streaming(&stream->queue))
                return 0;
 
-       video->frozen = 1;
-       uvc_uninit_video(video, 0);
-       usb_set_interface(video->dev->udev, video->streaming->intfnum, 0);
+       stream->frozen = 1;
+       uvc_uninit_video(stream, 0);
+       usb_set_interface(stream->dev->udev, stream->intfnum, 0);
        return 0;
 }
 
@@ -1006,22 +1018,24 @@ int uvc_video_suspend(struct uvc_video_device *video)
  * buffers, making sure userspace applications are notified of the problem
  * instead of waiting forever.
  */
-int uvc_video_resume(struct uvc_video_device *video)
+int uvc_video_resume(struct uvc_streaming *stream)
 {
        int ret;
 
-       video->frozen = 0;
+       stream->frozen = 0;
 
-       if ((ret = uvc_commit_video(video, &video->streaming->ctrl)) < 0) {
-               uvc_queue_enable(&video->queue, 0);
+       ret = uvc_commit_video(stream, &stream->ctrl);
+       if (ret < 0) {
+               uvc_queue_enable(&stream->queue, 0);
                return ret;
        }
 
-       if (!uvc_queue_streaming(&video->queue))
+       if (!uvc_queue_streaming(&stream->queue))
                return 0;
 
-       if ((ret = uvc_init_video(video, GFP_NOIO)) < 0)
-               uvc_queue_enable(&video->queue, 0);
+       ret = uvc_init_video(stream, GFP_NOIO);
+       if (ret < 0)
+               uvc_queue_enable(&stream->queue, 0);
 
        return ret;
 }
@@ -1040,47 +1054,53 @@ int uvc_video_resume(struct uvc_video_device *video)
  *
  * This function is called before registering the device with V4L.
  */
-int uvc_video_init(struct uvc_video_device *video)
+int uvc_video_init(struct uvc_streaming *stream)
 {
-       struct uvc_streaming_control *probe = &video->streaming->ctrl;
+       struct uvc_streaming_control *probe = &stream->ctrl;
        struct uvc_format *format = NULL;
        struct uvc_frame *frame = NULL;
        unsigned int i;
        int ret;
 
-       if (video->streaming->nformats == 0) {
+       if (stream->nformats == 0) {
                uvc_printk(KERN_INFO, "No supported video formats found.\n");
                return -EINVAL;
        }
 
+       atomic_set(&stream->active, 0);
+
+       /* Initialize the video buffers queue. */
+       uvc_queue_init(&stream->queue, stream->type);
+
        /* Alternate setting 0 should be the default, yet the XBox Live Vision
         * Cam (and possibly other devices) crash or otherwise misbehave if
         * they don't receive a SET_INTERFACE request before any other video
         * control request.
         */
-       usb_set_interface(video->dev->udev, video->streaming->intfnum, 0);
+       usb_set_interface(stream->dev->udev, stream->intfnum, 0);
 
        /* Set the streaming probe control with default streaming parameters
         * retrieved from the device. Webcams that don't suport GET_DEF
         * requests on the probe control will just keep their current streaming
         * parameters.
         */
-       if (uvc_get_video_ctrl(video, probe, 1, GET_DEF) == 0)
-               uvc_set_video_ctrl(video, probe, 1);
+       if (uvc_get_video_ctrl(stream, probe, 1, UVC_GET_DEF) == 0)
+               uvc_set_video_ctrl(stream, probe, 1);
 
        /* Initialize the streaming parameters with the probe control current
         * value. This makes sure SET_CUR requests on the streaming commit
         * control will always use values retrieved from a successful GET_CUR
         * request on the probe control, as required by the UVC specification.
         */
-       if ((ret = uvc_get_video_ctrl(video, probe, 1, GET_CUR)) < 0)
+       ret = uvc_get_video_ctrl(stream, probe, 1, UVC_GET_CUR);
+       if (ret < 0)
                return ret;
 
        /* Check if the default format descriptor exists. Use the first
         * available format otherwise.
         */
-       for (i = video->streaming->nformats; i > 0; --i) {
-               format = &video->streaming->format[i-1];
+       for (i = stream->nformats; i > 0; --i) {
+               format = &stream->format[i-1];
                if (format->index == probe->bFormatIndex)
                        break;
        }
@@ -1105,21 +1125,20 @@ int uvc_video_init(struct uvc_video_device *video)
        probe->bFormatIndex = format->index;
        probe->bFrameIndex = frame->bFrameIndex;
 
-       video->streaming->cur_format = format;
-       video->streaming->cur_frame = frame;
-       atomic_set(&video->active, 0);
+       stream->cur_format = format;
+       stream->cur_frame = frame;
 
        /* Select the video decoding function */
-       if (video->streaming->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) {
-               if (video->dev->quirks & UVC_QUIRK_BUILTIN_ISIGHT)
-                       video->decode = uvc_video_decode_isight;
-               else if (video->streaming->intf->num_altsetting > 1)
-                       video->decode = uvc_video_decode_isoc;
+       if (stream->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) {
+               if (stream->dev->quirks & UVC_QUIRK_BUILTIN_ISIGHT)
+                       stream->decode = uvc_video_decode_isight;
+               else if (stream->intf->num_altsetting > 1)
+                       stream->decode = uvc_video_decode_isoc;
                else
-                       video->decode = uvc_video_decode_bulk;
+                       stream->decode = uvc_video_decode_bulk;
        } else {
-               if (video->streaming->intf->num_altsetting == 1)
-                       video->decode = uvc_video_encode_bulk;
+               if (stream->intf->num_altsetting == 1)
+                       stream->decode = uvc_video_encode_bulk;
                else {
                        uvc_printk(KERN_INFO, "Isochronous endpoints are not "
                                "supported for video output devices.\n");
@@ -1133,31 +1152,32 @@ int uvc_video_init(struct uvc_video_device *video)
 /*
  * Enable or disable the video stream.
  */
-int uvc_video_enable(struct uvc_video_device *video, int enable)
+int uvc_video_enable(struct uvc_streaming *stream, int enable)
 {
        int ret;
 
        if (!enable) {
-               uvc_uninit_video(video, 1);
-               usb_set_interface(video->dev->udev,
-                       video->streaming->intfnum, 0);
-               uvc_queue_enable(&video->queue, 0);
+               uvc_uninit_video(stream, 1);
+               usb_set_interface(stream->dev->udev, stream->intfnum, 0);
+               uvc_queue_enable(&stream->queue, 0);
                return 0;
        }
 
-       if ((video->streaming->cur_format->flags & UVC_FMT_FLAG_COMPRESSED) ||
+       if ((stream->cur_format->flags & UVC_FMT_FLAG_COMPRESSED) ||
            uvc_no_drop_param)
-               video->queue.flags &= ~UVC_QUEUE_DROP_INCOMPLETE;
+               stream->queue.flags &= ~UVC_QUEUE_DROP_INCOMPLETE;
        else
-               video->queue.flags |= UVC_QUEUE_DROP_INCOMPLETE;
+               stream->queue.flags |= UVC_QUEUE_DROP_INCOMPLETE;
 
-       if ((ret = uvc_queue_enable(&video->queue, 1)) < 0)
+       ret = uvc_queue_enable(&stream->queue, 1);
+       if (ret < 0)
                return ret;
 
        /* Commit the streaming parameters. */
-       if ((ret = uvc_commit_video(video, &video->streaming->ctrl)) < 0)
+       ret = uvc_commit_video(stream, &stream->ctrl);
+       if (ret < 0)
                return ret;
 
-       return uvc_init_video(video, GFP_KERNEL);
+       return uvc_init_video(stream, GFP_KERNEL);
 }
 
index 3c78d3c1e4c0f7482122d7ddff4ea2c0411fea2e..e7958aa454cefa28603536e40a7ac65089bf309d 100644 (file)
@@ -67,155 +67,12 @@ struct uvc_xu_control {
 #ifdef __KERNEL__
 
 #include <linux/poll.h>
+#include <linux/usb/video.h>
 
 /* --------------------------------------------------------------------------
  * UVC constants
  */
 
-#define SC_UNDEFINED                   0x00
-#define SC_VIDEOCONTROL                        0x01
-#define SC_VIDEOSTREAMING              0x02
-#define SC_VIDEO_INTERFACE_COLLECTION  0x03
-
-#define PC_PROTOCOL_UNDEFINED          0x00
-
-#define CS_UNDEFINED                   0x20
-#define CS_DEVICE                      0x21
-#define CS_CONFIGURATION               0x22
-#define CS_STRING                      0x23
-#define CS_INTERFACE                   0x24
-#define CS_ENDPOINT                    0x25
-
-/* VideoControl class specific interface descriptor */
-#define VC_DESCRIPTOR_UNDEFINED                0x00
-#define VC_HEADER                      0x01
-#define VC_INPUT_TERMINAL              0x02
-#define VC_OUTPUT_TERMINAL             0x03
-#define VC_SELECTOR_UNIT               0x04
-#define VC_PROCESSING_UNIT             0x05
-#define VC_EXTENSION_UNIT              0x06
-
-/* VideoStreaming class specific interface descriptor */
-#define VS_UNDEFINED                   0x00
-#define VS_INPUT_HEADER                        0x01
-#define VS_OUTPUT_HEADER               0x02
-#define VS_STILL_IMAGE_FRAME           0x03
-#define VS_FORMAT_UNCOMPRESSED         0x04
-#define VS_FRAME_UNCOMPRESSED          0x05
-#define VS_FORMAT_MJPEG                        0x06
-#define VS_FRAME_MJPEG                 0x07
-#define VS_FORMAT_MPEG2TS              0x0a
-#define VS_FORMAT_DV                   0x0c
-#define VS_COLORFORMAT                 0x0d
-#define VS_FORMAT_FRAME_BASED          0x10
-#define VS_FRAME_FRAME_BASED           0x11
-#define VS_FORMAT_STREAM_BASED         0x12
-
-/* Endpoint type */
-#define EP_UNDEFINED                   0x00
-#define EP_GENERAL                     0x01
-#define EP_ENDPOINT                    0x02
-#define EP_INTERRUPT                   0x03
-
-/* Request codes */
-#define RC_UNDEFINED                   0x00
-#define SET_CUR                                0x01
-#define GET_CUR                                0x81
-#define GET_MIN                                0x82
-#define GET_MAX                                0x83
-#define GET_RES                                0x84
-#define GET_LEN                                0x85
-#define GET_INFO                       0x86
-#define GET_DEF                                0x87
-
-/* VideoControl interface controls */
-#define VC_CONTROL_UNDEFINED           0x00
-#define VC_VIDEO_POWER_MODE_CONTROL    0x01
-#define VC_REQUEST_ERROR_CODE_CONTROL  0x02
-
-/* Terminal controls */
-#define TE_CONTROL_UNDEFINED           0x00
-
-/* Selector Unit controls */
-#define SU_CONTROL_UNDEFINED           0x00
-#define SU_INPUT_SELECT_CONTROL                0x01
-
-/* Camera Terminal controls */
-#define CT_CONTROL_UNDEFINED                           0x00
-#define CT_SCANNING_MODE_CONTROL                       0x01
-#define CT_AE_MODE_CONTROL                             0x02
-#define CT_AE_PRIORITY_CONTROL                         0x03
-#define CT_EXPOSURE_TIME_ABSOLUTE_CONTROL              0x04
-#define CT_EXPOSURE_TIME_RELATIVE_CONTROL              0x05
-#define CT_FOCUS_ABSOLUTE_CONTROL                      0x06
-#define CT_FOCUS_RELATIVE_CONTROL                      0x07
-#define CT_FOCUS_AUTO_CONTROL                          0x08
-#define CT_IRIS_ABSOLUTE_CONTROL                       0x09
-#define CT_IRIS_RELATIVE_CONTROL                       0x0a
-#define CT_ZOOM_ABSOLUTE_CONTROL                       0x0b
-#define CT_ZOOM_RELATIVE_CONTROL                       0x0c
-#define CT_PANTILT_ABSOLUTE_CONTROL                    0x0d
-#define CT_PANTILT_RELATIVE_CONTROL                    0x0e
-#define CT_ROLL_ABSOLUTE_CONTROL                       0x0f
-#define CT_ROLL_RELATIVE_CONTROL                       0x10
-#define CT_PRIVACY_CONTROL                             0x11
-
-/* Processing Unit controls */
-#define PU_CONTROL_UNDEFINED                           0x00
-#define PU_BACKLIGHT_COMPENSATION_CONTROL              0x01
-#define PU_BRIGHTNESS_CONTROL                          0x02
-#define PU_CONTRAST_CONTROL                            0x03
-#define PU_GAIN_CONTROL                                        0x04
-#define PU_POWER_LINE_FREQUENCY_CONTROL                        0x05
-#define PU_HUE_CONTROL                                 0x06
-#define PU_SATURATION_CONTROL                          0x07
-#define PU_SHARPNESS_CONTROL                           0x08
-#define PU_GAMMA_CONTROL                               0x09
-#define PU_WHITE_BALANCE_TEMPERATURE_CONTROL           0x0a
-#define PU_WHITE_BALANCE_TEMPERATURE_AUTO_CONTROL      0x0b
-#define PU_WHITE_BALANCE_COMPONENT_CONTROL             0x0c
-#define PU_WHITE_BALANCE_COMPONENT_AUTO_CONTROL                0x0d
-#define PU_DIGITAL_MULTIPLIER_CONTROL                  0x0e
-#define PU_DIGITAL_MULTIPLIER_LIMIT_CONTROL            0x0f
-#define PU_HUE_AUTO_CONTROL                            0x10
-#define PU_ANALOG_VIDEO_STANDARD_CONTROL               0x11
-#define PU_ANALOG_LOCK_STATUS_CONTROL                  0x12
-
-#define LXU_MOTOR_PANTILT_RELATIVE_CONTROL             0x01
-#define LXU_MOTOR_PANTILT_RESET_CONTROL                        0x02
-#define LXU_MOTOR_FOCUS_MOTOR_CONTROL                  0x03
-
-/* VideoStreaming interface controls */
-#define VS_CONTROL_UNDEFINED           0x00
-#define VS_PROBE_CONTROL               0x01
-#define VS_COMMIT_CONTROL              0x02
-#define VS_STILL_PROBE_CONTROL         0x03
-#define VS_STILL_COMMIT_CONTROL                0x04
-#define VS_STILL_IMAGE_TRIGGER_CONTROL 0x05
-#define VS_STREAM_ERROR_CODE_CONTROL   0x06
-#define VS_GENERATE_KEY_FRAME_CONTROL  0x07
-#define VS_UPDATE_FRAME_SEGMENT_CONTROL        0x08
-#define VS_SYNC_DELAY_CONTROL          0x09
-
-#define TT_VENDOR_SPECIFIC             0x0100
-#define TT_STREAMING                   0x0101
-
-/* Input Terminal types */
-#define ITT_VENDOR_SPECIFIC            0x0200
-#define ITT_CAMERA                     0x0201
-#define ITT_MEDIA_TRANSPORT_INPUT      0x0202
-
-/* Output Terminal types */
-#define OTT_VENDOR_SPECIFIC            0x0300
-#define OTT_DISPLAY                    0x0301
-#define OTT_MEDIA_TRANSPORT_OUTPUT     0x0302
-
-/* External Terminal types */
-#define EXTERNAL_VENDOR_SPECIFIC       0x0400
-#define COMPOSITE_CONNECTOR            0x0401
-#define SVIDEO_CONNECTOR               0x0402
-#define COMPONENT_CONNECTOR            0x0403
-
 #define UVC_TERM_INPUT                 0x0000
 #define UVC_TERM_OUTPUT                        0x8000
 
@@ -223,12 +80,12 @@ struct uvc_xu_control {
 #define UVC_ENTITY_IS_UNIT(entity)     (((entity)->type & 0xff00) == 0)
 #define UVC_ENTITY_IS_TERM(entity)     (((entity)->type & 0xff00) != 0)
 #define UVC_ENTITY_IS_ITERM(entity) \
-       (((entity)->type & 0x8000) == UVC_TERM_INPUT)
+       (UVC_ENTITY_IS_TERM(entity) && \
+       ((entity)->type & 0x8000) == UVC_TERM_INPUT)
 #define UVC_ENTITY_IS_OTERM(entity) \
-       (((entity)->type & 0x8000) == UVC_TERM_OUTPUT)
+       (UVC_ENTITY_IS_TERM(entity) && \
+       ((entity)->type & 0x8000) == UVC_TERM_OUTPUT)
 
-#define UVC_STATUS_TYPE_CONTROL                1
-#define UVC_STATUS_TYPE_STREAMING      2
 
 /* ------------------------------------------------------------------------
  * GUIDs
@@ -249,19 +106,6 @@ struct uvc_xu_control {
        {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \
         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x02}
 
-#define UVC_GUID_LOGITECH_DEV_INFO \
-       {0x82, 0x06, 0x61, 0x63, 0x70, 0x50, 0xab, 0x49, \
-        0xb8, 0xcc, 0xb3, 0x85, 0x5e, 0x8d, 0x22, 0x1e}
-#define UVC_GUID_LOGITECH_USER_HW \
-       {0x82, 0x06, 0x61, 0x63, 0x70, 0x50, 0xab, 0x49, \
-        0xb8, 0xcc, 0xb3, 0x85, 0x5e, 0x8d, 0x22, 0x1f}
-#define UVC_GUID_LOGITECH_VIDEO \
-       {0x82, 0x06, 0x61, 0x63, 0x70, 0x50, 0xab, 0x49, \
-        0xb8, 0xcc, 0xb3, 0x85, 0x5e, 0x8d, 0x22, 0x50}
-#define UVC_GUID_LOGITECH_MOTOR \
-       {0x82, 0x06, 0x61, 0x63, 0x70, 0x50, 0xab, 0x49, \
-        0xb8, 0xcc, 0xb3, 0x85, 0x5e, 0x8d, 0x22, 0x56}
-
 #define UVC_GUID_FORMAT_MJPEG \
        { 'M',  'J',  'P',  'G', 0x00, 0x00, 0x10, 0x00, \
         0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71}
@@ -314,6 +158,7 @@ struct uvc_xu_control {
 #define UVC_QUIRK_STREAM_NO_FID                0x00000010
 #define UVC_QUIRK_IGNORE_SELECTOR_UNIT 0x00000020
 #define UVC_QUIRK_FIX_BANDWIDTH                0x00000080
+#define UVC_QUIRK_PROBE_DEF            0x00000100
 
 /* Format flags */
 #define UVC_FMT_FLAG_COMPRESSED                0x00000001
@@ -518,26 +363,6 @@ struct uvc_streaming_header {
        __u8 bTriggerUsage;
 };
 
-struct uvc_streaming {
-       struct list_head list;
-
-       struct usb_interface *intf;
-       int intfnum;
-       __u16 maxpsize;
-
-       struct uvc_streaming_header header;
-       enum v4l2_buf_type type;
-
-       unsigned int nformats;
-       struct uvc_format *format;
-
-       struct uvc_streaming_control ctrl;
-       struct uvc_format *cur_format;
-       struct uvc_frame *cur_frame;
-
-       struct mutex mutex;
-};
-
 enum uvc_buffer_state {
        UVC_BUF_STATE_IDLE      = 0,
        UVC_BUF_STATE_QUEUED    = 1,
@@ -579,26 +404,45 @@ struct uvc_video_queue {
        struct list_head irqqueue;
 };
 
-struct uvc_video_device {
+struct uvc_video_chain {
        struct uvc_device *dev;
-       struct video_device *vdev;
-       atomic_t active;
-       unsigned int frozen : 1;
+       struct list_head list;
 
        struct list_head iterms;                /* Input terminals */
-       struct uvc_entity *oterm;               /* Output terminal */
-       struct uvc_entity *sterm;               /* USB streaming terminal */
-       struct uvc_entity *processing;
-       struct uvc_entity *selector;
-       struct list_head extensions;
+       struct list_head oterms;                /* Output terminals */
+       struct uvc_entity *processing;          /* Processing unit */
+       struct uvc_entity *selector;            /* Selector unit */
+       struct list_head extensions;            /* Extension units */
+
        struct mutex ctrl_mutex;
+};
 
-       struct uvc_video_queue queue;
+struct uvc_streaming {
+       struct list_head list;
+       struct uvc_device *dev;
+       struct video_device *vdev;
+       struct uvc_video_chain *chain;
+       atomic_t active;
 
-       /* Video streaming object, must always be non-NULL. */
-       struct uvc_streaming *streaming;
+       struct usb_interface *intf;
+       int intfnum;
+       __u16 maxpsize;
 
-       void (*decode) (struct urb *urb, struct uvc_video_device *video,
+       struct uvc_streaming_header header;
+       enum v4l2_buf_type type;
+
+       unsigned int nformats;
+       struct uvc_format *format;
+
+       struct uvc_streaming_control ctrl;
+       struct uvc_format *cur_format;
+       struct uvc_frame *cur_frame;
+
+       struct mutex mutex;
+
+       unsigned int frozen : 1;
+       struct uvc_video_queue queue;
+       void (*decode) (struct urb *urb, struct uvc_streaming *video,
                        struct uvc_buffer *buf);
 
        /* Context data used by the bulk completion handler. */
@@ -640,8 +484,10 @@ struct uvc_device {
        __u32 clock_frequency;
 
        struct list_head entities;
+       struct list_head chains;
 
-       struct uvc_video_device video;
+       /* Video Streaming interfaces */
+       struct list_head streams;
 
        /* Status Interrupt Endpoint */
        struct usb_host_endpoint *int_ep;
@@ -649,9 +495,6 @@ struct uvc_device {
        __u8 *status;
        struct input_dev *input;
        char input_phys[64];
-
-       /* Video Streaming interfaces */
-       struct list_head streaming;
 };
 
 enum uvc_handle_state {
@@ -660,7 +503,8 @@ enum uvc_handle_state {
 };
 
 struct uvc_fh {
-       struct uvc_video_device *device;
+       struct uvc_video_chain *chain;
+       struct uvc_streaming *stream;
        enum uvc_handle_state state;
 };
 
@@ -757,13 +601,13 @@ static inline int uvc_queue_streaming(struct uvc_video_queue *queue)
 extern const struct v4l2_file_operations uvc_fops;
 
 /* Video */
-extern int uvc_video_init(struct uvc_video_device *video);
-extern int uvc_video_suspend(struct uvc_video_device *video);
-extern int uvc_video_resume(struct uvc_video_device *video);
-extern int uvc_video_enable(struct uvc_video_device *video, int enable);
-extern int uvc_probe_video(struct uvc_video_device *video,
+extern int uvc_video_init(struct uvc_streaming *stream);
+extern int uvc_video_suspend(struct uvc_streaming *stream);
+extern int uvc_video_resume(struct uvc_streaming *stream);
+extern int uvc_video_enable(struct uvc_streaming *stream, int enable);
+extern int uvc_probe_video(struct uvc_streaming *stream,
                struct uvc_streaming_control *probe);
-extern int uvc_commit_video(struct uvc_video_device *video,
+extern int uvc_commit_video(struct uvc_streaming *stream,
                struct uvc_streaming_control *ctrl);
 extern int uvc_query_ctrl(struct uvc_device *dev, __u8 query, __u8 unit,
                __u8 intfnum, __u8 cs, void *data, __u16 size);
@@ -777,9 +621,9 @@ extern int uvc_status_suspend(struct uvc_device *dev);
 extern int uvc_status_resume(struct uvc_device *dev);
 
 /* Controls */
-extern struct uvc_control *uvc_find_control(struct uvc_video_device *video,
+extern struct uvc_control *uvc_find_control(struct uvc_video_chain *chain,
                __u32 v4l2_id, struct uvc_control_mapping **mapping);
-extern int uvc_query_v4l2_ctrl(struct uvc_video_device *video,
+extern int uvc_query_v4l2_ctrl(struct uvc_video_chain *chain,
                struct v4l2_queryctrl *v4l2_ctrl);
 
 extern int uvc_ctrl_add_info(struct uvc_control_info *info);
@@ -789,23 +633,23 @@ extern void uvc_ctrl_cleanup_device(struct uvc_device *dev);
 extern int uvc_ctrl_resume_device(struct uvc_device *dev);
 extern void uvc_ctrl_init(void);
 
-extern int uvc_ctrl_begin(struct uvc_video_device *video);
-extern int __uvc_ctrl_commit(struct uvc_video_device *video, int rollback);
-static inline int uvc_ctrl_commit(struct uvc_video_device *video)
+extern int uvc_ctrl_begin(struct uvc_video_chain *chain);
+extern int __uvc_ctrl_commit(struct uvc_video_chain *chain, int rollback);
+static inline int uvc_ctrl_commit(struct uvc_video_chain *chain)
 {
-       return __uvc_ctrl_commit(video, 0);
+       return __uvc_ctrl_commit(chain, 0);
 }
-static inline int uvc_ctrl_rollback(struct uvc_video_device *video)
+static inline int uvc_ctrl_rollback(struct uvc_video_chain *chain)
 {
-       return __uvc_ctrl_commit(video, 1);
+       return __uvc_ctrl_commit(chain, 1);
 }
 
-extern int uvc_ctrl_get(struct uvc_video_device *video,
+extern int uvc_ctrl_get(struct uvc_video_chain *chain,
                struct v4l2_ext_control *xctrl);
-extern int uvc_ctrl_set(struct uvc_video_device *video,
+extern int uvc_ctrl_set(struct uvc_video_chain *chain,
                struct v4l2_ext_control *xctrl);
 
-extern int uvc_xu_ctrl_query(struct uvc_video_device *video,
+extern int uvc_xu_ctrl_query(struct uvc_video_chain *chain,
                struct uvc_xu_control *ctrl, int set);
 
 /* Utility functions */
@@ -817,7 +661,7 @@ extern struct usb_host_endpoint *uvc_find_endpoint(
                struct usb_host_interface *alts, __u8 epaddr);
 
 /* Quirks support */
-void uvc_video_decode_isight(struct urb *urb, struct uvc_video_device *video,
+void uvc_video_decode_isight(struct urb *urb, struct uvc_streaming *stream,
                struct uvc_buffer *buf);
 
 #endif /* __KERNEL__ */
index 02f2a6d18b4582987e1ce0ade96ba510738093ff..761fbd64db5850adfeba11a8cc3b32ba0f7f75a4 100644 (file)
@@ -76,9 +76,8 @@ get_v4l_control(struct file             *file,
                        dprintk("VIDIOC_G_CTRL: %d\n", err);
                        return 0;
                }
-               return ((ctrl2.value - qctrl2.minimum) * 65535
-                        + (qctrl2.maximum - qctrl2.minimum) / 2)
-                       / (qctrl2.maximum - qctrl2.minimum);
+               return DIV_ROUND_CLOSEST((ctrl2.value-qctrl2.minimum) * 65535,
+                                        qctrl2.maximum - qctrl2.minimum);
        }
        return 0;
 }
index b91d66a767d70a3fa825d9c309941fc358d9ee94..3a0c64935b0ed43d1ada0444b7803f49f3f9e0f8 100644 (file)
@@ -156,6 +156,8 @@ int v4l2_ctrl_check(struct v4l2_ext_control *ctrl, struct v4l2_queryctrl *qctrl,
                return -EINVAL;
        if (qctrl->flags & V4L2_CTRL_FLAG_GRABBED)
                return -EBUSY;
+       if (qctrl->type == V4L2_CTRL_TYPE_STRING)
+               return 0;
        if (qctrl->type == V4L2_CTRL_TYPE_BUTTON ||
            qctrl->type == V4L2_CTRL_TYPE_INTEGER64 ||
            qctrl->type == V4L2_CTRL_TYPE_CTRL_CLASS)
@@ -340,6 +342,12 @@ const char **v4l2_ctrl_get_menu(u32 id)
                "Sepia",
                NULL
        };
+       static const char *tune_preemphasis[] = {
+               "No preemphasis",
+               "50 useconds",
+               "75 useconds",
+               NULL,
+       };
 
        switch (id) {
                case V4L2_CID_MPEG_AUDIO_SAMPLING_FREQ:
@@ -378,6 +386,8 @@ const char **v4l2_ctrl_get_menu(u32 id)
                        return camera_exposure_auto;
                case V4L2_CID_COLORFX:
                        return colorfx;
+               case V4L2_CID_TUNE_PREEMPHASIS:
+                       return tune_preemphasis;
                default:
                        return NULL;
        }
@@ -476,6 +486,28 @@ const char *v4l2_ctrl_get_name(u32 id)
        case V4L2_CID_ZOOM_CONTINUOUS:          return "Zoom, Continuous";
        case V4L2_CID_PRIVACY:                  return "Privacy";
 
+       /* FM Radio Modulator control */
+       case V4L2_CID_FM_TX_CLASS:              return "FM Radio Modulator Controls";
+       case V4L2_CID_RDS_TX_DEVIATION:         return "RDS Signal Deviation";
+       case V4L2_CID_RDS_TX_PI:                return "RDS Program ID";
+       case V4L2_CID_RDS_TX_PTY:               return "RDS Program Type";
+       case V4L2_CID_RDS_TX_PS_NAME:           return "RDS PS Name";
+       case V4L2_CID_RDS_TX_RADIO_TEXT:        return "RDS Radio Text";
+       case V4L2_CID_AUDIO_LIMITER_ENABLED:    return "Audio Limiter Feature Enabled";
+       case V4L2_CID_AUDIO_LIMITER_RELEASE_TIME: return "Audio Limiter Release Time";
+       case V4L2_CID_AUDIO_LIMITER_DEVIATION:  return "Audio Limiter Deviation";
+       case V4L2_CID_AUDIO_COMPRESSION_ENABLED: return "Audio Compression Feature Enabled";
+       case V4L2_CID_AUDIO_COMPRESSION_GAIN:   return "Audio Compression Gain";
+       case V4L2_CID_AUDIO_COMPRESSION_THRESHOLD: return "Audio Compression Threshold";
+       case V4L2_CID_AUDIO_COMPRESSION_ATTACK_TIME: return "Audio Compression Attack Time";
+       case V4L2_CID_AUDIO_COMPRESSION_RELEASE_TIME: return "Audio Compression Release Time";
+       case V4L2_CID_PILOT_TONE_ENABLED:       return "Pilot Tone Feature Enabled";
+       case V4L2_CID_PILOT_TONE_DEVIATION:     return "Pilot Tone Deviation";
+       case V4L2_CID_PILOT_TONE_FREQUENCY:     return "Pilot Tone Frequency";
+       case V4L2_CID_TUNE_PREEMPHASIS: return "Pre-emphasis settings";
+       case V4L2_CID_TUNE_POWER_LEVEL:         return "Tune Power Level";
+       case V4L2_CID_TUNE_ANTENNA_CAPACITOR:   return "Tune Antenna Capacitor";
+
        default:
                return NULL;
        }
@@ -508,6 +540,9 @@ int v4l2_ctrl_query_fill(struct v4l2_queryctrl *qctrl, s32 min, s32 max, s32 ste
        case V4L2_CID_EXPOSURE_AUTO_PRIORITY:
        case V4L2_CID_FOCUS_AUTO:
        case V4L2_CID_PRIVACY:
+       case V4L2_CID_AUDIO_LIMITER_ENABLED:
+       case V4L2_CID_AUDIO_COMPRESSION_ENABLED:
+       case V4L2_CID_PILOT_TONE_ENABLED:
                qctrl->type = V4L2_CTRL_TYPE_BOOLEAN;
                min = 0;
                max = step = 1;
@@ -536,12 +571,18 @@ int v4l2_ctrl_query_fill(struct v4l2_queryctrl *qctrl, s32 min, s32 max, s32 ste
        case V4L2_CID_MPEG_STREAM_VBI_FMT:
        case V4L2_CID_EXPOSURE_AUTO:
        case V4L2_CID_COLORFX:
+       case V4L2_CID_TUNE_PREEMPHASIS:
                qctrl->type = V4L2_CTRL_TYPE_MENU;
                step = 1;
                break;
+       case V4L2_CID_RDS_TX_PS_NAME:
+       case V4L2_CID_RDS_TX_RADIO_TEXT:
+               qctrl->type = V4L2_CTRL_TYPE_STRING;
+               break;
        case V4L2_CID_USER_CLASS:
        case V4L2_CID_CAMERA_CLASS:
        case V4L2_CID_MPEG_CLASS:
+       case V4L2_CID_FM_TX_CLASS:
                qctrl->type = V4L2_CTRL_TYPE_CTRL_CLASS;
                qctrl->flags |= V4L2_CTRL_FLAG_READ_ONLY;
                min = max = step = def = 0;
@@ -570,6 +611,17 @@ int v4l2_ctrl_query_fill(struct v4l2_queryctrl *qctrl, s32 min, s32 max, s32 ste
        case V4L2_CID_BLUE_BALANCE:
        case V4L2_CID_GAMMA:
        case V4L2_CID_SHARPNESS:
+       case V4L2_CID_RDS_TX_DEVIATION:
+       case V4L2_CID_AUDIO_LIMITER_RELEASE_TIME:
+       case V4L2_CID_AUDIO_LIMITER_DEVIATION:
+       case V4L2_CID_AUDIO_COMPRESSION_GAIN:
+       case V4L2_CID_AUDIO_COMPRESSION_THRESHOLD:
+       case V4L2_CID_AUDIO_COMPRESSION_ATTACK_TIME:
+       case V4L2_CID_AUDIO_COMPRESSION_RELEASE_TIME:
+       case V4L2_CID_PILOT_TONE_DEVIATION:
+       case V4L2_CID_PILOT_TONE_FREQUENCY:
+       case V4L2_CID_TUNE_POWER_LEVEL:
+       case V4L2_CID_TUNE_ANTENNA_CAPACITOR:
                qctrl->flags |= V4L2_CTRL_FLAG_SLIDER;
                break;
        case V4L2_CID_PAN_RELATIVE:
index 0056b115b42e488239b56bc7793e1a105a67c0b2..997975d5e024b06934e0a4d1d39bba4c091be85b 100644 (file)
@@ -600,9 +600,37 @@ struct v4l2_ext_controls32 {
        compat_caddr_t controls; /* actually struct v4l2_ext_control32 * */
 };
 
+struct v4l2_ext_control32 {
+       __u32 id;
+       __u32 size;
+       __u32 reserved2[1];
+       union {
+               __s32 value;
+               __s64 value64;
+               compat_caddr_t string; /* actually char * */
+       };
+} __attribute__ ((packed));
+
+/* The following function really belong in v4l2-common, but that causes
+   a circular dependency between modules. We need to think about this, but
+   for now this will do. */
+
+/* Return non-zero if this control is a pointer type. Currently only
+   type STRING is a pointer type. */
+static inline int ctrl_is_pointer(u32 id)
+{
+       switch (id) {
+       case V4L2_CID_RDS_TX_PS_NAME:
+       case V4L2_CID_RDS_TX_RADIO_TEXT:
+               return 1;
+       default:
+               return 0;
+       }
+}
+
 static int get_v4l2_ext_controls32(struct v4l2_ext_controls *kp, struct v4l2_ext_controls32 __user *up)
 {
-       struct v4l2_ext_control __user *ucontrols;
+       struct v4l2_ext_control32 __user *ucontrols;
        struct v4l2_ext_control __user *kcontrols;
        int n;
        compat_caddr_t p;
@@ -626,15 +654,17 @@ static int get_v4l2_ext_controls32(struct v4l2_ext_controls *kp, struct v4l2_ext
        kcontrols = compat_alloc_user_space(n * sizeof(struct v4l2_ext_control));
        kp->controls = kcontrols;
        while (--n >= 0) {
-               if (copy_in_user(&kcontrols->id, &ucontrols->id, sizeof(__u32)))
-                       return -EFAULT;
-               if (copy_in_user(&kcontrols->reserved2, &ucontrols->reserved2, sizeof(ucontrols->reserved2)))
-                       return -EFAULT;
-               /* Note: if the void * part of the union ever becomes relevant
-                  then we need to know the type of the control in order to do
-                  the right thing here. Luckily, that is not yet an issue. */
-               if (copy_in_user(&kcontrols->value, &ucontrols->value, sizeof(ucontrols->value)))
+               if (copy_in_user(kcontrols, ucontrols, sizeof(*kcontrols)))
                        return -EFAULT;
+               if (ctrl_is_pointer(kcontrols->id)) {
+                       void __user *s;
+
+                       if (get_user(p, &ucontrols->string))
+                               return -EFAULT;
+                       s = compat_ptr(p);
+                       if (put_user(s, &kcontrols->string))
+                               return -EFAULT;
+               }
                ucontrols++;
                kcontrols++;
        }
@@ -643,7 +673,7 @@ static int get_v4l2_ext_controls32(struct v4l2_ext_controls *kp, struct v4l2_ext
 
 static int put_v4l2_ext_controls32(struct v4l2_ext_controls *kp, struct v4l2_ext_controls32 __user *up)
 {
-       struct v4l2_ext_control __user *ucontrols;
+       struct v4l2_ext_control32 __user *ucontrols;
        struct v4l2_ext_control __user *kcontrols = kp->controls;
        int n = kp->count;
        compat_caddr_t p;
@@ -664,15 +694,14 @@ static int put_v4l2_ext_controls32(struct v4l2_ext_controls *kp, struct v4l2_ext
                return -EFAULT;
 
        while (--n >= 0) {
-               if (copy_in_user(&ucontrols->id, &kcontrols->id, sizeof(__u32)))
-                       return -EFAULT;
-               if (copy_in_user(&ucontrols->reserved2, &kcontrols->reserved2,
-                                       sizeof(ucontrols->reserved2)))
-                       return -EFAULT;
-               /* Note: if the void * part of the union ever becomes relevant
-                  then we need to know the type of the control in order to do
-                  the right thing here. Luckily, that is not yet an issue. */
-               if (copy_in_user(&ucontrols->value, &kcontrols->value, sizeof(ucontrols->value)))
+               unsigned size = sizeof(*ucontrols);
+
+               /* Do not modify the pointer when copying a pointer control.
+                  The contents of the pointer was changed, not the pointer
+                  itself. */
+               if (ctrl_is_pointer(kcontrols->id))
+                       size -= sizeof(ucontrols->value64);
+               if (copy_in_user(ucontrols, kcontrols, size))
                        return -EFAULT;
                ucontrols++;
                kcontrols++;
index f2afc4e08379a1cee0c77201190dd698db576fbb..30cc3347ae52a417c83c9c899cb9c39f88b36667 100644 (file)
                        printk(KERN_DEBUG "%s: " fmt, vfd->name, ## arg);\
                } while (0)
 
+#define dbgarg3(fmt, arg...) \
+               do {                                                    \
+                   if (vfd->debug & V4L2_DEBUG_IOCTL_ARG)              \
+                       printk(KERN_CONT "%s: " fmt, vfd->name, ## arg);\
+               } while (0)
+
 /* Zero out the end of the struct pointed to by p.  Everthing after, but
  * not including, the specified field is cleared. */
 #define CLEAR_AFTER_FIELD(p, field) \
@@ -507,11 +513,12 @@ static inline void v4l_print_ext_ctrls(unsigned int cmd,
        dbgarg(cmd, "");
        printk(KERN_CONT "class=0x%x", c->ctrl_class);
        for (i = 0; i < c->count; i++) {
-               if (show_vals)
+               if (show_vals && !c->controls[i].size)
                        printk(KERN_CONT " id/val=0x%x/0x%x",
                                c->controls[i].id, c->controls[i].value);
                else
-                       printk(KERN_CONT " id=0x%x", c->controls[i].id);
+                       printk(KERN_CONT " id=0x%x,size=%u",
+                               c->controls[i].id, c->controls[i].size);
        }
        printk(KERN_CONT "\n");
 };
@@ -522,10 +529,9 @@ static inline int check_ext_ctrls(struct v4l2_ext_controls *c, int allow_priv)
 
        /* zero the reserved fields */
        c->reserved[0] = c->reserved[1] = 0;
-       for (i = 0; i < c->count; i++) {
+       for (i = 0; i < c->count; i++)
                c->controls[i].reserved2[0] = 0;
-               c->controls[i].reserved2[1] = 0;
-       }
+
        /* V4L2_CID_PRIVATE_BASE cannot be used as control class
           when using extended controls.
           Only when passed in through VIDIOC_G_CTRL and VIDIOC_S_CTRL
@@ -1726,24 +1732,29 @@ static long __video_do_ioctl(struct file *file,
 
                ret = ops->vidioc_enum_framesizes(file, fh, p);
                dbgarg(cmd,
-                       "index=%d, pixelformat=%d, type=%d ",
-                       p->index, p->pixel_format, p->type);
+                       "index=%d, pixelformat=%c%c%c%c, type=%d ",
+                       p->index,
+                       (p->pixel_format & 0xff),
+                       (p->pixel_format >>  8) & 0xff,
+                       (p->pixel_format >> 16) & 0xff,
+                       (p->pixel_format >> 24) & 0xff,
+                       p->type);
                switch (p->type) {
                case V4L2_FRMSIZE_TYPE_DISCRETE:
-                       dbgarg2("width = %d, height=%d\n",
+                       dbgarg3("width = %d, height=%d\n",
                                p->discrete.width, p->discrete.height);
                        break;
                case V4L2_FRMSIZE_TYPE_STEPWISE:
-                       dbgarg2("min %dx%d, max %dx%d, step %dx%d\n",
+                       dbgarg3("min %dx%d, max %dx%d, step %dx%d\n",
                                p->stepwise.min_width,  p->stepwise.min_height,
                                p->stepwise.step_width, p->stepwise.step_height,
                                p->stepwise.max_width,  p->stepwise.max_height);
                        break;
                case V4L2_FRMSIZE_TYPE_CONTINUOUS:
-                       dbgarg2("continuous\n");
+                       dbgarg3("continuous\n");
                        break;
                default:
-                       dbgarg2("- Unknown type!\n");
+                       dbgarg3("- Unknown type!\n");
                }
 
                break;
index 97b082fe44736423bf2a2240abc962cfdb90f999..f3b6e15d91f2b40df6e53a685c084a9807c0846b 100644 (file)
@@ -1776,7 +1776,6 @@ static struct i2c_algo_sgi_data i2c_sgi_vino_data = {
 
 static struct i2c_adapter vino_i2c_adapter = {
        .name                   = "VINO I2C bus",
-       .id                     = I2C_HW_SGI_VINO,
        .algo                   = &sgi_algo,
        .algo_data              = &i2c_sgi_vino_data,
        .owner                  = THIS_MODULE,
index 6c3f23e31b5cd19ab2a6bf73726d045bea199753..602484dd3da9385470abcfbbc7b03c569faa38b7 100644 (file)
@@ -1497,7 +1497,6 @@ static int w9968cf_i2c_init(struct w9968cf_device* cam)
        };
 
        static struct i2c_adapter adap = {
-               .id =                I2C_HW_SMBUS_W9968CF,
                .owner =             THIS_MODULE,
                .algo =              &algo,
        };
index 03dc2f3cf84af17d33530a3a6b6cc941764dbdd2..0c4d9b1f8e6f5ff455cee719ec7165209271f4ba 100644 (file)
@@ -732,7 +732,6 @@ zoran_register_i2c (struct zoran *zr)
        memcpy(&zr->i2c_algo, &zoran_i2c_bit_data_template,
               sizeof(struct i2c_algo_bit_data));
        zr->i2c_algo.data = zr;
-       zr->i2c_adapter.id = I2C_HW_B_ZR36067;
        strlcpy(zr->i2c_adapter.name, ZR_DEVNAME(zr),
                sizeof(zr->i2c_adapter.name));
        i2c_set_adapdata(&zr->i2c_adapter, &zr->v4l2_dev);
@@ -1169,7 +1168,7 @@ zoran_setup_videocodec (struct zoran *zr,
        m->type = 0;
 
        m->flags = CODEC_FLAG_ENCODER | CODEC_FLAG_DECODER;
-       strncpy(m->name, ZR_DEVNAME(zr), sizeof(m->name));
+       strlcpy(m->name, ZR_DEVNAME(zr), sizeof(m->name));
        m->data = zr;
 
        switch (type)
index 2622a6e63da1ed78b1bcaae07b164a33d13c1e66..9aae011d92abb9b1beff9e1ff14266166976dfd8 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Zoran 364xx based USB webcam module version 0.72
+ * Zoran 364xx based USB webcam module version 0.73
  *
  * Allows you to use your USB webcam with V4L2 applications
  * This is still in heavy developpement !
@@ -10,6 +10,8 @@
  * Heavily inspired by usb-skeleton.c, vicam.c, cpia.c and spca50x.c drivers
  * V4L2 version inspired by meye.c driver
  *
+ * Some video buffer code by Lamarque based on s2255drv.c and vivi.c drivers.
+ *
  * 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
@@ -27,6 +29,7 @@
 
 
 #include <linux/module.h>
+#include <linux/version.h>
 #include <linux/init.h>
 #include <linux/usb.h>
 #include <linux/vmalloc.h>
 #include <linux/highmem.h>
 #include <media/v4l2-common.h>
 #include <media/v4l2-ioctl.h>
+#include <media/videobuf-vmalloc.h>
 
 
 /* Version Information */
-#define DRIVER_VERSION "v0.72"
+#define DRIVER_VERSION "v0.73"
+#define ZR364XX_VERSION_CODE KERNEL_VERSION(0, 7, 3)
 #define DRIVER_AUTHOR "Antoine Jacquet, http://royale.zerezo.com/"
 #define DRIVER_DESC "Zoran 364xx"
 
 
 /* Camera */
-#define FRAMES 2
-#define MAX_FRAME_SIZE 100000
+#define FRAMES 1
+#define MAX_FRAME_SIZE 200000
 #define BUFFER_SIZE 0x1000
 #define CTRL_TIMEOUT 500
 
+#define ZR364XX_DEF_BUFS       4
+#define ZR364XX_READ_IDLE      0
+#define ZR364XX_READ_FRAME     1
 
 /* Debug macro */
-#define DBG(x...) if (debug) printk(KERN_INFO KBUILD_MODNAME x)
-
+#define DBG(fmt, args...) \
+       do { \
+               if (debug) { \
+                       printk(KERN_INFO KBUILD_MODNAME " " fmt, ##args); \
+               } \
+       } while (0)
+
+/*#define FULL_DEBUG 1*/
+#ifdef FULL_DEBUG
+#define _DBG DBG
+#else
+#define _DBG(fmt, args...)
+#endif
 
 /* Init methods, need to find nicer names for these
  * the exact names of the chipsets would be the best if someone finds it */
@@ -101,24 +120,93 @@ static struct usb_device_id device_table[] = {
 
 MODULE_DEVICE_TABLE(usb, device_table);
 
+struct zr364xx_mode {
+       u32 color;      /* output video color format */
+       u32 brightness; /* brightness */
+};
+
+/* frame structure */
+struct zr364xx_framei {
+       unsigned long ulState;  /* ulState:ZR364XX_READ_IDLE,
+                                          ZR364XX_READ_FRAME */
+       void *lpvbits;          /* image data */
+       unsigned long cur_size; /* current data copied to it */
+};
+
+/* image buffer structure */
+struct zr364xx_bufferi {
+       unsigned long dwFrames;                 /* number of frames in buffer */
+       struct zr364xx_framei frame[FRAMES];    /* array of FRAME structures */
+};
+
+struct zr364xx_dmaqueue {
+       struct list_head        active;
+       struct zr364xx_camera   *cam;
+};
+
+struct zr364xx_pipeinfo {
+       u32 transfer_size;
+       u8 *transfer_buffer;
+       u32 state;
+       void *stream_urb;
+       void *cam;      /* back pointer to zr364xx_camera struct */
+       u32 err_count;
+       u32 idx;
+};
+
+struct zr364xx_fmt {
+       char *name;
+       u32 fourcc;
+       int depth;
+};
+
+/* image formats.  */
+static const struct zr364xx_fmt formats[] = {
+       {
+               .name = "JPG",
+               .fourcc = V4L2_PIX_FMT_JPEG,
+               .depth = 24
+       }
+};
 
 /* Camera stuff */
 struct zr364xx_camera {
        struct usb_device *udev;        /* save off the usb device pointer */
        struct usb_interface *interface;/* the interface for this device */
        struct video_device *vdev;      /* v4l video device */
-       u8 *framebuf;
        int nb;
-       unsigned char *buffer;
+       struct zr364xx_bufferi          buffer;
        int skip;
-       int brightness;
        int width;
        int height;
        int method;
        struct mutex lock;
+       struct mutex open_lock;
        int users;
+
+       spinlock_t              slock;
+       struct zr364xx_dmaqueue vidq;
+       int                     resources;
+       int                     last_frame;
+       int                     cur_frame;
+       unsigned long           frame_count;
+       int                     b_acquire;
+       struct zr364xx_pipeinfo pipe[1];
+
+       u8                      read_endpoint;
+
+       const struct zr364xx_fmt *fmt;
+       struct videobuf_queue   vb_vidq;
+       enum v4l2_buf_type      type;
+       struct zr364xx_mode     mode;
 };
 
+/* buffer for one video frame */
+struct zr364xx_buffer {
+       /* common v4l buffer stuff -- must be first */
+       struct videobuf_buffer vb;
+       const struct zr364xx_fmt *fmt;
+};
 
 /* function used to send initialisation commands to the camera */
 static int send_control_msg(struct usb_device *udev, u8 request, u16 value,
@@ -272,139 +360,116 @@ static unsigned char header2[] = {
 };
 static unsigned char header3;
 
+/* ------------------------------------------------------------------
+   Videobuf operations
+   ------------------------------------------------------------------*/
 
+static int buffer_setup(struct videobuf_queue *vq, unsigned int *count,
+                       unsigned int *size)
+{
+       struct zr364xx_camera *cam = vq->priv_data;
 
-/********************/
-/* V4L2 integration */
-/********************/
+       *size = cam->width * cam->height * (cam->fmt->depth >> 3);
 
-/* this function reads a full JPEG picture synchronously
- * TODO: do it asynchronously... */
-static int read_frame(struct zr364xx_camera *cam, int framenum)
-{
-       int i, n, temp, head, size, actual_length;
-       unsigned char *ptr = NULL, *jpeg;
-
-      redo:
-       /* hardware brightness */
-       n = send_control_msg(cam->udev, 1, 0x2001, 0, NULL, 0);
-       temp = (0x60 << 8) + 127 - cam->brightness;
-       n = send_control_msg(cam->udev, 1, temp, 0, NULL, 0);
-
-       /* during the first loop we are going to insert JPEG header */
-       head = 0;
-       /* this is the place in memory where we are going to build
-        * the JPEG image */
-       jpeg = cam->framebuf + framenum * MAX_FRAME_SIZE;
-       /* read data... */
-       do {
-               n = usb_bulk_msg(cam->udev,
-                                usb_rcvbulkpipe(cam->udev, 0x81),
-                                cam->buffer, BUFFER_SIZE, &actual_length,
-                                CTRL_TIMEOUT);
-               DBG("buffer : %d %d", cam->buffer[0], cam->buffer[1]);
-               DBG("bulk : n=%d size=%d", n, actual_length);
-               if (n < 0) {
-                       dev_err(&cam->udev->dev, "error reading bulk msg\n");
-                       return 0;
-               }
-               if (actual_length < 0 || actual_length > BUFFER_SIZE) {
-                       dev_err(&cam->udev->dev, "wrong number of bytes\n");
-                       return 0;
-               }
+       if (*count == 0)
+               *count = ZR364XX_DEF_BUFS;
 
-               /* swap bytes if camera needs it */
-               if (cam->method == METHOD0) {
-                       u16 *buf = (u16*)cam->buffer;
-                       for (i = 0; i < BUFFER_SIZE/2; i++)
-                               swab16s(buf + i);
-               }
+       while (*size * (*count) > ZR364XX_DEF_BUFS * 1024 * 1024)
+               (*count)--;
 
-               /* write the JPEG header */
-               if (!head) {
-                       DBG("jpeg header");
-                       ptr = jpeg;
-                       memcpy(ptr, header1, sizeof(header1));
-                       ptr += sizeof(header1);
-                       header3 = 0;
-                       memcpy(ptr, &header3, 1);
-                       ptr++;
-                       memcpy(ptr, cam->buffer, 64);
-                       ptr += 64;
-                       header3 = 1;
-                       memcpy(ptr, &header3, 1);
-                       ptr++;
-                       memcpy(ptr, cam->buffer + 64, 64);
-                       ptr += 64;
-                       memcpy(ptr, header2, sizeof(header2));
-                       ptr += sizeof(header2);
-                       memcpy(ptr, cam->buffer + 128,
-                              actual_length - 128);
-                       ptr += actual_length - 128;
-                       head = 1;
-                       DBG("header : %d %d %d %d %d %d %d %d %d",
-                           cam->buffer[0], cam->buffer[1], cam->buffer[2],
-                           cam->buffer[3], cam->buffer[4], cam->buffer[5],
-                           cam->buffer[6], cam->buffer[7], cam->buffer[8]);
-               } else {
-                       memcpy(ptr, cam->buffer, actual_length);
-                       ptr += actual_length;
-               }
-       }
-       /* ... until there is no more */
-       while (actual_length == BUFFER_SIZE);
+       return 0;
+}
 
-       /* we skip the 2 first frames which are usually buggy */
-       if (cam->skip) {
-               cam->skip--;
-               goto redo;
-       }
+static void free_buffer(struct videobuf_queue *vq, struct zr364xx_buffer *buf)
+{
+       _DBG("%s\n", __func__);
 
-       /* go back to find the JPEG EOI marker */
-       size = ptr - jpeg;
-       ptr -= 2;
-       while (ptr > jpeg) {
-               if (*ptr == 0xFF && *(ptr + 1) == 0xD9
-                   && *(ptr + 2) == 0xFF)
-                       break;
-               ptr--;
-       }
-       if (ptr == jpeg)
-               DBG("No EOI marker");
+       if (in_interrupt())
+               BUG();
 
-       /* Sometimes there is junk data in the middle of the picture,
-        * we want to skip this bogus frames */
-       while (ptr > jpeg) {
-               if (*ptr == 0xFF && *(ptr + 1) == 0xFF
-                   && *(ptr + 2) == 0xFF)
-                       break;
-               ptr--;
+       videobuf_vmalloc_free(&buf->vb);
+       buf->vb.state = VIDEOBUF_NEEDS_INIT;
+}
+
+static int buffer_prepare(struct videobuf_queue *vq, struct videobuf_buffer *vb,
+                         enum v4l2_field field)
+{
+       struct zr364xx_camera *cam = vq->priv_data;
+       struct zr364xx_buffer *buf = container_of(vb, struct zr364xx_buffer,
+                                                 vb);
+       int rc;
+
+       DBG("%s, field=%d, fmt name = %s\n", __func__, field, cam->fmt != NULL ?
+           cam->fmt->name : "");
+       if (cam->fmt == NULL)
+               return -EINVAL;
+
+       buf->vb.size = cam->width * cam->height * (cam->fmt->depth >> 3);
+
+       if (buf->vb.baddr != 0 && buf->vb.bsize < buf->vb.size) {
+               DBG("invalid buffer prepare\n");
+               return -EINVAL;
        }
-       if (ptr != jpeg) {
-               DBG("Bogus frame ? %d", cam->nb);
-               goto redo;
+
+       buf->fmt = cam->fmt;
+       buf->vb.width = cam->width;
+       buf->vb.height = cam->height;
+       buf->vb.field = field;
+
+       if (buf->vb.state == VIDEOBUF_NEEDS_INIT) {
+               rc = videobuf_iolock(vq, &buf->vb, NULL);
+               if (rc < 0)
+                       goto fail;
        }
 
-       DBG("jpeg : %d %d %d %d %d %d %d %d",
-           jpeg[0], jpeg[1], jpeg[2], jpeg[3],
-           jpeg[4], jpeg[5], jpeg[6], jpeg[7]);
+       buf->vb.state = VIDEOBUF_PREPARED;
+       return 0;
+fail:
+       free_buffer(vq, buf);
+       return rc;
+}
+
+static void buffer_queue(struct videobuf_queue *vq, struct videobuf_buffer *vb)
+{
+       struct zr364xx_buffer *buf = container_of(vb, struct zr364xx_buffer,
+                                                 vb);
+       struct zr364xx_camera *cam = vq->priv_data;
+
+       _DBG("%s\n", __func__);
+
+       buf->vb.state = VIDEOBUF_QUEUED;
+       list_add_tail(&buf->vb.queue, &cam->vidq.active);
+}
+
+static void buffer_release(struct videobuf_queue *vq,
+                          struct videobuf_buffer *vb)
+{
+       struct zr364xx_buffer *buf = container_of(vb, struct zr364xx_buffer,
+                                                 vb);
 
-       return size;
+       _DBG("%s\n", __func__);
+       free_buffer(vq, buf);
 }
 
+static struct videobuf_queue_ops zr364xx_video_qops = {
+       .buf_setup = buffer_setup,
+       .buf_prepare = buffer_prepare,
+       .buf_queue = buffer_queue,
+       .buf_release = buffer_release,
+};
+
+/********************/
+/* V4L2 integration */
+/********************/
+static int zr364xx_vidioc_streamon(struct file *file, void *priv,
+                                  enum v4l2_buf_type type);
 
-static ssize_t zr364xx_read(struct file *file, char __user *buf, size_t cnt,
+static ssize_t zr364xx_read(struct file *file, char __user *buf, size_t count,
                            loff_t * ppos)
 {
-       unsigned long count = cnt;
-       struct video_device *vdev = video_devdata(file);
-       struct zr364xx_camera *cam;
+       struct zr364xx_camera *cam = video_drvdata(file);
 
-       DBG("zr364xx_read: read %d bytes.", (int) count);
-
-       if (vdev == NULL)
-               return -ENODEV;
-       cam = video_get_drvdata(vdev);
+       _DBG("%s\n", __func__);
 
        if (!buf)
                return -EINVAL;
@@ -412,21 +477,276 @@ static ssize_t zr364xx_read(struct file *file, char __user *buf, size_t cnt,
        if (!count)
                return -EINVAL;
 
-       /* NoMan Sux ! */
-       count = read_frame(cam, 0);
+       if (cam->type == V4L2_BUF_TYPE_VIDEO_CAPTURE &&
+           zr364xx_vidioc_streamon(file, cam, cam->type) == 0) {
+               DBG("%s: reading %d bytes at pos %d.\n", __func__, (int) count,
+                   (int) *ppos);
+
+               /* NoMan Sux ! */
+               return videobuf_read_one(&cam->vb_vidq, buf, count, ppos,
+                                       file->f_flags & O_NONBLOCK);
+       }
+
+       return 0;
+}
+
+/* video buffer vmalloc implementation based partly on VIVI driver which is
+ *          Copyright (c) 2006 by
+ *                  Mauro Carvalho Chehab <mchehab--a.t--infradead.org>
+ *                  Ted Walther <ted--a.t--enumera.com>
+ *                  John Sokol <sokol--a.t--videotechnology.com>
+ *                  http://v4l.videotechnology.com/
+ *
+ */
+static void zr364xx_fillbuff(struct zr364xx_camera *cam,
+                            struct zr364xx_buffer *buf,
+                            int jpgsize)
+{
+       int pos = 0;
+       struct timeval ts;
+       const char *tmpbuf;
+       char *vbuf = videobuf_to_vmalloc(&buf->vb);
+       unsigned long last_frame;
+       struct zr364xx_framei *frm;
+
+       if (!vbuf)
+               return;
+
+       last_frame = cam->last_frame;
+       if (last_frame != -1) {
+               frm = &cam->buffer.frame[last_frame];
+               tmpbuf = (const char *)cam->buffer.frame[last_frame].lpvbits;
+               switch (buf->fmt->fourcc) {
+               case V4L2_PIX_FMT_JPEG:
+                       buf->vb.size = jpgsize;
+                       memcpy(vbuf, tmpbuf, buf->vb.size);
+                       break;
+               default:
+                       printk(KERN_DEBUG KBUILD_MODNAME ": unknown format?\n");
+               }
+               cam->last_frame = -1;
+       } else {
+               printk(KERN_ERR KBUILD_MODNAME ": =======no frame\n");
+               return;
+       }
+       DBG("%s: Buffer 0x%08lx size= %d\n", __func__,
+               (unsigned long)vbuf, pos);
+       /* tell v4l buffer was filled */
+
+       buf->vb.field_count = cam->frame_count * 2;
+       do_gettimeofday(&ts);
+       buf->vb.ts = ts;
+       buf->vb.state = VIDEOBUF_DONE;
+}
+
+static int zr364xx_got_frame(struct zr364xx_camera *cam, int jpgsize)
+{
+       struct zr364xx_dmaqueue *dma_q = &cam->vidq;
+       struct zr364xx_buffer *buf;
+       unsigned long flags = 0;
+       int rc = 0;
+
+       DBG("wakeup: %p\n", &dma_q);
+       spin_lock_irqsave(&cam->slock, flags);
+
+       if (list_empty(&dma_q->active)) {
+               DBG("No active queue to serve\n");
+               rc = -1;
+               goto unlock;
+       }
+       buf = list_entry(dma_q->active.next,
+                        struct zr364xx_buffer, vb.queue);
+
+       if (!waitqueue_active(&buf->vb.done)) {
+               /* no one active */
+               rc = -1;
+               goto unlock;
+       }
+       list_del(&buf->vb.queue);
+       do_gettimeofday(&buf->vb.ts);
+       DBG("[%p/%d] wakeup\n", buf, buf->vb.i);
+       zr364xx_fillbuff(cam, buf, jpgsize);
+       wake_up(&buf->vb.done);
+       DBG("wakeup [buf/i] [%p/%d]\n", buf, buf->vb.i);
+unlock:
+       spin_unlock_irqrestore(&cam->slock, flags);
+       return 0;
+}
+
+/* this function moves the usb stream read pipe data
+ * into the system buffers.
+ * returns 0 on success, EAGAIN if more data to process (call this
+ * function again).
+ */
+static int zr364xx_read_video_callback(struct zr364xx_camera *cam,
+                                       struct zr364xx_pipeinfo *pipe_info,
+                                       struct urb *purb)
+{
+       unsigned char *pdest;
+       unsigned char *psrc;
+       s32 idx = -1;
+       struct zr364xx_framei *frm;
+       int i = 0;
+       unsigned char *ptr = NULL;
+
+       _DBG("buffer to user\n");
+       idx = cam->cur_frame;
+       frm = &cam->buffer.frame[idx];
+
+       /* swap bytes if camera needs it */
+       if (cam->method == METHOD0) {
+               u16 *buf = (u16 *)pipe_info->transfer_buffer;
+               for (i = 0; i < purb->actual_length/2; i++)
+                       swab16s(buf + i);
+       }
+
+       /* search done.  now find out if should be acquiring */
+       if (!cam->b_acquire) {
+               /* we found a frame, but this channel is turned off */
+               frm->ulState = ZR364XX_READ_IDLE;
+               return -EINVAL;
+       }
+
+       psrc = (u8 *)pipe_info->transfer_buffer;
+       ptr = pdest = frm->lpvbits;
+
+       if (frm->ulState == ZR364XX_READ_IDLE) {
+               frm->ulState = ZR364XX_READ_FRAME;
+               frm->cur_size = 0;
+
+               _DBG("jpeg header, ");
+               memcpy(ptr, header1, sizeof(header1));
+               ptr += sizeof(header1);
+               header3 = 0;
+               memcpy(ptr, &header3, 1);
+               ptr++;
+               memcpy(ptr, psrc, 64);
+               ptr += 64;
+               header3 = 1;
+               memcpy(ptr, &header3, 1);
+               ptr++;
+               memcpy(ptr, psrc + 64, 64);
+               ptr += 64;
+               memcpy(ptr, header2, sizeof(header2));
+               ptr += sizeof(header2);
+               memcpy(ptr, psrc + 128,
+                      purb->actual_length - 128);
+               ptr += purb->actual_length - 128;
+               _DBG("header : %d %d %d %d %d %d %d %d %d\n",
+                   psrc[0], psrc[1], psrc[2],
+                   psrc[3], psrc[4], psrc[5],
+                   psrc[6], psrc[7], psrc[8]);
+               frm->cur_size = ptr - pdest;
+       } else {
+               if (frm->cur_size + purb->actual_length > MAX_FRAME_SIZE) {
+                       dev_info(&cam->udev->dev,
+                                "%s: buffer (%d bytes) too small to hold "
+                                "frame data. Discarding frame data.\n",
+                                __func__, MAX_FRAME_SIZE);
+               } else {
+                       pdest += frm->cur_size;
+                       memcpy(pdest, psrc, purb->actual_length);
+                       frm->cur_size += purb->actual_length;
+               }
+       }
+       /*_DBG("cur_size %lu urb size %d\n", frm->cur_size,
+               purb->actual_length);*/
+
+       if (purb->actual_length < pipe_info->transfer_size) {
+               _DBG("****************Buffer[%d]full*************\n", idx);
+               cam->last_frame = cam->cur_frame;
+               cam->cur_frame++;
+               /* end of system frame ring buffer, start at zero */
+               if (cam->cur_frame == cam->buffer.dwFrames)
+                       cam->cur_frame = 0;
+
+               /* frame ready */
+               /* go back to find the JPEG EOI marker */
+               ptr = pdest = frm->lpvbits;
+               ptr += frm->cur_size - 2;
+               while (ptr > pdest) {
+                       if (*ptr == 0xFF && *(ptr + 1) == 0xD9
+                           && *(ptr + 2) == 0xFF)
+                               break;
+                       ptr--;
+               }
+               if (ptr == pdest)
+                       DBG("No EOI marker\n");
+
+               /* Sometimes there is junk data in the middle of the picture,
+                * we want to skip this bogus frames */
+               while (ptr > pdest) {
+                       if (*ptr == 0xFF && *(ptr + 1) == 0xFF
+                           && *(ptr + 2) == 0xFF)
+                               break;
+                       ptr--;
+               }
+               if (ptr != pdest) {
+                       DBG("Bogus frame ? %d\n", ++(cam->nb));
+               } else if (cam->b_acquire) {
+                       /* we skip the 2 first frames which are usually buggy */
+                       if (cam->skip)
+                               cam->skip--;
+                       else {
+                               _DBG("jpeg(%lu): %d %d %d %d %d %d %d %d\n",
+                                   frm->cur_size,
+                                   pdest[0], pdest[1], pdest[2], pdest[3],
+                                   pdest[4], pdest[5], pdest[6], pdest[7]);
+
+                               zr364xx_got_frame(cam, frm->cur_size);
+                       }
+               }
+               cam->frame_count++;
+               frm->ulState = ZR364XX_READ_IDLE;
+               frm->cur_size = 0;
+       }
+       /* done successfully */
+       return 0;
+}
 
-       if (copy_to_user(buf, cam->framebuf, count))
-               return -EFAULT;
+static int res_get(struct zr364xx_camera *cam)
+{
+       /* is it free? */
+       mutex_lock(&cam->lock);
+       if (cam->resources) {
+               /* no, someone else uses it */
+               mutex_unlock(&cam->lock);
+               return 0;
+       }
+       /* it's free, grab it */
+       cam->resources = 1;
+       _DBG("res: get\n");
+       mutex_unlock(&cam->lock);
+       return 1;
+}
 
-       return count;
+static inline int res_check(struct zr364xx_camera *cam)
+{
+       return cam->resources;
 }
 
+static void res_free(struct zr364xx_camera *cam)
+{
+       mutex_lock(&cam->lock);
+       cam->resources = 0;
+       mutex_unlock(&cam->lock);
+       _DBG("res: put\n");
+}
 
 static int zr364xx_vidioc_querycap(struct file *file, void *priv,
                                   struct v4l2_capability *cap)
 {
-       strcpy(cap->driver, DRIVER_DESC);
-       cap->capabilities = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_READWRITE;
+       struct zr364xx_camera *cam = video_drvdata(file);
+
+       strlcpy(cap->driver, DRIVER_DESC, sizeof(cap->driver));
+       strlcpy(cap->card, cam->udev->product, sizeof(cap->card));
+       strlcpy(cap->bus_info, dev_name(&cam->udev->dev),
+               sizeof(cap->bus_info));
+       cap->version = ZR364XX_VERSION_CODE;
+       cap->capabilities = V4L2_CAP_VIDEO_CAPTURE |
+                           V4L2_CAP_READWRITE |
+                           V4L2_CAP_STREAMING;
+
        return 0;
 }
 
@@ -458,12 +778,11 @@ static int zr364xx_vidioc_s_input(struct file *file, void *priv,
 static int zr364xx_vidioc_queryctrl(struct file *file, void *priv,
                                    struct v4l2_queryctrl *c)
 {
-       struct video_device *vdev = video_devdata(file);
        struct zr364xx_camera *cam;
 
-       if (vdev == NULL)
+       if (file == NULL)
                return -ENODEV;
-       cam = video_get_drvdata(vdev);
+       cam = video_drvdata(file);
 
        switch (c->id) {
        case V4L2_CID_BRIGHTNESS:
@@ -472,7 +791,7 @@ static int zr364xx_vidioc_queryctrl(struct file *file, void *priv,
                c->minimum = 0;
                c->maximum = 127;
                c->step = 1;
-               c->default_value = cam->brightness;
+               c->default_value = cam->mode.brightness;
                c->flags = 0;
                break;
        default:
@@ -484,36 +803,42 @@ static int zr364xx_vidioc_queryctrl(struct file *file, void *priv,
 static int zr364xx_vidioc_s_ctrl(struct file *file, void *priv,
                                 struct v4l2_control *c)
 {
-       struct video_device *vdev = video_devdata(file);
        struct zr364xx_camera *cam;
+       int temp;
 
-       if (vdev == NULL)
+       if (file == NULL)
                return -ENODEV;
-       cam = video_get_drvdata(vdev);
+       cam = video_drvdata(file);
 
        switch (c->id) {
        case V4L2_CID_BRIGHTNESS:
-               cam->brightness = c->value;
+               cam->mode.brightness = c->value;
+               /* hardware brightness */
+               mutex_lock(&cam->lock);
+               send_control_msg(cam->udev, 1, 0x2001, 0, NULL, 0);
+               temp = (0x60 << 8) + 127 - cam->mode.brightness;
+               send_control_msg(cam->udev, 1, temp, 0, NULL, 0);
+               mutex_unlock(&cam->lock);
                break;
        default:
                return -EINVAL;
        }
+
        return 0;
 }
 
 static int zr364xx_vidioc_g_ctrl(struct file *file, void *priv,
                                 struct v4l2_control *c)
 {
-       struct video_device *vdev = video_devdata(file);
        struct zr364xx_camera *cam;
 
-       if (vdev == NULL)
+       if (file == NULL)
                return -ENODEV;
-       cam = video_get_drvdata(vdev);
+       cam = video_drvdata(file);
 
        switch (c->id) {
        case V4L2_CID_BRIGHTNESS:
-               c->value = cam->brightness;
+               c->value = cam->mode.brightness;
                break;
        default:
                return -EINVAL;
@@ -527,47 +852,63 @@ static int zr364xx_vidioc_enum_fmt_vid_cap(struct file *file,
        if (f->index > 0)
                return -EINVAL;
        f->flags = V4L2_FMT_FLAG_COMPRESSED;
-       strcpy(f->description, "JPEG");
-       f->pixelformat = V4L2_PIX_FMT_JPEG;
+       strcpy(f->description, formats[0].name);
+       f->pixelformat = formats[0].fourcc;
        return 0;
 }
 
+static char *decode_fourcc(__u32 pixelformat, char *buf)
+{
+       buf[0] = pixelformat & 0xff;
+       buf[1] = (pixelformat >> 8) & 0xff;
+       buf[2] = (pixelformat >> 16) & 0xff;
+       buf[3] = (pixelformat >> 24) & 0xff;
+       buf[4] = '\0';
+       return buf;
+}
+
 static int zr364xx_vidioc_try_fmt_vid_cap(struct file *file, void *priv,
                                      struct v4l2_format *f)
 {
-       struct video_device *vdev = video_devdata(file);
-       struct zr364xx_camera *cam;
+       struct zr364xx_camera *cam = video_drvdata(file);
+       char pixelformat_name[5];
 
-       if (vdev == NULL)
+       if (cam == NULL)
                return -ENODEV;
-       cam = video_get_drvdata(vdev);
 
-       if (f->fmt.pix.pixelformat != V4L2_PIX_FMT_JPEG)
-               return -EINVAL;
-       if (f->fmt.pix.field != V4L2_FIELD_ANY &&
-           f->fmt.pix.field != V4L2_FIELD_NONE)
+       if (f->fmt.pix.pixelformat != V4L2_PIX_FMT_JPEG) {
+               DBG("%s: unsupported pixelformat V4L2_PIX_FMT_%s\n", __func__,
+                   decode_fourcc(f->fmt.pix.pixelformat, pixelformat_name));
                return -EINVAL;
+       }
+
+       if (!(f->fmt.pix.width == 160 && f->fmt.pix.height == 120) &&
+           !(f->fmt.pix.width == 640 && f->fmt.pix.height == 480)) {
+               f->fmt.pix.width = 320;
+               f->fmt.pix.height = 240;
+       }
+
        f->fmt.pix.field = V4L2_FIELD_NONE;
-       f->fmt.pix.width = cam->width;
-       f->fmt.pix.height = cam->height;
        f->fmt.pix.bytesperline = f->fmt.pix.width * 2;
        f->fmt.pix.sizeimage = f->fmt.pix.height * f->fmt.pix.bytesperline;
        f->fmt.pix.colorspace = 0;
        f->fmt.pix.priv = 0;
+       DBG("%s: V4L2_PIX_FMT_%s (%d) ok!\n", __func__,
+           decode_fourcc(f->fmt.pix.pixelformat, pixelformat_name),
+           f->fmt.pix.field);
        return 0;
 }
 
 static int zr364xx_vidioc_g_fmt_vid_cap(struct file *file, void *priv,
                                    struct v4l2_format *f)
 {
-       struct video_device *vdev = video_devdata(file);
        struct zr364xx_camera *cam;
 
-       if (vdev == NULL)
+       if (file == NULL)
                return -ENODEV;
-       cam = video_get_drvdata(vdev);
+       cam = video_drvdata(file);
 
-       f->fmt.pix.pixelformat = V4L2_PIX_FMT_JPEG;
+       f->fmt.pix.pixelformat = formats[0].fourcc;
        f->fmt.pix.field = V4L2_FIELD_NONE;
        f->fmt.pix.width = cam->width;
        f->fmt.pix.height = cam->height;
@@ -581,38 +922,327 @@ static int zr364xx_vidioc_g_fmt_vid_cap(struct file *file, void *priv,
 static int zr364xx_vidioc_s_fmt_vid_cap(struct file *file, void *priv,
                                    struct v4l2_format *f)
 {
-       struct video_device *vdev = video_devdata(file);
-       struct zr364xx_camera *cam;
+       struct zr364xx_camera *cam = video_drvdata(file);
+       struct videobuf_queue *q = &cam->vb_vidq;
+       char pixelformat_name[5];
+       int ret = zr364xx_vidioc_try_fmt_vid_cap(file, cam, f);
+       int i;
 
-       if (vdev == NULL)
-               return -ENODEV;
-       cam = video_get_drvdata(vdev);
+       if (ret < 0)
+               return ret;
 
-       if (f->fmt.pix.pixelformat != V4L2_PIX_FMT_JPEG)
-               return -EINVAL;
-       if (f->fmt.pix.field != V4L2_FIELD_ANY &&
-           f->fmt.pix.field != V4L2_FIELD_NONE)
-               return -EINVAL;
-       f->fmt.pix.field = V4L2_FIELD_NONE;
-       f->fmt.pix.width = cam->width;
-       f->fmt.pix.height = cam->height;
+       mutex_lock(&q->vb_lock);
+
+       if (videobuf_queue_is_busy(&cam->vb_vidq)) {
+               DBG("%s queue busy\n", __func__);
+               ret = -EBUSY;
+               goto out;
+       }
+
+       if (res_check(cam)) {
+               DBG("%s can't change format after started\n", __func__);
+               ret = -EBUSY;
+               goto out;
+       }
+
+       cam->width = f->fmt.pix.width;
+       cam->height = f->fmt.pix.height;
+       dev_info(&cam->udev->dev, "%s: %dx%d mode selected\n", __func__,
+                cam->width, cam->height);
        f->fmt.pix.bytesperline = f->fmt.pix.width * 2;
        f->fmt.pix.sizeimage = f->fmt.pix.height * f->fmt.pix.bytesperline;
        f->fmt.pix.colorspace = 0;
        f->fmt.pix.priv = 0;
-       DBG("ok!");
+       cam->vb_vidq.field = f->fmt.pix.field;
+       cam->mode.color = V4L2_PIX_FMT_JPEG;
+
+       if (f->fmt.pix.width == 160 && f->fmt.pix.height == 120)
+               mode = 1;
+       else if (f->fmt.pix.width == 640 && f->fmt.pix.height == 480)
+               mode = 2;
+       else
+               mode = 0;
+
+       m0d1[0] = mode;
+       m1[2].value = 0xf000 + mode;
+       m2[1].value = 0xf000 + mode;
+       header2[437] = cam->height / 256;
+       header2[438] = cam->height % 256;
+       header2[439] = cam->width / 256;
+       header2[440] = cam->width % 256;
+
+       for (i = 0; init[cam->method][i].size != -1; i++) {
+               ret =
+                   send_control_msg(cam->udev, 1, init[cam->method][i].value,
+                                    0, init[cam->method][i].bytes,
+                                    init[cam->method][i].size);
+               if (ret < 0) {
+                       dev_err(&cam->udev->dev,
+                          "error during resolution change sequence: %d\n", i);
+                       goto out;
+               }
+       }
+
+       /* Added some delay here, since opening/closing the camera quickly,
+        * like Ekiga does during its startup, can crash the webcam
+        */
+       mdelay(100);
+       cam->skip = 2;
+       ret = 0;
+
+out:
+       mutex_unlock(&q->vb_lock);
+
+       DBG("%s: V4L2_PIX_FMT_%s (%d) ok!\n", __func__,
+           decode_fourcc(f->fmt.pix.pixelformat, pixelformat_name),
+           f->fmt.pix.field);
+       return ret;
+}
+
+static int zr364xx_vidioc_reqbufs(struct file *file, void *priv,
+                         struct v4l2_requestbuffers *p)
+{
+       int rc;
+       struct zr364xx_camera *cam = video_drvdata(file);
+       rc = videobuf_reqbufs(&cam->vb_vidq, p);
+       return rc;
+}
+
+static int zr364xx_vidioc_querybuf(struct file *file,
+                               void *priv,
+                               struct v4l2_buffer *p)
+{
+       int rc;
+       struct zr364xx_camera *cam = video_drvdata(file);
+       rc = videobuf_querybuf(&cam->vb_vidq, p);
+       return rc;
+}
+
+static int zr364xx_vidioc_qbuf(struct file *file,
+                               void *priv,
+                               struct v4l2_buffer *p)
+{
+       int rc;
+       struct zr364xx_camera *cam = video_drvdata(file);
+       _DBG("%s\n", __func__);
+       rc = videobuf_qbuf(&cam->vb_vidq, p);
+       return rc;
+}
+
+static int zr364xx_vidioc_dqbuf(struct file *file,
+                               void *priv,
+                               struct v4l2_buffer *p)
+{
+       int rc;
+       struct zr364xx_camera *cam = video_drvdata(file);
+       _DBG("%s\n", __func__);
+       rc = videobuf_dqbuf(&cam->vb_vidq, p, file->f_flags & O_NONBLOCK);
+       return rc;
+}
+
+static void read_pipe_completion(struct urb *purb)
+{
+       struct zr364xx_pipeinfo *pipe_info;
+       struct zr364xx_camera *cam;
+       int pipe;
+
+       pipe_info = purb->context;
+       _DBG("%s %p, status %d\n", __func__, purb, purb->status);
+       if (pipe_info == NULL) {
+               printk(KERN_ERR KBUILD_MODNAME ": no context!\n");
+               return;
+       }
+
+       cam = pipe_info->cam;
+       if (cam == NULL) {
+               printk(KERN_ERR KBUILD_MODNAME ": no context!\n");
+               return;
+       }
+
+       /* if shutting down, do not resubmit, exit immediately */
+       if (purb->status == -ESHUTDOWN) {
+               DBG("%s, err shutdown\n", __func__);
+               pipe_info->err_count++;
+               return;
+       }
+
+       if (pipe_info->state == 0) {
+               DBG("exiting USB pipe\n");
+               return;
+       }
+
+       if (purb->actual_length < 0 ||
+           purb->actual_length > pipe_info->transfer_size) {
+               dev_err(&cam->udev->dev, "wrong number of bytes\n");
+               return;
+       }
+
+       if (purb->status == 0)
+               zr364xx_read_video_callback(cam, pipe_info, purb);
+       else {
+               pipe_info->err_count++;
+               DBG("%s: failed URB %d\n", __func__, purb->status);
+       }
+
+       pipe = usb_rcvbulkpipe(cam->udev, cam->read_endpoint);
+
+       /* reuse urb */
+       usb_fill_bulk_urb(pipe_info->stream_urb, cam->udev,
+                         pipe,
+                         pipe_info->transfer_buffer,
+                         pipe_info->transfer_size,
+                         read_pipe_completion, pipe_info);
+
+       if (pipe_info->state != 0) {
+               purb->status = usb_submit_urb(pipe_info->stream_urb,
+                                             GFP_ATOMIC);
+
+               if (purb->status)
+                       dev_err(&cam->udev->dev,
+                               "error submitting urb (error=%i)\n",
+                               purb->status);
+       } else
+               DBG("read pipe complete state 0\n");
+}
+
+static int zr364xx_start_readpipe(struct zr364xx_camera *cam)
+{
+       int pipe;
+       int retval;
+       struct zr364xx_pipeinfo *pipe_info = cam->pipe;
+       pipe = usb_rcvbulkpipe(cam->udev, cam->read_endpoint);
+       DBG("%s: start pipe IN x%x\n", __func__, cam->read_endpoint);
+
+       pipe_info->state = 1;
+       pipe_info->err_count = 0;
+       pipe_info->stream_urb = usb_alloc_urb(0, GFP_KERNEL);
+       if (!pipe_info->stream_urb) {
+               dev_err(&cam->udev->dev, "ReadStream: Unable to alloc URB\n");
+               return -ENOMEM;
+       }
+       /* transfer buffer allocated in board_init */
+       usb_fill_bulk_urb(pipe_info->stream_urb, cam->udev,
+                         pipe,
+                         pipe_info->transfer_buffer,
+                         pipe_info->transfer_size,
+                         read_pipe_completion, pipe_info);
+
+       DBG("submitting URB %p\n", pipe_info->stream_urb);
+       retval = usb_submit_urb(pipe_info->stream_urb, GFP_KERNEL);
+       if (retval) {
+               printk(KERN_ERR KBUILD_MODNAME ": start read pipe failed\n");
+               return retval;
+       }
+
+       return 0;
+}
+
+static void zr364xx_stop_readpipe(struct zr364xx_camera *cam)
+{
+       struct zr364xx_pipeinfo *pipe_info;
+
+       if (cam == NULL) {
+               printk(KERN_ERR KBUILD_MODNAME ": invalid device\n");
+               return;
+       }
+       DBG("stop read pipe\n");
+       pipe_info = cam->pipe;
+       if (pipe_info) {
+               if (pipe_info->state != 0)
+                       pipe_info->state = 0;
+
+               if (pipe_info->stream_urb) {
+                       /* cancel urb */
+                       usb_kill_urb(pipe_info->stream_urb);
+                       usb_free_urb(pipe_info->stream_urb);
+                       pipe_info->stream_urb = NULL;
+               }
+       }
+       return;
+}
+
+/* starts acquisition process */
+static int zr364xx_start_acquire(struct zr364xx_camera *cam)
+{
+       int j;
+
+       DBG("start acquire\n");
+
+       cam->last_frame = -1;
+       cam->cur_frame = 0;
+       for (j = 0; j < FRAMES; j++) {
+               cam->buffer.frame[j].ulState = ZR364XX_READ_IDLE;
+               cam->buffer.frame[j].cur_size = 0;
+       }
+       cam->b_acquire = 1;
+       return 0;
+}
+
+static inline int zr364xx_stop_acquire(struct zr364xx_camera *cam)
+{
+       cam->b_acquire = 0;
        return 0;
 }
 
 static int zr364xx_vidioc_streamon(struct file *file, void *priv,
                                   enum v4l2_buf_type type)
 {
-       return 0;
+       struct zr364xx_camera *cam = video_drvdata(file);
+       int j;
+       int res;
+
+       DBG("%s\n", __func__);
+
+       if (cam->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) {
+               dev_err(&cam->udev->dev, "invalid fh type0\n");
+               return -EINVAL;
+       }
+       if (cam->type != type) {
+               dev_err(&cam->udev->dev, "invalid fh type1\n");
+               return -EINVAL;
+       }
+
+       if (!res_get(cam)) {
+               dev_err(&cam->udev->dev, "stream busy\n");
+               return -EBUSY;
+       }
+
+       cam->last_frame = -1;
+       cam->cur_frame = 0;
+       cam->frame_count = 0;
+       for (j = 0; j < FRAMES; j++) {
+               cam->buffer.frame[j].ulState = ZR364XX_READ_IDLE;
+               cam->buffer.frame[j].cur_size = 0;
+       }
+       res = videobuf_streamon(&cam->vb_vidq);
+       if (res == 0) {
+               zr364xx_start_acquire(cam);
+       } else {
+               res_free(cam);
+       }
+       return res;
 }
 
 static int zr364xx_vidioc_streamoff(struct file *file, void *priv,
                                    enum v4l2_buf_type type)
 {
+       int res;
+       struct zr364xx_camera *cam = video_drvdata(file);
+
+       DBG("%s\n", __func__);
+       if (cam->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) {
+               dev_err(&cam->udev->dev, "invalid fh type0\n");
+               return -EINVAL;
+       }
+       if (cam->type != type) {
+               dev_err(&cam->udev->dev, "invalid fh type1\n");
+               return -EINVAL;
+       }
+       zr364xx_stop_acquire(cam);
+       res = videobuf_streamoff(&cam->vb_vidq);
+       if (res < 0)
+               return res;
+       res_free(cam);
        return 0;
 }
 
@@ -621,28 +1251,19 @@ static int zr364xx_vidioc_streamoff(struct file *file, void *priv,
 static int zr364xx_open(struct file *file)
 {
        struct video_device *vdev = video_devdata(file);
-       struct zr364xx_camera *cam = video_get_drvdata(vdev);
+       struct zr364xx_camera *cam = video_drvdata(file);
        struct usb_device *udev = cam->udev;
        int i, err;
 
-       DBG("zr364xx_open");
+       DBG("%s\n", __func__);
 
-       mutex_lock(&cam->lock);
+       mutex_lock(&cam->open_lock);
 
        if (cam->users) {
                err = -EBUSY;
                goto out;
        }
 
-       if (!cam->framebuf) {
-               cam->framebuf = vmalloc_32(MAX_FRAME_SIZE * FRAMES);
-               if (!cam->framebuf) {
-                       dev_err(&cam->udev->dev, "vmalloc_32 failed!\n");
-                       err = -ENOMEM;
-                       goto out;
-               }
-       }
-
        for (i = 0; init[cam->method][i].size != -1; i++) {
                err =
                    send_control_msg(udev, 1, init[cam->method][i].value,
@@ -658,6 +1279,14 @@ static int zr364xx_open(struct file *file)
        cam->skip = 2;
        cam->users++;
        file->private_data = vdev;
+       cam->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+       cam->fmt = formats;
+
+       videobuf_queue_vmalloc_init(&cam->vb_vidq, &zr364xx_video_qops,
+                                   NULL, &cam->slock,
+                                   cam->type,
+                                   V4L2_FIELD_NONE,
+                                   sizeof(struct zr364xx_buffer), cam);
 
        /* Added some delay here, since opening/closing the camera quickly,
         * like Ekiga does during its startup, can crash the webcam
@@ -666,28 +1295,70 @@ static int zr364xx_open(struct file *file)
        err = 0;
 
 out:
-       mutex_unlock(&cam->lock);
+       mutex_unlock(&cam->open_lock);
+       DBG("%s: %d\n", __func__, err);
        return err;
 }
 
+static void zr364xx_destroy(struct zr364xx_camera *cam)
+{
+       unsigned long i;
+
+       if (!cam) {
+               printk(KERN_ERR KBUILD_MODNAME ", %s: no device\n", __func__);
+               return;
+       }
+       mutex_lock(&cam->open_lock);
+       if (cam->vdev)
+               video_unregister_device(cam->vdev);
+       cam->vdev = NULL;
+
+       /* stops the read pipe if it is running */
+       if (cam->b_acquire)
+               zr364xx_stop_acquire(cam);
+
+       zr364xx_stop_readpipe(cam);
+
+       /* release sys buffers */
+       for (i = 0; i < FRAMES; i++) {
+               if (cam->buffer.frame[i].lpvbits) {
+                       DBG("vfree %p\n", cam->buffer.frame[i].lpvbits);
+                       vfree(cam->buffer.frame[i].lpvbits);
+               }
+               cam->buffer.frame[i].lpvbits = NULL;
+       }
+
+       /* release transfer buffer */
+       kfree(cam->pipe->transfer_buffer);
+       cam->pipe->transfer_buffer = NULL;
+       mutex_unlock(&cam->open_lock);
+       kfree(cam);
+       cam = NULL;
+}
 
 /* release the camera */
 static int zr364xx_release(struct file *file)
 {
-       struct video_device *vdev = video_devdata(file);
        struct zr364xx_camera *cam;
        struct usb_device *udev;
        int i, err;
 
-       DBG("zr364xx_release");
+       DBG("%s\n", __func__);
+       cam = video_drvdata(file);
 
-       if (vdev == NULL)
+       if (!cam)
                return -ENODEV;
-       cam = video_get_drvdata(vdev);
 
+       mutex_lock(&cam->open_lock);
        udev = cam->udev;
 
-       mutex_lock(&cam->lock);
+       /* turn off stream */
+       if (res_check(cam)) {
+               if (cam->b_acquire)
+                       zr364xx_stop_acquire(cam);
+               videobuf_streamoff(&cam->vb_vidq);
+               res_free(cam);
+       }
 
        cam->users--;
        file->private_data = NULL;
@@ -710,40 +1381,43 @@ static int zr364xx_release(struct file *file)
        err = 0;
 
 out:
-       mutex_unlock(&cam->lock);
+       mutex_unlock(&cam->open_lock);
+
        return err;
 }
 
 
 static int zr364xx_mmap(struct file *file, struct vm_area_struct *vma)
 {
-       void *pos;
-       unsigned long start = vma->vm_start;
-       unsigned long size = vma->vm_end - vma->vm_start;
-       struct video_device *vdev = video_devdata(file);
-       struct zr364xx_camera *cam;
-
-       DBG("zr364xx_mmap: %ld\n", size);
+       struct zr364xx_camera *cam = video_drvdata(file);
+       int ret;
 
-       if (vdev == NULL)
+       if (cam == NULL) {
+               DBG("%s: cam == NULL\n", __func__);
                return -ENODEV;
-       cam = video_get_drvdata(vdev);
-
-       pos = cam->framebuf;
-       while (size > 0) {
-               if (vm_insert_page(vma, start, vmalloc_to_page(pos)))
-                       return -EAGAIN;
-               start += PAGE_SIZE;
-               pos += PAGE_SIZE;
-               if (size > PAGE_SIZE)
-                       size -= PAGE_SIZE;
-               else
-                       size = 0;
        }
+       DBG("mmap called, vma=0x%08lx\n", (unsigned long)vma);
 
-       return 0;
+       ret = videobuf_mmap_mapper(&cam->vb_vidq, vma);
+
+       DBG("vma start=0x%08lx, size=%ld, ret=%d\n",
+               (unsigned long)vma->vm_start,
+               (unsigned long)vma->vm_end - (unsigned long)vma->vm_start, ret);
+       return ret;
 }
 
+static unsigned int zr364xx_poll(struct file *file,
+                              struct poll_table_struct *wait)
+{
+       struct zr364xx_camera *cam = video_drvdata(file);
+       struct videobuf_queue *q = &cam->vb_vidq;
+       _DBG("%s\n", __func__);
+
+       if (cam->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+               return POLLERR;
+
+       return videobuf_poll_stream(file, q, wait);
+}
 
 static const struct v4l2_file_operations zr364xx_fops = {
        .owner = THIS_MODULE,
@@ -752,6 +1426,7 @@ static const struct v4l2_file_operations zr364xx_fops = {
        .read = zr364xx_read,
        .mmap = zr364xx_mmap,
        .ioctl = video_ioctl2,
+       .poll = zr364xx_poll,
 };
 
 static const struct v4l2_ioctl_ops zr364xx_ioctl_ops = {
@@ -768,6 +1443,10 @@ static const struct v4l2_ioctl_ops zr364xx_ioctl_ops = {
        .vidioc_queryctrl       = zr364xx_vidioc_queryctrl,
        .vidioc_g_ctrl          = zr364xx_vidioc_g_ctrl,
        .vidioc_s_ctrl          = zr364xx_vidioc_s_ctrl,
+       .vidioc_reqbufs         = zr364xx_vidioc_reqbufs,
+       .vidioc_querybuf        = zr364xx_vidioc_querybuf,
+       .vidioc_qbuf            = zr364xx_vidioc_qbuf,
+       .vidioc_dqbuf           = zr364xx_vidioc_dqbuf,
 };
 
 static struct video_device zr364xx_template = {
@@ -783,15 +1462,76 @@ static struct video_device zr364xx_template = {
 /*******************/
 /* USB integration */
 /*******************/
+static int zr364xx_board_init(struct zr364xx_camera *cam)
+{
+       struct zr364xx_pipeinfo *pipe = cam->pipe;
+       unsigned long i;
+
+       DBG("board init: %p\n", cam);
+       memset(pipe, 0, sizeof(*pipe));
+       pipe->cam = cam;
+       pipe->transfer_size = BUFFER_SIZE;
+
+       pipe->transfer_buffer = kzalloc(pipe->transfer_size,
+                                       GFP_KERNEL);
+       if (pipe->transfer_buffer == NULL) {
+               DBG("out of memory!\n");
+               return -ENOMEM;
+       }
+
+       cam->b_acquire = 0;
+       cam->frame_count = 0;
+
+       /*** start create system buffers ***/
+       for (i = 0; i < FRAMES; i++) {
+               /* always allocate maximum size for system buffers */
+               cam->buffer.frame[i].lpvbits = vmalloc(MAX_FRAME_SIZE);
+
+               DBG("valloc %p, idx %lu, pdata %p\n",
+                       &cam->buffer.frame[i], i,
+                       cam->buffer.frame[i].lpvbits);
+               if (cam->buffer.frame[i].lpvbits == NULL) {
+                       printk(KERN_INFO KBUILD_MODNAME ": out of memory. "
+                              "Using less frames\n");
+                       break;
+               }
+       }
+
+       if (i == 0) {
+               printk(KERN_INFO KBUILD_MODNAME ": out of memory. Aborting\n");
+               kfree(cam->pipe->transfer_buffer);
+               cam->pipe->transfer_buffer = NULL;
+               return -ENOMEM;
+       } else
+               cam->buffer.dwFrames = i;
+
+       /* make sure internal states are set */
+       for (i = 0; i < FRAMES; i++) {
+               cam->buffer.frame[i].ulState = ZR364XX_READ_IDLE;
+               cam->buffer.frame[i].cur_size = 0;
+       }
+
+       cam->cur_frame = 0;
+       cam->last_frame = -1;
+       /*** end create system buffers ***/
+
+       /* start read pipe */
+       zr364xx_start_readpipe(cam);
+       DBG(": board initialized\n");
+       return 0;
+}
 
 static int zr364xx_probe(struct usb_interface *intf,
                         const struct usb_device_id *id)
 {
        struct usb_device *udev = interface_to_usbdev(intf);
        struct zr364xx_camera *cam = NULL;
+       struct usb_host_interface *iface_desc;
+       struct usb_endpoint_descriptor *endpoint;
        int err;
+       int i;
 
-       DBG("probing...");
+       DBG("probing...\n");
 
        dev_info(&intf->dev, DRIVER_DESC " compatible webcam plugged\n");
        dev_info(&intf->dev, "model %04x:%04x detected\n",
@@ -810,22 +1550,17 @@ static int zr364xx_probe(struct usb_interface *intf,
        if (cam->vdev == NULL) {
                dev_err(&udev->dev, "cam->vdev: out of memory !\n");
                kfree(cam);
+               cam = NULL;
                return -ENOMEM;
        }
        memcpy(cam->vdev, &zr364xx_template, sizeof(zr364xx_template));
+       cam->vdev->parent = &intf->dev;
        video_set_drvdata(cam->vdev, cam);
        if (debug)
                cam->vdev->debug = V4L2_DEBUG_IOCTL | V4L2_DEBUG_IOCTL_ARG;
 
        cam->udev = udev;
 
-       if ((cam->buffer = kmalloc(BUFFER_SIZE, GFP_KERNEL)) == NULL) {
-               dev_info(&udev->dev, "cam->buffer: out of memory !\n");
-               video_device_release(cam->vdev);
-               kfree(cam);
-               return -ENODEV;
-       }
-
        switch (mode) {
        case 1:
                dev_info(&udev->dev, "160x120 mode selected\n");
@@ -852,21 +1587,53 @@ static int zr364xx_probe(struct usb_interface *intf,
        header2[439] = cam->width / 256;
        header2[440] = cam->width % 256;
 
+       cam->users = 0;
        cam->nb = 0;
-       cam->brightness = 64;
+       cam->mode.brightness = 64;
        mutex_init(&cam->lock);
+       mutex_init(&cam->open_lock);
+
+       DBG("dev: %p, udev %p interface %p\n", cam, cam->udev, intf);
+
+       /* set up the endpoint information  */
+       iface_desc = intf->cur_altsetting;
+       DBG("num endpoints %d\n", iface_desc->desc.bNumEndpoints);
+       for (i = 0; i < iface_desc->desc.bNumEndpoints; ++i) {
+               endpoint = &iface_desc->endpoint[i].desc;
+               if (!cam->read_endpoint && usb_endpoint_is_bulk_in(endpoint)) {
+                       /* we found the bulk in endpoint */
+                       cam->read_endpoint = endpoint->bEndpointAddress;
+               }
+       }
+
+       if (!cam->read_endpoint) {
+               dev_err(&intf->dev, "Could not find bulk-in endpoint\n");
+               return -ENOMEM;
+       }
 
+       /* v4l */
+       INIT_LIST_HEAD(&cam->vidq.active);
+       cam->vidq.cam = cam;
        err = video_register_device(cam->vdev, VFL_TYPE_GRABBER, -1);
        if (err) {
                dev_err(&udev->dev, "video_register_device failed\n");
                video_device_release(cam->vdev);
-               kfree(cam->buffer);
                kfree(cam);
+               cam = NULL;
                return err;
        }
 
        usb_set_intfdata(intf, cam);
 
+       /* load zr364xx board specific */
+       err = zr364xx_board_init(cam);
+       if (err) {
+               spin_lock_init(&cam->slock);
+               return err;
+       }
+
+       spin_lock_init(&cam->slock);
+
        dev_info(&udev->dev, DRIVER_DESC " controlling video device %d\n",
                 cam->vdev->num);
        return 0;
@@ -876,17 +1643,10 @@ static int zr364xx_probe(struct usb_interface *intf,
 static void zr364xx_disconnect(struct usb_interface *intf)
 {
        struct zr364xx_camera *cam = usb_get_intfdata(intf);
+       videobuf_mmap_free(&cam->vb_vidq);
        usb_set_intfdata(intf, NULL);
        dev_info(&intf->dev, DRIVER_DESC " webcam unplugged\n");
-       if (cam->vdev)
-               video_unregister_device(cam->vdev);
-       cam->vdev = NULL;
-       kfree(cam->buffer);
-       cam->buffer = NULL;
-       vfree(cam->framebuf);
-       cam->framebuf = NULL;
-       kfree(cam);
-       cam = NULL;
+       zr364xx_destroy(cam);
 }
 
 
index 8664feebc93ba3bf184857dfb42f7cb7f51b9a4a..e7563a9872d0af6404f64adae9610a9fffad027f 100644 (file)
@@ -5,7 +5,7 @@
  * (C) 2000 Red Hat. GPL'd
  *
  *
- * 10/10/2000  Nicolas Pitre <nico@cam.org>
+ * 10/10/2000  Nicolas Pitre <nico@fluxnic.net>
  *     - completely revamped method functions so they are aware and
  *       independent of the flash geometry (buswidth, interleave, etc.)
  *     - scalability vs code size is completely set at compile-time
index 6c740f346f910e50ddf4a8fba8329e13498cb13b..0667a671525da07061b5fdb22bed940ff16687bc 100644 (file)
@@ -4,7 +4,7 @@
  *
  * (C) 2000 Red Hat. GPL'd
  *
- * 10/10/2000  Nicolas Pitre <nico@cam.org>
+ * 10/10/2000  Nicolas Pitre <nico@fluxnic.net>
  *     - completely revamped method functions so they are aware and
  *       independent of the flash geometry (buswidth, interleave, etc.)
  *     - scalability vs code size is completely set at compile-time
index 365c77b1b871d5d81d939989e406cfa3940fb4c4..a7c808b577d376a5f99edc98adcf5dd49cc2cba0 100644 (file)
@@ -6,7 +6,7 @@
  * for example.  All board-specific configuration goes in your
  * board resources file.
  *
- * Copyright 2000 Nicolas Pitre <nico@cam.org>
+ * Copyright 2000 Nicolas Pitre <nico@fluxnic.net>
  * Copyright 2005-2008 Analog Devices Inc.
  *
  * Enter bugs at http://blackfin.uclinux.org/
index 60e68bde0fea55358ae79377e26a1f7740cc5fbf..d41f34766e53177ea4d78259d815a75e1e2b2fee 100644 (file)
@@ -9,7 +9,7 @@
  * Based on: sa1100-flash.c, which has the following copyright:
  * Flash memory access on SA11x0 based devices
  *
- * (C) 2000 Nicolas Pitre <nico@cam.org>
+ * (C) 2000 Nicolas Pitre <nico@fluxnic.net>
  *
  */
 
index 42969fe051b219b5ec0788f60f51c1141d1e4770..b3cb3a18380995a250cf3c4614f7a5bfe3115cf1 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * MTD map driver for flash on the DC21285 (the StrongARM-110 companion chip)
  *
- * (C) 2000  Nicolas Pitre <nico@cam.org>
+ * (C) 2000  Nicolas Pitre <nico@fluxnic.net>
  *
  * This code is GPL
  */
@@ -249,5 +249,5 @@ module_exit(cleanup_dc21285);
 
 
 MODULE_LICENSE("GPL");
-MODULE_AUTHOR("Nicolas Pitre <nico@cam.org>");
+MODULE_AUTHOR("Nicolas Pitre <nico@fluxnic.net>");
 MODULE_DESCRIPTION("MTD map driver for DC21285 boards");
index 748c85f635f1b340523b9cab6511455369c770e0..76708e796b700ff4e4cabca56a427d08fb6d1a64 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * Flash memory access on iPAQ Handhelds (either SA1100 or PXA250 based)
  *
- * (C) 2000 Nicolas Pitre <nico@cam.org>
+ * (C) 2000 Nicolas Pitre <nico@fluxnic.net>
  * (C) 2002 Hewlett-Packard Company <jamey.hicks@hp.com>
  * (C) 2003 Christian Pellegrin <chri@ascensit.com>, <chri@infis.univ.ts.it>: concatenation of multiple flashes
  */
index 643aa06b599e8f9733d0c87072c21f530d5f20d8..74fa075c838a52209c2c6db29d49df1a7e00f7bc 100644 (file)
@@ -175,5 +175,5 @@ module_init(init_pxa2xx_flash);
 module_exit(cleanup_pxa2xx_flash);
 
 MODULE_LICENSE("GPL");
-MODULE_AUTHOR("Nicolas Pitre <nico@cam.org>");
+MODULE_AUTHOR("Nicolas Pitre <nico@fluxnic.net>");
 MODULE_DESCRIPTION("MTD map driver for Intel XScale PXA2xx");
index c6210f5118d1f13ab690a16a479888a2019adfa6..fdb97f3d30e9afc8b0c6b07143ebba9ece6bae79 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * Flash memory access on SA11x0 based devices
  *
- * (C) 2000 Nicolas Pitre <nico@cam.org>
+ * (C) 2000 Nicolas Pitre <nico@fluxnic.net>
  */
 #include <linux/module.h>
 #include <linux/types.h>
index 77db5ce24d92b9fed41970d83bb1346a95740d85..2d70295a5fa350ae7e541948bfc9623b634b18fa 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * Direct MTD block device access
  *
- * (C) 2000-2003 Nicolas Pitre <nico@cam.org>
+ * (C) 2000-2003 Nicolas Pitre <nico@fluxnic.net>
  * (C) 1999-2003 David Woodhouse <dwmw2@infradead.org>
  */
 
@@ -403,5 +403,5 @@ module_exit(cleanup_mtdblock);
 
 
 MODULE_LICENSE("GPL");
-MODULE_AUTHOR("Nicolas Pitre <nico@cam.org> et al.");
+MODULE_AUTHOR("Nicolas Pitre <nico@fluxnic.net> et al.");
 MODULE_DESCRIPTION("Caching read/erase/writeback block device emulation access to MTD devices");
index 349fcbe5cc0ff2718c7372bf3263b17a7af3c8d3..742504ea96f5de11cfb377a8c82126675958fe62 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * Simple MTD partitioning layer
  *
- * (C) 2000 Nicolas Pitre <nico@cam.org>
+ * (C) 2000 Nicolas Pitre <nico@fluxnic.net>
  *
  * This code is GPL
  *
index 61be6d7680f68aeab97ff76ac93b649ce097d633..05c91ee6921e8a2082ed605db93f3ddb92581b27 100644 (file)
@@ -35,7 +35,7 @@
  *
  * contributors:
  *     Daris A Nevil <dnevil@snmc.com>
- *      Nicolas Pitre <nico@cam.org>
+ *      Nicolas Pitre <nico@fluxnic.net>
  *     Russell King <rmk@arm.linux.org.uk>
  *
  * History:
@@ -58,7 +58,7 @@
  *   22/09/04  Nicolas Pitre      big update (see commit log for details)
  */
 static const char version[] =
-       "smc91x.c: v1.1, sep 22 2004 by Nicolas Pitre <nico@cam.org>\n";
+       "smc91x.c: v1.1, sep 22 2004 by Nicolas Pitre <nico@fluxnic.net>\n";
 
 /* Debugging level */
 #ifndef SMC_DEBUG
index 57a159fac99fcc1308ae106e06aadb7602bfe496..784b631cfa3cf9e4930886ffec6419c939e5012e 100644 (file)
@@ -28,7 +28,7 @@
  . Authors
  .     Erik Stahlman           <erik@vt.edu>
  .     Daris A Nevil           <dnevil@snmc.com>
- .     Nicolas Pitre           <nico@cam.org>
+ .     Nicolas Pitre           <nico@fluxnic.net>
  .
  ---------------------------------------------------------------------------*/
 #ifndef _SMC91X_H_
index 7b287cb38b7ad76b562d1fd3684b1bca676e4bb7..ab99783dccec9570c7aecd9e8141490a97cadc14 100644 (file)
@@ -33,6 +33,7 @@
 #include <linux/timer.h>
 #include <linux/irq.h>
 #include <linux/interrupt.h>
+#include <linux/tboot.h>
 
 #undef PREFIX
 #define PREFIX "DMAR:"
@@ -413,6 +414,12 @@ parse_dmar_table(void)
         */
        dmar_table_detect();
 
+       /*
+        * ACPI tables may not be DMA protected by tboot, so use DMAR copy
+        * SINIT saved in SinitMleData in TXT heap (which is DMA protected)
+        */
+       dmar_tbl = tboot_get_dmar_table(dmar_tbl);
+
        dmar = (struct acpi_table_dmar *)dmar_tbl;
        if (!dmar)
                return -ENODEV;
index 2314ad7ee5fef4544ab2159cd7e253ed6e1d3889..562221e119172ffe19655b5ff6b5792098d89e48 100644 (file)
@@ -37,6 +37,7 @@
 #include <linux/iommu.h>
 #include <linux/intel-iommu.h>
 #include <linux/sysdev.h>
+#include <linux/tboot.h>
 #include <asm/cacheflush.h>
 #include <asm/iommu.h>
 #include "pci.h"
@@ -3183,12 +3184,22 @@ static int __init init_iommu_sysfs(void)
 int __init intel_iommu_init(void)
 {
        int ret = 0;
+       int force_on = 0;
 
-       if (dmar_table_init())
+       /* VT-d is required for a TXT/tboot launch, so enforce that */
+       force_on = tboot_force_iommu();
+
+       if (dmar_table_init()) {
+               if (force_on)
+                       panic("tboot: Failed to initialize DMAR table\n");
                return  -ENODEV;
+       }
 
-       if (dmar_dev_scope_init())
+       if (dmar_dev_scope_init()) {
+               if (force_on)
+                       panic("tboot: Failed to initialize DMAR device scope\n");
                return  -ENODEV;
+       }
 
        /*
         * Check the need for DMA-remapping initialization now.
@@ -3204,6 +3215,8 @@ int __init intel_iommu_init(void)
 
        ret = init_dmars();
        if (ret) {
+               if (force_on)
+                       panic("tboot: Failed to initialize DMARs\n");
                printk(KERN_ERR "IOMMU: dmar init failed\n");
                put_iova_domain(&reserved_iova_list);
                iommu_exit_mempool();
index 18066d55539764abd94c9b157f4392c303236083..af0afa1db4a8b3261dfba62b2d13cb680f3b3c9a 100644 (file)
 #include <asm/lv1call.h>
 #include <asm/ps3stor.h>
 
+/*
+ * A workaround for flash memory I/O errors when the internal hard disk
+ * has not been formatted for OtherOS use.  Delay disk close until flash
+ * memory is closed.
+ */
+
+static struct ps3_flash_workaround {
+       int flash_open;
+       int disk_open;
+       struct ps3_system_bus_device *disk_sbd;
+} ps3_flash_workaround;
+
+static int ps3stor_open_hv_device(struct ps3_system_bus_device *sbd)
+{
+       int error = ps3_open_hv_device(sbd);
+
+       if (error)
+               return error;
+
+       if (sbd->match_id == PS3_MATCH_ID_STOR_FLASH)
+               ps3_flash_workaround.flash_open = 1;
+
+       if (sbd->match_id == PS3_MATCH_ID_STOR_DISK)
+               ps3_flash_workaround.disk_open = 1;
+
+       return 0;
+}
+
+static int ps3stor_close_hv_device(struct ps3_system_bus_device *sbd)
+{
+       int error;
+
+       if (sbd->match_id == PS3_MATCH_ID_STOR_DISK
+               && ps3_flash_workaround.disk_open
+               && ps3_flash_workaround.flash_open) {
+               ps3_flash_workaround.disk_sbd = sbd;
+               return 0;
+       }
+
+       error = ps3_close_hv_device(sbd);
+
+       if (error)
+               return error;
+
+       if (sbd->match_id == PS3_MATCH_ID_STOR_DISK)
+               ps3_flash_workaround.disk_open = 0;
+
+       if (sbd->match_id == PS3_MATCH_ID_STOR_FLASH) {
+               ps3_flash_workaround.flash_open = 0;
+
+               if (ps3_flash_workaround.disk_sbd) {
+                       ps3_close_hv_device(ps3_flash_workaround.disk_sbd);
+                       ps3_flash_workaround.disk_open = 0;
+                       ps3_flash_workaround.disk_sbd = NULL;
+               }
+       }
+
+       return 0;
+}
 
 static int ps3stor_probe_access(struct ps3_storage_device *dev)
 {
@@ -90,7 +149,7 @@ int ps3stor_setup(struct ps3_storage_device *dev, irq_handler_t handler)
        int error, res, alignment;
        enum ps3_dma_page_size page_size;
 
-       error = ps3_open_hv_device(&dev->sbd);
+       error = ps3stor_open_hv_device(&dev->sbd);
        if (error) {
                dev_err(&dev->sbd.core,
                        "%s:%u: ps3_open_hv_device failed %d\n", __func__,
@@ -166,7 +225,7 @@ fail_free_irq:
 fail_sb_event_receive_port_destroy:
        ps3_sb_event_receive_port_destroy(&dev->sbd, dev->irq);
 fail_close_device:
-       ps3_close_hv_device(&dev->sbd);
+       ps3stor_close_hv_device(&dev->sbd);
 fail:
        return error;
 }
@@ -193,7 +252,7 @@ void ps3stor_teardown(struct ps3_storage_device *dev)
                        "%s:%u: destroy event receive port failed %d\n",
                        __func__, __LINE__, error);
 
-       error = ps3_close_hv_device(&dev->sbd);
+       error = ps3stor_close_hv_device(&dev->sbd);
        if (error)
                dev_err(&dev->sbd.core,
                        "%s:%u: ps3_close_hv_device failed %d\n", __func__,
index 4f247e4dd3f934441b46c4b87f7e69305bc8a02e..021b2928f0b9d39d4ecf15bb4a9f6fe46cfc1f41 100644 (file)
@@ -9,7 +9,7 @@
  *
  * Modifications from:
  *   CIH <cih@coventive.com>
- *   Nicolas Pitre <nico@cam.org>
+ *   Nicolas Pitre <nico@fluxnic.net>
  *   Andrew Christian <andrew.christian@hp.com>
  *
  * Converted to the RTC subsystem and Driver Model
index c0af638fe702441c4095d168f4b464769296274c..9c0144ee7ae516f6d0042127f8acad4279249f46 100644 (file)
@@ -32,7 +32,7 @@
 #include <linux/init.h>
 
 #include <asm/abs_addr.h>
-#include <asm/iommu.h>
+#include <asm/cell-regs.h>
 #include <asm/lv1call.h>
 #include <asm/ps3av.h>
 #include <asm/ps3fb.h>
index 10ddad8e17d65a0ac0a0ed397129fef02b5c3472..cdaa873a60541f00acad18def540fd010ee05b5b 100644 (file)
@@ -66,7 +66,7 @@
  *     - FrameBuffer memory is now allocated at run-time when the
  *       driver is initialized.    
  *
- * 2000/04/10: Nicolas Pitre <nico@cam.org>
+ * 2000/04/10: Nicolas Pitre <nico@fluxnic.net>
  *     - Big cleanup for dynamic selection of machine type at run time.
  *
  * 2000/07/19: Jamey Hicks <jamey@crl.dec.com>
index abad71b1632b10dab15c8fb51e2df7554fb4d62c..2f57276e87a2f65cd8c468529484e3ca21f88c8b 100644 (file)
 static DEFINE_SPINLOCK(irq_mapping_update_lock);
 
 /* IRQ <-> VIRQ mapping. */
-static DEFINE_PER_CPU(int, virq_to_irq[NR_VIRQS]) = {[0 ... NR_VIRQS-1] = -1};
+static DEFINE_PER_CPU(int [NR_VIRQS], virq_to_irq) = {[0 ... NR_VIRQS-1] = -1};
 
 /* IRQ <-> IPI mapping */
-static DEFINE_PER_CPU(int, ipi_to_irq[XEN_NR_IPIS]) = {[0 ... XEN_NR_IPIS-1] = -1};
+static DEFINE_PER_CPU(int [XEN_NR_IPIS], ipi_to_irq) = {[0 ... XEN_NR_IPIS-1] = -1};
 
 /* Interrupt types. */
 enum xen_irq_type {
@@ -602,6 +602,8 @@ irqreturn_t xen_debug_interrupt(int irq, void *dev_id)
        return IRQ_HANDLED;
 }
 
+static DEFINE_PER_CPU(unsigned, xed_nesting_count);
+
 /*
  * Search the CPUs pending events bitmasks.  For each one found, map
  * the event number to an irq, and feed it into do_IRQ() for
@@ -617,7 +619,6 @@ void xen_evtchn_do_upcall(struct pt_regs *regs)
        struct pt_regs *old_regs = set_irq_regs(regs);
        struct shared_info *s = HYPERVISOR_shared_info;
        struct vcpu_info *vcpu_info = __get_cpu_var(xen_vcpu);
-       static DEFINE_PER_CPU(unsigned, nesting_count);
        unsigned count;
 
        exit_idle();
@@ -628,7 +629,7 @@ void xen_evtchn_do_upcall(struct pt_regs *regs)
 
                vcpu_info->evtchn_upcall_pending = 0;
 
-               if (__get_cpu_var(nesting_count)++)
+               if (__get_cpu_var(xed_nesting_count)++)
                        goto out;
 
 #ifndef CONFIG_X86 /* No need for a barrier -- XCHG is a barrier on x86. */
@@ -653,8 +654,8 @@ void xen_evtchn_do_upcall(struct pt_regs *regs)
 
                BUG_ON(!irqs_disabled());
 
-               count = __get_cpu_var(nesting_count);
-               __get_cpu_var(nesting_count) = 0;
+               count = __get_cpu_var(xed_nesting_count);
+               __get_cpu_var(xed_nesting_count) = 0;
        } while(count != 1);
 
 out:
index c2e7a7ff008054ad63fb8ae33677b96b359bd90f..c63a3c8beb73d50f84674b6b21963e177d937562 100644 (file)
@@ -712,7 +712,6 @@ int afs_writeback_all(struct afs_vnode *vnode)
                .bdi            = mapping->backing_dev_info,
                .sync_mode      = WB_SYNC_ALL,
                .nr_to_write    = LONG_MAX,
-               .for_writepages = 1,
                .range_cyclic   = 1,
        };
        int ret;
index 3581a4e53942f85e961662b8872fa870f3cbf864..71e7e03ac34313ed2fcb890d727bf1e47e006317 100644 (file)
@@ -420,7 +420,6 @@ static void bdev_destroy_inode(struct inode *inode)
 {
        struct bdev_inode *bdi = BDEV_I(inode);
 
-       bdi->bdev.bd_inode_backing_dev_info = NULL;
        kmem_cache_free(bdev_cachep, bdi);
 }
 
index 15831d5c73676ef79804f5308997f44745c33da3..8b81927900117b34368191495f78e5bca6e954ac 100644 (file)
@@ -1600,6 +1600,7 @@ struct btrfs_root *open_ctree(struct super_block *sb,
 
        sb->s_blocksize = 4096;
        sb->s_blocksize_bits = blksize_bits(4096);
+       sb->s_bdi = &fs_info->bdi;
 
        /*
         * we set the i_size on the btree inode to the max possible int.
index d6f0806c682ff83fc11b019ac4f26d1f732acbec..7b2f401e604e3e4706ba2b8d8b9646949cfca3db 100644 (file)
@@ -740,7 +740,6 @@ int btrfs_fdatawrite_range(struct address_space *mapping, loff_t start,
                .nr_to_write = mapping->nrpages * 2,
                .range_start = start,
                .range_end = end,
-               .for_writepages = 1,
        };
        return btrfs_writepages(mapping, &wbc);
 }
index 628235cf44b59e311898a2766fdc45ea1b34ed70..8e1e5e19d21e1fd60c9f99b3988fee0191c3e901 100644 (file)
  */
 int nr_pdflush_threads;
 
+/*
+ * Passed into wb_writeback(), essentially a subset of writeback_control
+ */
+struct wb_writeback_args {
+       long nr_pages;
+       struct super_block *sb;
+       enum writeback_sync_modes sync_mode;
+       int for_kupdate;
+       int range_cyclic;
+};
+
 /*
  * Work items for the bdi_writeback threads
  */
 struct bdi_work {
-       struct list_head list;
-       struct list_head wait_list;
-       struct rcu_head rcu_head;
+       struct list_head list;          /* pending work list */
+       struct rcu_head rcu_head;       /* for RCU free/clear of work */
 
-       unsigned long seen;
-       atomic_t pending;
+       unsigned long seen;             /* threads that have seen this work */
+       atomic_t pending;               /* number of threads still to do work */
 
-       struct super_block *sb;
-       unsigned long nr_pages;
-       enum writeback_sync_modes sync_mode;
+       struct wb_writeback_args args;  /* writeback arguments */
 
-       unsigned long state;
+       unsigned long state;            /* flag bits, see WS_* */
 };
 
 enum {
@@ -66,22 +74,13 @@ static inline bool bdi_work_on_stack(struct bdi_work *work)
 }
 
 static inline void bdi_work_init(struct bdi_work *work,
-                                struct writeback_control *wbc)
+                                struct wb_writeback_args *args)
 {
        INIT_RCU_HEAD(&work->rcu_head);
-       work->sb = wbc->sb;
-       work->nr_pages = wbc->nr_to_write;
-       work->sync_mode = wbc->sync_mode;
+       work->args = *args;
        work->state = WS_USED;
 }
 
-static inline void bdi_work_init_on_stack(struct bdi_work *work,
-                                         struct writeback_control *wbc)
-{
-       bdi_work_init(work, wbc);
-       work->state |= WS_ONSTACK;
-}
-
 /**
  * writeback_in_progress - determine whether there is writeback in progress
  * @bdi: the device's backing_dev_info structure.
@@ -98,6 +97,11 @@ static void bdi_work_clear(struct bdi_work *work)
 {
        clear_bit(WS_USED_B, &work->state);
        smp_mb__after_clear_bit();
+       /*
+        * work can have disappeared at this point. bit waitq functions
+        * should be able to tolerate this, provided bdi_sched_wait does
+        * not dereference it's pointer argument.
+       */
        wake_up_bit(&work->state, WS_USED_B);
 }
 
@@ -113,7 +117,8 @@ static void bdi_work_free(struct rcu_head *head)
 
 static void wb_work_complete(struct bdi_work *work)
 {
-       const enum writeback_sync_modes sync_mode = work->sync_mode;
+       const enum writeback_sync_modes sync_mode = work->args.sync_mode;
+       int onstack = bdi_work_on_stack(work);
 
        /*
         * For allocated work, we can clear the done/seen bit right here.
@@ -121,9 +126,9 @@ static void wb_work_complete(struct bdi_work *work)
         * to after the RCU grace period, since the stack could be invalidated
         * as soon as bdi_work_clear() has done the wakeup.
         */
-       if (!bdi_work_on_stack(work))
+       if (!onstack)
                bdi_work_clear(work);
-       if (sync_mode == WB_SYNC_NONE || bdi_work_on_stack(work))
+       if (sync_mode == WB_SYNC_NONE || onstack)
                call_rcu(&work->rcu_head, bdi_work_free);
 }
 
@@ -146,21 +151,19 @@ static void wb_clear_pending(struct bdi_writeback *wb, struct bdi_work *work)
 
 static void bdi_queue_work(struct backing_dev_info *bdi, struct bdi_work *work)
 {
-       if (work) {
-               work->seen = bdi->wb_mask;
-               BUG_ON(!work->seen);
-               atomic_set(&work->pending, bdi->wb_cnt);
-               BUG_ON(!bdi->wb_cnt);
-
-               /*
-                * Make sure stores are seen before it appears on the list
-                */
-               smp_mb();
+       work->seen = bdi->wb_mask;
+       BUG_ON(!work->seen);
+       atomic_set(&work->pending, bdi->wb_cnt);
+       BUG_ON(!bdi->wb_cnt);
 
-               spin_lock(&bdi->wb_lock);
-               list_add_tail_rcu(&work->list, &bdi->work_list);
-               spin_unlock(&bdi->wb_lock);
-       }
+       /*
+        * list_add_tail_rcu() contains the necessary barriers to
+        * make sure the above stores are seen before the item is
+        * noticed on the list
+        */
+       spin_lock(&bdi->wb_lock);
+       list_add_tail_rcu(&work->list, &bdi->work_list);
+       spin_unlock(&bdi->wb_lock);
 
        /*
         * If the default thread isn't there, make sure we add it. When
@@ -171,15 +174,7 @@ static void bdi_queue_work(struct backing_dev_info *bdi, struct bdi_work *work)
        else {
                struct bdi_writeback *wb = &bdi->wb;
 
-               /*
-                * If we failed allocating the bdi work item, wake up the wb
-                * thread always. As a safety precaution, it'll flush out
-                * everything
-                */
-               if (!wb_has_dirty_io(wb)) {
-                       if (work)
-                               wb_clear_pending(wb, work);
-               } else if (wb->task)
+               if (wb->task)
                        wake_up_process(wb->task);
        }
 }
@@ -194,48 +189,75 @@ static void bdi_wait_on_work_clear(struct bdi_work *work)
                    TASK_UNINTERRUPTIBLE);
 }
 
-static struct bdi_work *bdi_alloc_work(struct writeback_control *wbc)
+static void bdi_alloc_queue_work(struct backing_dev_info *bdi,
+                                struct wb_writeback_args *args)
 {
        struct bdi_work *work;
 
+       /*
+        * This is WB_SYNC_NONE writeback, so if allocation fails just
+        * wakeup the thread for old dirty data writeback
+        */
        work = kmalloc(sizeof(*work), GFP_ATOMIC);
-       if (work)
-               bdi_work_init(work, wbc);
+       if (work) {
+               bdi_work_init(work, args);
+               bdi_queue_work(bdi, work);
+       } else {
+               struct bdi_writeback *wb = &bdi->wb;
 
-       return work;
+               if (wb->task)
+                       wake_up_process(wb->task);
+       }
 }
 
-void bdi_start_writeback(struct writeback_control *wbc)
+/**
+ * bdi_sync_writeback - start and wait for writeback
+ * @bdi: the backing device to write from
+ * @sb: write inodes from this super_block
+ *
+ * Description:
+ *   This does WB_SYNC_ALL data integrity writeback and waits for the
+ *   IO to complete. Callers must hold the sb s_umount semaphore for
+ *   reading, to avoid having the super disappear before we are done.
+ */
+static void bdi_sync_writeback(struct backing_dev_info *bdi,
+                              struct super_block *sb)
 {
-       const bool must_wait = wbc->sync_mode == WB_SYNC_ALL;
-       struct bdi_work work_stack, *work = NULL;
+       struct wb_writeback_args args = {
+               .sb             = sb,
+               .sync_mode      = WB_SYNC_ALL,
+               .nr_pages       = LONG_MAX,
+               .range_cyclic   = 0,
+       };
+       struct bdi_work work;
 
-       if (!must_wait)
-               work = bdi_alloc_work(wbc);
+       bdi_work_init(&work, &args);
+       work.state |= WS_ONSTACK;
 
-       if (!work) {
-               work = &work_stack;
-               bdi_work_init_on_stack(work, wbc);
-       }
+       bdi_queue_work(bdi, &work);
+       bdi_wait_on_work_clear(&work);
+}
 
-       bdi_queue_work(wbc->bdi, work);
+/**
+ * bdi_start_writeback - start writeback
+ * @bdi: the backing device to write from
+ * @nr_pages: the number of pages to write
+ *
+ * Description:
+ *   This does WB_SYNC_NONE opportunistic writeback. The IO is only
+ *   started when this function returns, we make no guarentees on
+ *   completion. Caller need not hold sb s_umount semaphore.
+ *
+ */
+void bdi_start_writeback(struct backing_dev_info *bdi, long nr_pages)
+{
+       struct wb_writeback_args args = {
+               .sync_mode      = WB_SYNC_NONE,
+               .nr_pages       = nr_pages,
+               .range_cyclic   = 1,
+       };
 
-       /*
-        * If the sync mode is WB_SYNC_ALL, block waiting for the work to
-        * complete. If not, we only need to wait for the work to be started,
-        * if we allocated it on-stack. We use the same mechanism, if the
-        * wait bit is set in the bdi_work struct, then threads will not
-        * clear pending until after they are done.
-        *
-        * Note that work == &work_stack if must_wait is true, so we don't
-        * need to do call_rcu() here ever, since the completion path will
-        * have done that for us.
-        */
-       if (must_wait || work == &work_stack) {
-               bdi_wait_on_work_clear(work);
-               if (work != &work_stack)
-                       call_rcu(&work->rcu_head, bdi_work_free);
-       }
+       bdi_alloc_queue_work(bdi, &args);
 }
 
 /*
@@ -671,17 +693,16 @@ static inline bool over_bground_thresh(void)
  * older_than_this takes precedence over nr_to_write.  So we'll only write back
  * all dirty pages if they are all attached to "old" mappings.
  */
-static long wb_writeback(struct bdi_writeback *wb, long nr_pages,
-                        struct super_block *sb,
-                        enum writeback_sync_modes sync_mode, int for_kupdate)
+static long wb_writeback(struct bdi_writeback *wb,
+                        struct wb_writeback_args *args)
 {
        struct writeback_control wbc = {
                .bdi                    = wb->bdi,
-               .sb                     = sb,
-               .sync_mode              = sync_mode,
+               .sb                     = args->sb,
+               .sync_mode              = args->sync_mode,
                .older_than_this        = NULL,
-               .for_kupdate            = for_kupdate,
-               .range_cyclic           = 1,
+               .for_kupdate            = args->for_kupdate,
+               .range_cyclic           = args->range_cyclic,
        };
        unsigned long oldest_jif;
        long wrote = 0;
@@ -691,13 +712,18 @@ static long wb_writeback(struct bdi_writeback *wb, long nr_pages,
                oldest_jif = jiffies -
                                msecs_to_jiffies(dirty_expire_interval * 10);
        }
+       if (!wbc.range_cyclic) {
+               wbc.range_start = 0;
+               wbc.range_end = LLONG_MAX;
+       }
 
        for (;;) {
                /*
                 * Don't flush anything for non-integrity writeback where
                 * no nr_pages was given
                 */
-               if (!for_kupdate && nr_pages <= 0 && sync_mode == WB_SYNC_NONE)
+               if (!args->for_kupdate && args->nr_pages <= 0 &&
+                    args->sync_mode == WB_SYNC_NONE)
                        break;
 
                /*
@@ -705,7 +731,8 @@ static long wb_writeback(struct bdi_writeback *wb, long nr_pages,
                 * periodic background writeout and we are below the
                 * background dirty threshold, don't do anything
                 */
-               if (for_kupdate && nr_pages <= 0 && !over_bground_thresh())
+               if (args->for_kupdate && args->nr_pages <= 0 &&
+                   !over_bground_thresh())
                        break;
 
                wbc.more_io = 0;
@@ -713,7 +740,7 @@ static long wb_writeback(struct bdi_writeback *wb, long nr_pages,
                wbc.nr_to_write = MAX_WRITEBACK_PAGES;
                wbc.pages_skipped = 0;
                writeback_inodes_wb(wb, &wbc);
-               nr_pages -= MAX_WRITEBACK_PAGES - wbc.nr_to_write;
+               args->nr_pages -= MAX_WRITEBACK_PAGES - wbc.nr_to_write;
                wrote += MAX_WRITEBACK_PAGES - wbc.nr_to_write;
 
                /*
@@ -731,7 +758,11 @@ static long wb_writeback(struct bdi_writeback *wb, long nr_pages,
 
 /*
  * Return the next bdi_work struct that hasn't been processed by this
- * wb thread yet
+ * wb thread yet. ->seen is initially set for each thread that exists
+ * for this device, when a thread first notices a piece of work it
+ * clears its bit. Depending on writeback type, the thread will notify
+ * completion on either receiving the work (WB_SYNC_NONE) or after
+ * it is done (WB_SYNC_ALL).
  */
 static struct bdi_work *get_next_work_item(struct backing_dev_info *bdi,
                                           struct bdi_writeback *wb)
@@ -741,8 +772,9 @@ static struct bdi_work *get_next_work_item(struct backing_dev_info *bdi,
        rcu_read_lock();
 
        list_for_each_entry_rcu(work, &bdi->work_list, list) {
-               if (!test_and_clear_bit(wb->nr, &work->seen))
+               if (!test_bit(wb->nr, &work->seen))
                        continue;
+               clear_bit(wb->nr, &work->seen);
 
                ret = work;
                break;
@@ -767,8 +799,16 @@ static long wb_check_old_data_flush(struct bdi_writeback *wb)
                        global_page_state(NR_UNSTABLE_NFS) +
                        (inodes_stat.nr_inodes - inodes_stat.nr_unused);
 
-       if (nr_pages)
-               return wb_writeback(wb, nr_pages, NULL, WB_SYNC_NONE, 1);
+       if (nr_pages) {
+               struct wb_writeback_args args = {
+                       .nr_pages       = nr_pages,
+                       .sync_mode      = WB_SYNC_NONE,
+                       .for_kupdate    = 1,
+                       .range_cyclic   = 1,
+               };
+
+               return wb_writeback(wb, &args);
+       }
 
        return 0;
 }
@@ -780,35 +820,31 @@ long wb_do_writeback(struct bdi_writeback *wb, int force_wait)
 {
        struct backing_dev_info *bdi = wb->bdi;
        struct bdi_work *work;
-       long nr_pages, wrote = 0;
+       long wrote = 0;
 
        while ((work = get_next_work_item(bdi, wb)) != NULL) {
-               enum writeback_sync_modes sync_mode;
-
-               nr_pages = work->nr_pages;
+               struct wb_writeback_args args = work->args;
 
                /*
                 * Override sync mode, in case we must wait for completion
                 */
                if (force_wait)
-                       work->sync_mode = sync_mode = WB_SYNC_ALL;
-               else
-                       sync_mode = work->sync_mode;
+                       work->args.sync_mode = args.sync_mode = WB_SYNC_ALL;
 
                /*
                 * If this isn't a data integrity operation, just notify
                 * that we have seen this work and we are now starting it.
                 */
-               if (sync_mode == WB_SYNC_NONE)
+               if (args.sync_mode == WB_SYNC_NONE)
                        wb_clear_pending(wb, work);
 
-               wrote += wb_writeback(wb, nr_pages, work->sb, sync_mode, 0);
+               wrote += wb_writeback(wb, &args);
 
                /*
                 * This is a data integrity writeback, so only do the
                 * notification when we have completed the work.
                 */
-               if (sync_mode == WB_SYNC_ALL)
+               if (args.sync_mode == WB_SYNC_ALL)
                        wb_clear_pending(wb, work);
        }
 
@@ -849,8 +885,7 @@ int bdi_writeback_task(struct bdi_writeback *wb)
                }
 
                wait_jiffies = msecs_to_jiffies(dirty_writeback_interval * 10);
-               set_current_state(TASK_INTERRUPTIBLE);
-               schedule_timeout(wait_jiffies);
+               schedule_timeout_interruptible(wait_jiffies);
                try_to_freeze();
        }
 
@@ -858,67 +893,28 @@ int bdi_writeback_task(struct bdi_writeback *wb)
 }
 
 /*
- * Schedule writeback for all backing devices. Expensive! If this is a data
- * integrity operation, writeback will be complete when this returns. If
- * we are simply called for WB_SYNC_NONE, then writeback will merely be
- * scheduled to run.
+ * Schedule writeback for all backing devices. This does WB_SYNC_NONE
+ * writeback, for integrity writeback see bdi_sync_writeback().
  */
-static void bdi_writeback_all(struct writeback_control *wbc)
+static void bdi_writeback_all(struct super_block *sb, long nr_pages)
 {
-       const bool must_wait = wbc->sync_mode == WB_SYNC_ALL;
+       struct wb_writeback_args args = {
+               .sb             = sb,
+               .nr_pages       = nr_pages,
+               .sync_mode      = WB_SYNC_NONE,
+       };
        struct backing_dev_info *bdi;
-       struct bdi_work *work;
-       LIST_HEAD(list);
-
-restart:
-       spin_lock(&bdi_lock);
 
-       list_for_each_entry(bdi, &bdi_list, bdi_list) {
-               struct bdi_work *work;
+       rcu_read_lock();
 
+       list_for_each_entry_rcu(bdi, &bdi_list, bdi_list) {
                if (!bdi_has_dirty_io(bdi))
                        continue;
 
-               /*
-                * If work allocation fails, do the writes inline. We drop
-                * the lock and restart the list writeout. This should be OK,
-                * since this happens rarely and because the writeout should
-                * eventually make more free memory available.
-                */
-               work = bdi_alloc_work(wbc);
-               if (!work) {
-                       struct writeback_control __wbc;
-
-                       /*
-                        * Not a data integrity writeout, just continue
-                        */
-                       if (!must_wait)
-                               continue;
-
-                       spin_unlock(&bdi_lock);
-                       __wbc = *wbc;
-                       __wbc.bdi = bdi;
-                       writeback_inodes_wbc(&__wbc);
-                       goto restart;
-               }
-               if (must_wait)
-                       list_add_tail(&work->wait_list, &list);
-
-               bdi_queue_work(bdi, work);
+               bdi_alloc_queue_work(bdi, &args);
        }
 
-       spin_unlock(&bdi_lock);
-
-       /*
-        * If this is for WB_SYNC_ALL, wait for pending work to complete
-        * before returning.
-        */
-       while (!list_empty(&list)) {
-               work = list_entry(list.next, struct bdi_work, wait_list);
-               list_del(&work->wait_list);
-               bdi_wait_on_work_clear(work);
-               call_rcu(&work->rcu_head, bdi_work_free);
-       }
+       rcu_read_unlock();
 }
 
 /*
@@ -927,17 +923,10 @@ restart:
  */
 void wakeup_flusher_threads(long nr_pages)
 {
-       struct writeback_control wbc = {
-               .sync_mode      = WB_SYNC_NONE,
-               .older_than_this = NULL,
-               .range_cyclic   = 1,
-       };
-
        if (nr_pages == 0)
                nr_pages = global_page_state(NR_FILE_DIRTY) +
                                global_page_state(NR_UNSTABLE_NFS);
-       wbc.nr_to_write = nr_pages;
-       bdi_writeback_all(&wbc);
+       bdi_writeback_all(NULL, nr_pages);
 }
 
 static noinline void block_dump___mark_inode_dirty(struct inode *inode)
@@ -1084,7 +1073,7 @@ EXPORT_SYMBOL(__mark_inode_dirty);
  * on the writer throttling path, and we get decent balancing between many
  * throttled threads: we don't want them all piling up on inode_sync_wait.
  */
-static void wait_sb_inodes(struct writeback_control *wbc)
+static void wait_sb_inodes(struct super_block *sb)
 {
        struct inode *inode, *old_inode = NULL;
 
@@ -1092,7 +1081,7 @@ static void wait_sb_inodes(struct writeback_control *wbc)
         * We need to be protected against the filesystem going from
         * r/o to r/w or vice versa.
         */
-       WARN_ON(!rwsem_is_locked(&wbc->sb->s_umount));
+       WARN_ON(!rwsem_is_locked(&sb->s_umount));
 
        spin_lock(&inode_lock);
 
@@ -1103,7 +1092,7 @@ static void wait_sb_inodes(struct writeback_control *wbc)
         * In which case, the inode may not be on the dirty list, but
         * we still have to wait for that writeout.
         */
-       list_for_each_entry(inode, &wbc->sb->s_inodes, i_sb_list) {
+       list_for_each_entry(inode, &sb->s_inodes, i_sb_list) {
                struct address_space *mapping;
 
                if (inode->i_state & (I_FREEING|I_CLEAR|I_WILL_FREE|I_NEW))
@@ -1143,14 +1132,8 @@ static void wait_sb_inodes(struct writeback_control *wbc)
  * for IO completion of submitted IO. The number of pages submitted is
  * returned.
  */
-long writeback_inodes_sb(struct super_block *sb)
+void writeback_inodes_sb(struct super_block *sb)
 {
-       struct writeback_control wbc = {
-               .sb             = sb,
-               .sync_mode      = WB_SYNC_NONE,
-               .range_start    = 0,
-               .range_end      = LLONG_MAX,
-       };
        unsigned long nr_dirty = global_page_state(NR_FILE_DIRTY);
        unsigned long nr_unstable = global_page_state(NR_UNSTABLE_NFS);
        long nr_to_write;
@@ -1158,9 +1141,7 @@ long writeback_inodes_sb(struct super_block *sb)
        nr_to_write = nr_dirty + nr_unstable +
                        (inodes_stat.nr_inodes - inodes_stat.nr_unused);
 
-       wbc.nr_to_write = nr_to_write;
-       bdi_writeback_all(&wbc);
-       return nr_to_write - wbc.nr_to_write;
+       bdi_writeback_all(sb, nr_to_write);
 }
 EXPORT_SYMBOL(writeback_inodes_sb);
 
@@ -1171,20 +1152,10 @@ EXPORT_SYMBOL(writeback_inodes_sb);
  * This function writes and waits on any dirty inode belonging to this
  * super_block. The number of pages synced is returned.
  */
-long sync_inodes_sb(struct super_block *sb)
+void sync_inodes_sb(struct super_block *sb)
 {
-       struct writeback_control wbc = {
-               .sb             = sb,
-               .sync_mode      = WB_SYNC_ALL,
-               .range_start    = 0,
-               .range_end      = LLONG_MAX,
-       };
-       long nr_to_write = LONG_MAX; /* doesn't actually matter */
-
-       wbc.nr_to_write = nr_to_write;
-       bdi_writeback_all(&wbc);
-       wait_sb_inodes(&wbc);
-       return nr_to_write - wbc.nr_to_write;
+       bdi_sync_writeback(sb->s_bdi, sb);
+       wait_sb_inodes(sb);
 }
 EXPORT_SYMBOL(sync_inodes_sb);
 
index 4567db6f94308d41242dc29bc40458e36bf8300d..e5dbecd87b0f49c748aa4465c3a22447e29fc540 100644 (file)
@@ -894,6 +894,8 @@ static int fuse_fill_super(struct super_block *sb, void *data, int silent)
        if (err)
                goto err_put_conn;
 
+       sb->s_bdi = &fc->bdi;
+
        /* Handle umasking inside the fuse code */
        if (sb->s_flags & MS_POSIXACL)
                fc->dont_mask = 1;
index ae7b67e48661b0f078679a67d6f0c1d40847bf06..b2ba83d2c4e12425629ed3681f2d2ca2d147f2e1 100644 (file)
@@ -182,9 +182,7 @@ int inode_init_always(struct super_block *sb, struct inode *inode)
        if (sb->s_bdev) {
                struct backing_dev_info *bdi;
 
-               bdi = sb->s_bdev->bd_inode_backing_dev_info;
-               if (!bdi)
-                       bdi = sb->s_bdev->bd_inode->i_mapping->backing_dev_info;
+               bdi = sb->s_bdev->bd_inode->i_mapping->backing_dev_info;
                mapping->backing_dev_info = bdi;
        }
        inode->i_private = NULL;
index 7b4088b2364d5caf8145d610cea8dc885022cda4..0df600e9162dcd3ca4d996aeb5a742863b3394f5 100644 (file)
@@ -220,7 +220,6 @@ static int journal_submit_inode_data_buffers(struct address_space *mapping)
                .nr_to_write = mapping->nrpages * 2,
                .range_start = 0,
                .range_end = i_size_read(mapping->host),
-               .for_writepages = 1,
        };
 
        ret = generic_writepages(mapping, &wbc);
index 867f705045313217c2bcbf40d3a78ad82cbeccb9..de935692d40d77a6592a61ac810887f2bf1ce313 100644 (file)
@@ -1918,6 +1918,8 @@ static inline void nfs_initialise_sb(struct super_block *sb)
        if (server->flags & NFS_MOUNT_NOAC)
                sb->s_flags |= MS_SYNCHRONOUS;
 
+       sb->s_bdi = &server->backing_dev_info;
+
        nfs_super_set_maxbytes(sb, server->maxfilesize);
 }
 
index 120acadc6a843e8b792f408c46900d4c62a0f1f8..53eb26c16b50a06c0126f156a1ee6fddc1480413 100644 (file)
@@ -1490,7 +1490,6 @@ static int nfs_write_mapping(struct address_space *mapping, int how)
                .nr_to_write = LONG_MAX,
                .range_start = 0,
                .range_end = LLONG_MAX,
-               .for_writepages = 1,
        };
 
        return __nfs_write_mapping(mapping, &wbc, how);
index d4168e269c5d66a4fe85915f24f70f2e35c7aa3c..ad391a8c3e7e51190eb691e24699044fe11e256d 100644 (file)
@@ -591,9 +591,7 @@ int init_nilfs(struct the_nilfs *nilfs, struct nilfs_sb_info *sbi, char *data)
 
        nilfs->ns_mount_state = le16_to_cpu(sbp->s_state);
 
-       bdi = nilfs->ns_bdev->bd_inode_backing_dev_info;
-       if (!bdi)
-               bdi = nilfs->ns_bdev->bd_inode->i_mapping->backing_dev_info;
+       bdi = nilfs->ns_bdev->bd_inode->i_mapping->backing_dev_info;
        nilfs->ns_bdi = bdi ? : &default_backing_dev_info;
 
        /* Finding last segment */
index 9cda337ddae20f30ed6590abca9dcf6cf2a7189d..b03fea8fbfb6e0c1d5276e59141ec620f0050db7 100644 (file)
@@ -707,6 +707,12 @@ static int set_bdev_super(struct super_block *s, void *data)
 {
        s->s_bdev = data;
        s->s_dev = s->s_bdev->bd_dev;
+
+       /*
+        * We set the bdi here to the queue backing, file systems can
+        * overwrite this in ->fill_super()
+        */
+       s->s_bdi = &bdev_get_queue(s->s_bdev)->backing_dev_info;
        return 0;
 }
 
index 192340930bb477f506eeee2eb132db06a1a6309f..c08467a5d7cb73d2988157c8c5fa4ab33ee2f48d 100644 (file)
--- a/fs/sync.c
+++ b/fs/sync.c
  */
 static int __sync_filesystem(struct super_block *sb, int wait)
 {
+       /*
+        * This should be safe, as we require bdi backing to actually
+        * write out data in the first place
+        */
+       if (!sb->s_bdi)
+               return 0;
+
        /* Avoid doing twice syncing and cache pruning for quota sync */
        if (!wait) {
                writeout_quota_sb(sb, -1);
@@ -101,7 +108,7 @@ restart:
                spin_unlock(&sb_lock);
 
                down_read(&sb->s_umount);
-               if (!(sb->s_flags & MS_RDONLY) && sb->s_root)
+               if (!(sb->s_flags & MS_RDONLY) && sb->s_root && sb->s_bdi)
                        __sync_filesystem(sb, wait);
                up_read(&sb->s_umount);
 
index 1c8991b0db1344cb66aa49b3f9bb20555ed0c61e..ee1ce68fd98b74bb5e46fd6eb589a68d7e8e7054 100644 (file)
  * @nr_to_write: how many dirty pages to write-back
  *
  * This function shrinks UBIFS liability by means of writing back some amount
- * of dirty inodes and their pages. Returns the amount of pages which were
- * written back. The returned value does not include dirty inodes which were
- * synchronized.
+ * of dirty inodes and their pages.
  *
  * Note, this function synchronizes even VFS inodes which are locked
  * (@i_mutex) by the caller of the budgeting function, because write-back does
  * not touch @i_mutex.
  */
-static int shrink_liability(struct ubifs_info *c, int nr_to_write)
+static void shrink_liability(struct ubifs_info *c, int nr_to_write)
 {
-       int nr_written;
-
-       nr_written = writeback_inodes_sb(c->vfs_sb);
-       if (!nr_written) {
-               /*
-                * Re-try again but wait on pages/inodes which are being
-                * written-back concurrently (e.g., by pdflush).
-                */
-               nr_written = sync_inodes_sb(c->vfs_sb);
-       }
-
-       dbg_budg("%d pages were written back", nr_written);
-       return nr_written;
+       writeback_inodes_sb(c->vfs_sb);
 }
 
 /**
index 51763aa8f4dec59890553f9331475f7fa1f4aed0..c4af069df1adbc30e05798815ddfdc5a2395a92c 100644 (file)
@@ -1980,6 +1980,7 @@ static int ubifs_fill_super(struct super_block *sb, void *data, int silent)
        if (err)
                goto out_bdi;
 
+       sb->s_bdi = &c->bdi;
        sb->s_fs_info = c;
        sb->s_magic = UBIFS_SUPER_MAGIC;
        sb->s_blocksize = UBIFS_BLOCK_SIZE;
index 6ad76bf5fb40dd03b03682fa561b943ad209650d..a43223af98b667c0e5af01ed90d4637fe001272e 100644 (file)
  *     BSS_SECTION(0, 0, 0)
  *     _end = .;
  *
- *     /DISCARD/ : {
- *             EXIT_TEXT
- *             EXIT_DATA
- *             EXIT_CALL
- *     }
  *     STABS_DEBUG
  *     DWARF_DEBUG
+ *
+ *     DISCARDS                // must be the last
  * }
  *
  * [__init_begin, __init_end] is the init section that may be freed after init
 #define INIT_RAM_FS
 #endif
 
+/*
+ * Default discarded sections.
+ *
+ * Some archs want to discard exit text/data at runtime rather than
+ * link time due to cross-section references such as alt instructions,
+ * bug table, eh_frame, etc.  DISCARDS must be the last of output
+ * section definitions so that such archs put those in earlier section
+ * definitions.
+ */
+#define DISCARDS                                                       \
+       /DISCARD/ : {                                                   \
+       EXIT_TEXT                                                       \
+       EXIT_DATA                                                       \
+       EXIT_CALL                                                       \
+       *(.discard)                                                     \
+       }
+
 /**
  * PERCPU_VADDR - define output section for percpu area
  * @vaddr: explicit base address (optional)
index 76fa794fdac0fdab91bfc74204c5642ec09384fb..880130f7311fca6006b97e10865744b1461188b2 100644 (file)
@@ -79,9 +79,12 @@ struct agp_memory {
        u32 physical;
        bool is_bound;
        bool is_flushed;
-        bool vmalloc_flag;
+       bool vmalloc_flag;
        /* list of agp_memory mapped to the aperture */
        struct list_head mapped_list;
+       /* DMA-mapped addresses */
+       struct scatterlist *sg_list;
+       int num_sg;
 };
 
 #define AGP_NORMAL_MEMORY 0
index f169bcb90b58b3b098208984a50a921132bd9f5f..0ee33c2e6129005aa13191244f9ed391af9630e7 100644 (file)
@@ -59,6 +59,7 @@ struct bdi_writeback {
 
 struct backing_dev_info {
        struct list_head bdi_list;
+       struct rcu_head rcu_head;
        unsigned long ra_pages; /* max readahead in PAGE_CACHE_SIZE units */
        unsigned long state;    /* Always use atomic bitops on this */
        unsigned int capabilities; /* Device capabilities */
@@ -100,7 +101,7 @@ int bdi_register(struct backing_dev_info *bdi, struct device *parent,
                const char *fmt, ...);
 int bdi_register_dev(struct backing_dev_info *bdi, dev_t dev);
 void bdi_unregister(struct backing_dev_info *bdi);
-void bdi_start_writeback(struct writeback_control *wbc);
+void bdi_start_writeback(struct backing_dev_info *bdi, long nr_pages);
 int bdi_writeback_task(struct bdi_writeback *wb);
 int bdi_has_dirty_io(struct backing_dev_info *bdi);
 
index c0f6c3cd788c6caa057bfec7938cac696740b013..91b761846061412efa3cf91e5ec9235ed626ce50 100644 (file)
@@ -58,6 +58,7 @@ struct dma_map_ops {
                                   enum dma_data_direction dir);
        int (*mapping_error)(struct device *dev, dma_addr_t dma_addr);
        int (*dma_supported)(struct device *dev, u64 mask);
+       int (*set_dma_mask)(struct device *dev, u64 mask);
        int is_phys;
 };
 
index fef943738a24d56127516c1abbf863c8e79b5ed0..f078f3ac82d4bc606c345926722fefce6fdb4abe 100644 (file)
@@ -151,5 +151,7 @@ struct dmx_stc {
 #define DMX_GET_CAPS             _IOR('o', 48, dmx_caps_t)
 #define DMX_SET_SOURCE           _IOW('o', 49, dmx_source_t)
 #define DMX_GET_STC              _IOWR('o', 50, struct dmx_stc)
+#define DMX_ADD_PID              _IOW('o', 51, __u16)
+#define DMX_REMOVE_PID           _IOW('o', 52, __u16)
 
 #endif /*_DVBDMX_H_*/
index b21cf6b9c80b2510f87d8fc6dab47c8d500f4015..90162fb3bf044cfaba959679ca048ea3e66e397a 100644 (file)
@@ -655,7 +655,6 @@ struct block_device {
        int                     bd_invalidated;
        struct gendisk *        bd_disk;
        struct list_head        bd_list;
-       struct backing_dev_info *bd_inode_backing_dev_info;
        /*
         * Private data.  You must have bd_claim'ed the block_device
         * to use this.  NOTE:  bd_claim allows an owner to claim
@@ -1343,6 +1342,7 @@ struct super_block {
        int                     s_nr_dentry_unused;     /* # of dentry on lru */
 
        struct block_device     *s_bdev;
+       struct backing_dev_info *s_bdi;
        struct mtd_info         *s_mtd;
        struct list_head        s_instances;
        struct quota_info       s_dquot;        /* Diskquota specific options */
index edc93a6d931db45fecc9ba3064aecb0619ea6115..e4135d6e05568ebbbae8d0716349f2a65574079c 100644 (file)
@@ -258,6 +258,7 @@ enum {
        IDE_TFLAG_DYN                   = (1 << 5),
        IDE_TFLAG_FS                    = (1 << 6),
        IDE_TFLAG_MULTI_PIO             = (1 << 7),
+       IDE_TFLAG_SET_XFER              = (1 << 8),
 };
 
 enum {
@@ -294,7 +295,7 @@ struct ide_cmd {
                } out, in;
        } valid;
 
-       u                     tf_flags;
+       u16                     tf_flags;
        u8                      ftf_flags;      /* for TASKFILE ioctl */
        int                     protocol;
 
@@ -918,8 +919,7 @@ __IDE_PROC_DEVSET(_name, _min, _max, NULL, NULL)
 typedef struct {
        const char      *name;
        mode_t          mode;
-       read_proc_t     *read_proc;
-       write_proc_t    *write_proc;
+       const struct file_operations *proc_fops;
 } ide_proc_entry_t;
 
 void proc_ide_create(void);
@@ -931,24 +931,8 @@ void ide_proc_unregister_port(ide_hwif_t *);
 void ide_proc_register_driver(ide_drive_t *, struct ide_driver *);
 void ide_proc_unregister_driver(ide_drive_t *, struct ide_driver *);
 
-read_proc_t proc_ide_read_capacity;
-read_proc_t proc_ide_read_geometry;
-
-/*
- * Standard exit stuff:
- */
-#define PROC_IDE_READ_RETURN(page,start,off,count,eof,len) \
-{                                      \
-       len -= off;                     \
-       if (len < count) {              \
-               *eof = 1;               \
-               if (len <= 0)           \
-                       return 0;       \
-       } else                          \
-               len = count;            \
-       *start = page + off;            \
-       return len;                     \
-}
+extern const struct file_operations ide_capacity_proc_fops;
+extern const struct file_operations ide_geometry_proc_fops;
 #else
 static inline void proc_ide_create(void) { ; }
 static inline void proc_ide_destroy(void) { ; }
@@ -960,7 +944,6 @@ static inline void ide_proc_register_driver(ide_drive_t *drive,
                                            struct ide_driver *driver) { ; }
 static inline void ide_proc_unregister_driver(ide_drive_t *drive,
                                              struct ide_driver *driver) { ; }
-#define PROC_IDE_READ_RETURN(page,start,off,count,eof,len) return 0;
 #endif
 
 enum {
@@ -1081,6 +1064,7 @@ extern void ide_fixstring(u8 *, const int, const int);
 
 int ide_busy_sleep(ide_drive_t *, unsigned long, int);
 
+int __ide_wait_stat(ide_drive_t *, u8, u8, unsigned long, u8 *);
 int ide_wait_stat(ide_startstop_t *, ide_drive_t *, u8, u8, unsigned long);
 
 ide_startstop_t ide_do_park_unpark(ide_drive_t *, struct request *);
@@ -1169,7 +1153,7 @@ int ide_no_data_taskfile(ide_drive_t *, struct ide_cmd *);
 
 int ide_taskfile_ioctl(ide_drive_t *, unsigned long);
 
-int ide_dev_read_id(ide_drive_t *, u8, u16 *);
+int ide_dev_read_id(ide_drive_t *, u8, u16 *, int);
 
 extern int ide_driveid_update(ide_drive_t *);
 extern int ide_config_drive_speed(ide_drive_t *, u8);
index 0adb0f91568c1cfd407b1e88c1dce5b39d0080d5..97eb928b49243076d89f634b06a1ab4802f49847 100644 (file)
@@ -49,23 +49,30 @@ static inline struct io_mapping *
 io_mapping_create_wc(resource_size_t base, unsigned long size)
 {
        struct io_mapping *iomap;
-
-       if (!is_io_mapping_possible(base, size))
-               return NULL;
+       pgprot_t prot;
 
        iomap = kmalloc(sizeof(*iomap), GFP_KERNEL);
        if (!iomap)
-               return NULL;
+               goto out_err;
+
+       if (iomap_create_wc(base, size, &prot))
+               goto out_free;
 
        iomap->base = base;
        iomap->size = size;
-       iomap->prot = pgprot_writecombine(__pgprot(__PAGE_KERNEL));
+       iomap->prot = prot;
        return iomap;
+
+out_free:
+       kfree(iomap);
+out_err:
+       return NULL;
 }
 
 static inline void
 io_mapping_free(struct io_mapping *mapping)
 {
+       iomap_free(mapping->base, mapping->size);
        kfree(mapping);
 }
 
index b70313d33ff8ba0390889c7a87b8415ac6f3b27c..274b6196091df019e9e2fb65214a8fdbeafeca15 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * MTD partitioning layer definitions
  *
- * (C) 2000 Nicolas Pitre <nico@cam.org>
+ * (C) 2000 Nicolas Pitre <nico@fluxnic.net>
  *
  * This code is GPL
  */
index e2e5ce543595df658b883a227fd753f9ab2a92e0..2b87acfc5f87496f323d69b1c2a487f634331878 100644 (file)
@@ -99,7 +99,7 @@ enum pageflags {
 #ifdef CONFIG_HAVE_MLOCKED_PAGE_BIT
        PG_mlocked,             /* Page is vma mlocked */
 #endif
-#ifdef CONFIG_IA64_UNCACHED_ALLOCATOR
+#ifdef CONFIG_ARCH_USES_PG_UNCACHED
        PG_uncached,            /* Page has been mapped as uncached */
 #endif
        __NR_PAGEFLAGS,
@@ -257,7 +257,7 @@ PAGEFLAG_FALSE(Mlocked)
        SETPAGEFLAG_NOOP(Mlocked) TESTCLEARFLAG_FALSE(Mlocked)
 #endif
 
-#ifdef CONFIG_IA64_UNCACHED_ALLOCATOR
+#ifdef CONFIG_ARCH_USES_PG_UNCACHED
 PAGEFLAG(Uncached, uncached)
 #else
 PAGEFLAG_FALSE(Uncached)
index 555a8262fbc2b8ce407e156327a5939b5ceba4c5..0d96be93b926c345ac731efa7926c7006b472549 100644 (file)
 #define PCI_DEVICE_ID_APPLE_SH_SUNGEM   0x0051
 #define PCI_DEVICE_ID_APPLE_U3L_AGP    0x0058
 #define PCI_DEVICE_ID_APPLE_U3H_AGP    0x0059
+#define PCI_DEVICE_ID_APPLE_U4_PCIE    0x005b
 #define PCI_DEVICE_ID_APPLE_IPID2_AGP  0x0066
 #define PCI_DEVICE_ID_APPLE_IPID2_ATA  0x0069
 #define PCI_DEVICE_ID_APPLE_IPID2_FW   0x006a
index 0761491b3eec791b6869d989c4c905429d2a686a..9bd03193ecd48c5e2c1283309a2c8ac2914cab37 100644 (file)
 /*
  * Base implementations of per-CPU variable declarations and definitions, where
  * the section in which the variable is to be placed is provided by the
- * 'section' argument.  This may be used to affect the parameters governing the
+ * 'sec' argument.  This may be used to affect the parameters governing the
  * variable's storage.
  *
  * NOTE!  The sections for the DECLARE and for the DEFINE must match, lest
  * linkage errors occur due the compiler generating the wrong code to access
  * that section.
  */
-#define DECLARE_PER_CPU_SECTION(type, name, section)                   \
-       extern                                                          \
-       __attribute__((__section__(PER_CPU_BASE_SECTION section)))      \
-       PER_CPU_ATTRIBUTES __typeof__(type) per_cpu__##name
-
-#define DEFINE_PER_CPU_SECTION(type, name, section)                    \
-       __attribute__((__section__(PER_CPU_BASE_SECTION section)))      \
-       PER_CPU_ATTRIBUTES PER_CPU_DEF_ATTRIBUTES                       \
+#define __PCPU_ATTRS(sec)                                              \
+       __attribute__((section(PER_CPU_BASE_SECTION sec)))              \
+       PER_CPU_ATTRIBUTES
+
+#define __PCPU_DUMMY_ATTRS                                             \
+       __attribute__((section(".discard"), unused))
+
+/*
+ * s390 and alpha modules require percpu variables to be defined as
+ * weak to force the compiler to generate GOT based external
+ * references for them.  This is necessary because percpu sections
+ * will be located outside of the usually addressable area.
+ *
+ * This definition puts the following two extra restrictions when
+ * defining percpu variables.
+ *
+ * 1. The symbol must be globally unique, even the static ones.
+ * 2. Static percpu variables cannot be defined inside a function.
+ *
+ * Archs which need weak percpu definitions should define
+ * ARCH_NEEDS_WEAK_PER_CPU in asm/percpu.h when necessary.
+ *
+ * To ensure that the generic code observes the above two
+ * restrictions, if CONFIG_DEBUG_FORCE_WEAK_PER_CPU is set weak
+ * definition is used for all cases.
+ */
+#if defined(ARCH_NEEDS_WEAK_PER_CPU) || defined(CONFIG_DEBUG_FORCE_WEAK_PER_CPU)
+/*
+ * __pcpu_scope_* dummy variable is used to enforce scope.  It
+ * receives the static modifier when it's used in front of
+ * DEFINE_PER_CPU() and will trigger build failure if
+ * DECLARE_PER_CPU() is used for the same variable.
+ *
+ * __pcpu_unique_* dummy variable is used to enforce symbol uniqueness
+ * such that hidden weak symbol collision, which will cause unrelated
+ * variables to share the same address, can be detected during build.
+ */
+#define DECLARE_PER_CPU_SECTION(type, name, sec)                       \
+       extern __PCPU_DUMMY_ATTRS char __pcpu_scope_##name;             \
+       extern __PCPU_ATTRS(sec) __typeof__(type) per_cpu__##name
+
+#define DEFINE_PER_CPU_SECTION(type, name, sec)                                \
+       __PCPU_DUMMY_ATTRS char __pcpu_scope_##name;                    \
+       __PCPU_DUMMY_ATTRS char __pcpu_unique_##name;                   \
+       __PCPU_ATTRS(sec) PER_CPU_DEF_ATTRIBUTES __weak                 \
+       __typeof__(type) per_cpu__##name
+#else
+/*
+ * Normal declaration and definition macros.
+ */
+#define DECLARE_PER_CPU_SECTION(type, name, sec)                       \
+       extern __PCPU_ATTRS(sec) __typeof__(type) per_cpu__##name
+
+#define DEFINE_PER_CPU_SECTION(type, name, sec)                                \
+       __PCPU_ATTRS(sec) PER_CPU_DEF_ATTRIBUTES                        \
        __typeof__(type) per_cpu__##name
+#endif
 
 /*
  * Variant on the per-CPU variable declaration/definition theme used for
index 26fd9d12f050b32a1d766071ab4e3e4fc0a1aeff..878836ca999c0f3e2b65836cbe8bd7816d44ffaa 100644 (file)
@@ -34,7 +34,7 @@
 
 #ifdef CONFIG_SMP
 
-#ifdef CONFIG_HAVE_DYNAMIC_PER_CPU_AREA
+#ifndef CONFIG_HAVE_LEGACY_PER_CPU_AREA
 
 /* minimum unit size, also is the maximum supported allocation size */
 #define PCPU_MIN_UNIT_SIZE             PFN_ALIGN(64 << 10)
 #endif
 
 extern void *pcpu_base_addr;
+extern const unsigned long *pcpu_unit_offsets;
 
-typedef struct page * (*pcpu_get_page_fn_t)(unsigned int cpu, int pageno);
-typedef void (*pcpu_populate_pte_fn_t)(unsigned long addr);
+struct pcpu_group_info {
+       int                     nr_units;       /* aligned # of units */
+       unsigned long           base_offset;    /* base address offset */
+       unsigned int            *cpu_map;       /* unit->cpu map, empty
+                                                * entries contain NR_CPUS */
+};
+
+struct pcpu_alloc_info {
+       size_t                  static_size;
+       size_t                  reserved_size;
+       size_t                  dyn_size;
+       size_t                  unit_size;
+       size_t                  atom_size;
+       size_t                  alloc_size;
+       size_t                  __ai_size;      /* internal, don't use */
+       int                     nr_groups;      /* 0 if grouping unnecessary */
+       struct pcpu_group_info  groups[];
+};
 
-extern size_t __init pcpu_setup_first_chunk(pcpu_get_page_fn_t get_page_fn,
-                               size_t static_size, size_t reserved_size,
-                               ssize_t dyn_size, ssize_t unit_size,
-                               void *base_addr,
-                               pcpu_populate_pte_fn_t populate_pte_fn);
+enum pcpu_fc {
+       PCPU_FC_AUTO,
+       PCPU_FC_EMBED,
+       PCPU_FC_PAGE,
 
-extern ssize_t __init pcpu_embed_first_chunk(
-                               size_t static_size, size_t reserved_size,
-                               ssize_t dyn_size, ssize_t unit_size);
+       PCPU_FC_NR,
+};
+extern const char *pcpu_fc_names[PCPU_FC_NR];
+
+extern enum pcpu_fc pcpu_chosen_fc;
+
+typedef void * (*pcpu_fc_alloc_fn_t)(unsigned int cpu, size_t size,
+                                    size_t align);
+typedef void (*pcpu_fc_free_fn_t)(void *ptr, size_t size);
+typedef void (*pcpu_fc_populate_pte_fn_t)(unsigned long addr);
+typedef int (pcpu_fc_cpu_distance_fn_t)(unsigned int from, unsigned int to);
+
+extern struct pcpu_alloc_info * __init pcpu_alloc_alloc_info(int nr_groups,
+                                                            int nr_units);
+extern void __init pcpu_free_alloc_info(struct pcpu_alloc_info *ai);
+
+extern struct pcpu_alloc_info * __init pcpu_build_alloc_info(
+                               size_t reserved_size, ssize_t dyn_size,
+                               size_t atom_size,
+                               pcpu_fc_cpu_distance_fn_t cpu_distance_fn);
+
+extern int __init pcpu_setup_first_chunk(const struct pcpu_alloc_info *ai,
+                                        void *base_addr);
+
+#ifdef CONFIG_NEED_PER_CPU_EMBED_FIRST_CHUNK
+extern int __init pcpu_embed_first_chunk(size_t reserved_size, ssize_t dyn_size,
+                               size_t atom_size,
+                               pcpu_fc_cpu_distance_fn_t cpu_distance_fn,
+                               pcpu_fc_alloc_fn_t alloc_fn,
+                               pcpu_fc_free_fn_t free_fn);
+#endif
+
+#ifdef CONFIG_NEED_PER_CPU_PAGE_FIRST_CHUNK
+extern int __init pcpu_page_first_chunk(size_t reserved_size,
+                               pcpu_fc_alloc_fn_t alloc_fn,
+                               pcpu_fc_free_fn_t free_fn,
+                               pcpu_fc_populate_pte_fn_t populate_pte_fn);
+#endif
 
 /*
  * Use this to get to a cpu's version of the per-cpu object
@@ -80,7 +131,7 @@ extern ssize_t __init pcpu_embed_first_chunk(
 
 extern void *__alloc_reserved_percpu(size_t size, size_t align);
 
-#else /* CONFIG_HAVE_DYNAMIC_PER_CPU_AREA */
+#else /* CONFIG_HAVE_LEGACY_PER_CPU_AREA */
 
 struct percpu_data {
        void *ptrs[1];
@@ -99,11 +150,15 @@ struct percpu_data {
         (__typeof__(ptr))__p->ptrs[(cpu)];                             \
 })
 
-#endif /* CONFIG_HAVE_DYNAMIC_PER_CPU_AREA */
+#endif /* CONFIG_HAVE_LEGACY_PER_CPU_AREA */
 
 extern void *__alloc_percpu(size_t size, size_t align);
 extern void free_percpu(void *__pdata);
 
+#ifndef CONFIG_HAVE_SETUP_PER_CPU_AREA
+extern void __init setup_per_cpu_areas(void);
+#endif
+
 #else /* CONFIG_SMP */
 
 #define per_cpu_ptr(ptr, cpu) ({ (void)(cpu); (ptr); })
@@ -124,6 +179,13 @@ static inline void free_percpu(void *p)
        kfree(p);
 }
 
+static inline void __init setup_per_cpu_areas(void) { }
+
+static inline void *pcpu_lpage_remapped(void *kaddr)
+{
+       return NULL;
+}
+
 #endif /* CONFIG_SMP */
 
 #define alloc_percpu(type)     (type *)__alloc_percpu(sizeof(type), \
diff --git a/include/linux/tboot.h b/include/linux/tboot.h
new file mode 100644 (file)
index 0000000..bf2a0c7
--- /dev/null
@@ -0,0 +1,162 @@
+/*
+ * tboot.h: shared data structure with tboot and kernel and functions
+ *          used by kernel for runtime support of Intel(R) Trusted
+ *          Execution Technology
+ *
+ * Copyright (c) 2006-2009, Intel Corporation
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope 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.,
+ * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ */
+
+#ifndef _LINUX_TBOOT_H
+#define _LINUX_TBOOT_H
+
+/* these must have the values from 0-5 in this order */
+enum {
+       TB_SHUTDOWN_REBOOT = 0,
+       TB_SHUTDOWN_S5,
+       TB_SHUTDOWN_S4,
+       TB_SHUTDOWN_S3,
+       TB_SHUTDOWN_HALT,
+       TB_SHUTDOWN_WFS
+};
+
+#ifdef CONFIG_INTEL_TXT
+#include <acpi/acpi.h>
+/* used to communicate between tboot and the launched kernel */
+
+#define TB_KEY_SIZE             64   /* 512 bits */
+
+#define MAX_TB_MAC_REGIONS      32
+
+struct tboot_mac_region {
+       u64  start;         /* must be 64 byte -aligned */
+       u32  size;          /* must be 64 byte -granular */
+} __packed;
+
+/* GAS - Generic Address Structure (ACPI 2.0+) */
+struct tboot_acpi_generic_address {
+       u8  space_id;
+       u8  bit_width;
+       u8  bit_offset;
+       u8  access_width;
+       u64 address;
+} __packed;
+
+/*
+ * combines Sx info from FADT and FACS tables per ACPI 2.0+ spec
+ * (http://www.acpi.info/)
+ */
+struct tboot_acpi_sleep_info {
+       struct tboot_acpi_generic_address pm1a_cnt_blk;
+       struct tboot_acpi_generic_address pm1b_cnt_blk;
+       struct tboot_acpi_generic_address pm1a_evt_blk;
+       struct tboot_acpi_generic_address pm1b_evt_blk;
+       u16 pm1a_cnt_val;
+       u16 pm1b_cnt_val;
+       u64 wakeup_vector;
+       u32 vector_width;
+       u64 kernel_s3_resume_vector;
+} __packed;
+
+/*
+ * shared memory page used for communication between tboot and kernel
+ */
+struct tboot {
+       /*
+        * version 3+ fields:
+        */
+
+       /* TBOOT_UUID */
+       u8 uuid[16];
+
+       /* version number: 5 is current */
+       u32 version;
+
+       /* physical addr of tb_log_t log */
+       u32 log_addr;
+
+       /*
+        * physical addr of entry point for tboot shutdown and
+        * type of shutdown (TB_SHUTDOWN_*) being requested
+        */
+       u32 shutdown_entry;
+       u32 shutdown_type;
+
+       /* kernel-specified ACPI info for Sx shutdown */
+       struct tboot_acpi_sleep_info acpi_sinfo;
+
+       /* tboot location in memory (physical) */
+       u32 tboot_base;
+       u32 tboot_size;
+
+       /* memory regions (phys addrs) for tboot to MAC on S3 */
+       u8 num_mac_regions;
+       struct tboot_mac_region mac_regions[MAX_TB_MAC_REGIONS];
+
+
+       /*
+        * version 4+ fields:
+        */
+
+       /* symmetric key for use by kernel; will be encrypted on S3 */
+       u8 s3_key[TB_KEY_SIZE];
+
+
+       /*
+        * version 5+ fields:
+        */
+
+       /* used to 4byte-align num_in_wfs */
+       u8 reserved_align[3];
+
+       /* number of processors in wait-for-SIPI */
+       u32 num_in_wfs;
+} __packed;
+
+/*
+ * UUID for tboot data struct to facilitate matching
+ * defined as {663C8DFF-E8B3-4b82-AABF-19EA4D057A08} by tboot, which is
+ * represented as {} in the char array used here
+ */
+#define TBOOT_UUID     {0xff, 0x8d, 0x3c, 0x66, 0xb3, 0xe8, 0x82, 0x4b, 0xbf,\
+                        0xaa, 0x19, 0xea, 0x4d, 0x5, 0x7a, 0x8}
+
+extern struct tboot *tboot;
+
+static inline int tboot_enabled(void)
+{
+       return tboot != NULL;
+}
+
+extern void tboot_probe(void);
+extern void tboot_shutdown(u32 shutdown_type);
+extern void tboot_sleep(u8 sleep_state, u32 pm1a_control, u32 pm1b_control);
+extern struct acpi_table_header *tboot_get_dmar_table(
+                                     struct acpi_table_header *dmar_tbl);
+extern int tboot_force_iommu(void);
+
+#else
+
+#define tboot_probe()                  do { } while (0)
+#define tboot_shutdown(shutdown_type)  do { } while (0)
+#define tboot_sleep(sleep_state, pm1a_control, pm1b_control)   \
+                                       do { } while (0)
+#define tboot_get_dmar_table(dmar_tbl) (dmar_tbl)
+#define tboot_force_iommu()            0
+
+#endif /* !CONFIG_INTEL_TXT */
+
+#endif /* _LINUX_TBOOT_H */
diff --git a/include/linux/usb/video.h b/include/linux/usb/video.h
new file mode 100644 (file)
index 0000000..be436d9
--- /dev/null
@@ -0,0 +1,164 @@
+/*
+ * USB Video Class definitions.
+ *
+ * Copyright (C) 2009 Laurent Pinchart <laurent.pinchart@skynet.be>
+ *
+ * This file holds USB constants and structures defined by the USB Device
+ * Class Definition for Video Devices. Unless otherwise stated, comments
+ * below reference relevant sections of the USB Video Class 1.1 specification
+ * available at
+ *
+ * http://www.usb.org/developers/devclass_docs/USB_Video_Class_1_1.zip
+ */
+
+#ifndef __LINUX_USB_VIDEO_H
+#define __LINUX_USB_VIDEO_H
+
+#include <linux/types.h>
+
+/* --------------------------------------------------------------------------
+ * UVC constants
+ */
+
+/* A.2. Video Interface Subclass Codes */
+#define UVC_SC_UNDEFINED                               0x00
+#define UVC_SC_VIDEOCONTROL                            0x01
+#define UVC_SC_VIDEOSTREAMING                          0x02
+#define UVC_SC_VIDEO_INTERFACE_COLLECTION              0x03
+
+/* A.3. Video Interface Protocol Codes */
+#define UVC_PC_PROTOCOL_UNDEFINED                      0x00
+
+/* A.5. Video Class-Specific VC Interface Descriptor Subtypes */
+#define UVC_VC_DESCRIPTOR_UNDEFINED                    0x00
+#define UVC_VC_HEADER                                  0x01
+#define UVC_VC_INPUT_TERMINAL                          0x02
+#define UVC_VC_OUTPUT_TERMINAL                         0x03
+#define UVC_VC_SELECTOR_UNIT                           0x04
+#define UVC_VC_PROCESSING_UNIT                         0x05
+#define UVC_VC_EXTENSION_UNIT                          0x06
+
+/* A.6. Video Class-Specific VS Interface Descriptor Subtypes */
+#define UVC_VS_UNDEFINED                               0x00
+#define UVC_VS_INPUT_HEADER                            0x01
+#define UVC_VS_OUTPUT_HEADER                           0x02
+#define UVC_VS_STILL_IMAGE_FRAME                       0x03
+#define UVC_VS_FORMAT_UNCOMPRESSED                     0x04
+#define UVC_VS_FRAME_UNCOMPRESSED                      0x05
+#define UVC_VS_FORMAT_MJPEG                            0x06
+#define UVC_VS_FRAME_MJPEG                             0x07
+#define UVC_VS_FORMAT_MPEG2TS                          0x0a
+#define UVC_VS_FORMAT_DV                               0x0c
+#define UVC_VS_COLORFORMAT                             0x0d
+#define UVC_VS_FORMAT_FRAME_BASED                      0x10
+#define UVC_VS_FRAME_FRAME_BASED                       0x11
+#define UVC_VS_FORMAT_STREAM_BASED                     0x12
+
+/* A.7. Video Class-Specific Endpoint Descriptor Subtypes */
+#define UVC_EP_UNDEFINED                               0x00
+#define UVC_EP_GENERAL                                 0x01
+#define UVC_EP_ENDPOINT                                        0x02
+#define UVC_EP_INTERRUPT                               0x03
+
+/* A.8. Video Class-Specific Request Codes */
+#define UVC_RC_UNDEFINED                               0x00
+#define UVC_SET_CUR                                    0x01
+#define UVC_GET_CUR                                    0x81
+#define UVC_GET_MIN                                    0x82
+#define UVC_GET_MAX                                    0x83
+#define UVC_GET_RES                                    0x84
+#define UVC_GET_LEN                                    0x85
+#define UVC_GET_INFO                                   0x86
+#define UVC_GET_DEF                                    0x87
+
+/* A.9.1. VideoControl Interface Control Selectors */
+#define UVC_VC_CONTROL_UNDEFINED                       0x00
+#define UVC_VC_VIDEO_POWER_MODE_CONTROL                        0x01
+#define UVC_VC_REQUEST_ERROR_CODE_CONTROL              0x02
+
+/* A.9.2. Terminal Control Selectors */
+#define UVC_TE_CONTROL_UNDEFINED                       0x00
+
+/* A.9.3. Selector Unit Control Selectors */
+#define UVC_SU_CONTROL_UNDEFINED                       0x00
+#define UVC_SU_INPUT_SELECT_CONTROL                    0x01
+
+/* A.9.4. Camera Terminal Control Selectors */
+#define UVC_CT_CONTROL_UNDEFINED                       0x00
+#define UVC_CT_SCANNING_MODE_CONTROL                   0x01
+#define UVC_CT_AE_MODE_CONTROL                         0x02
+#define UVC_CT_AE_PRIORITY_CONTROL                     0x03
+#define UVC_CT_EXPOSURE_TIME_ABSOLUTE_CONTROL          0x04
+#define UVC_CT_EXPOSURE_TIME_RELATIVE_CONTROL          0x05
+#define UVC_CT_FOCUS_ABSOLUTE_CONTROL                  0x06
+#define UVC_CT_FOCUS_RELATIVE_CONTROL                  0x07
+#define UVC_CT_FOCUS_AUTO_CONTROL                      0x08
+#define UVC_CT_IRIS_ABSOLUTE_CONTROL                   0x09
+#define UVC_CT_IRIS_RELATIVE_CONTROL                   0x0a
+#define UVC_CT_ZOOM_ABSOLUTE_CONTROL                   0x0b
+#define UVC_CT_ZOOM_RELATIVE_CONTROL                   0x0c
+#define UVC_CT_PANTILT_ABSOLUTE_CONTROL                        0x0d
+#define UVC_CT_PANTILT_RELATIVE_CONTROL                        0x0e
+#define UVC_CT_ROLL_ABSOLUTE_CONTROL                   0x0f
+#define UVC_CT_ROLL_RELATIVE_CONTROL                   0x10
+#define UVC_CT_PRIVACY_CONTROL                         0x11
+
+/* A.9.5. Processing Unit Control Selectors */
+#define UVC_PU_CONTROL_UNDEFINED                       0x00
+#define UVC_PU_BACKLIGHT_COMPENSATION_CONTROL          0x01
+#define UVC_PU_BRIGHTNESS_CONTROL                      0x02
+#define UVC_PU_CONTRAST_CONTROL                                0x03
+#define UVC_PU_GAIN_CONTROL                            0x04
+#define UVC_PU_POWER_LINE_FREQUENCY_CONTROL            0x05
+#define UVC_PU_HUE_CONTROL                             0x06
+#define UVC_PU_SATURATION_CONTROL                      0x07
+#define UVC_PU_SHARPNESS_CONTROL                       0x08
+#define UVC_PU_GAMMA_CONTROL                           0x09
+#define UVC_PU_WHITE_BALANCE_TEMPERATURE_CONTROL       0x0a
+#define UVC_PU_WHITE_BALANCE_TEMPERATURE_AUTO_CONTROL  0x0b
+#define UVC_PU_WHITE_BALANCE_COMPONENT_CONTROL         0x0c
+#define UVC_PU_WHITE_BALANCE_COMPONENT_AUTO_CONTROL    0x0d
+#define UVC_PU_DIGITAL_MULTIPLIER_CONTROL              0x0e
+#define UVC_PU_DIGITAL_MULTIPLIER_LIMIT_CONTROL                0x0f
+#define UVC_PU_HUE_AUTO_CONTROL                                0x10
+#define UVC_PU_ANALOG_VIDEO_STANDARD_CONTROL           0x11
+#define UVC_PU_ANALOG_LOCK_STATUS_CONTROL              0x12
+
+/* A.9.7. VideoStreaming Interface Control Selectors */
+#define UVC_VS_CONTROL_UNDEFINED                       0x00
+#define UVC_VS_PROBE_CONTROL                           0x01
+#define UVC_VS_COMMIT_CONTROL                          0x02
+#define UVC_VS_STILL_PROBE_CONTROL                     0x03
+#define UVC_VS_STILL_COMMIT_CONTROL                    0x04
+#define UVC_VS_STILL_IMAGE_TRIGGER_CONTROL             0x05
+#define UVC_VS_STREAM_ERROR_CODE_CONTROL               0x06
+#define UVC_VS_GENERATE_KEY_FRAME_CONTROL              0x07
+#define UVC_VS_UPDATE_FRAME_SEGMENT_CONTROL            0x08
+#define UVC_VS_SYNC_DELAY_CONTROL                      0x09
+
+/* B.1. USB Terminal Types */
+#define UVC_TT_VENDOR_SPECIFIC                         0x0100
+#define UVC_TT_STREAMING                               0x0101
+
+/* B.2. Input Terminal Types */
+#define UVC_ITT_VENDOR_SPECIFIC                                0x0200
+#define UVC_ITT_CAMERA                                 0x0201
+#define UVC_ITT_MEDIA_TRANSPORT_INPUT                  0x0202
+
+/* B.3. Output Terminal Types */
+#define UVC_OTT_VENDOR_SPECIFIC                                0x0300
+#define UVC_OTT_DISPLAY                                        0x0301
+#define UVC_OTT_MEDIA_TRANSPORT_OUTPUT                 0x0302
+
+/* B.4. External Terminal Types */
+#define UVC_EXTERNAL_VENDOR_SPECIFIC                   0x0400
+#define UVC_COMPOSITE_CONNECTOR                                0x0401
+#define UVC_SVIDEO_CONNECTOR                           0x0402
+#define UVC_COMPONENT_CONNECTOR                                0x0403
+
+/* 2.4.2.2. Status Packet Type */
+#define UVC_STATUS_TYPE_CONTROL                                1
+#define UVC_STATUS_TYPE_STREAMING                      2
+
+#endif /* __LINUX_USB_VIDEO_H */
+
index 74f16876f38d643eb6b9df7c548b1b90131c6794..3689d7d81fe9975b1a51ee544a6adfdc1dc25c95 100644 (file)
@@ -167,6 +167,7 @@ enum v4l2_ctrl_type {
        V4L2_CTRL_TYPE_BUTTON        = 4,
        V4L2_CTRL_TYPE_INTEGER64     = 5,
        V4L2_CTRL_TYPE_CTRL_CLASS    = 6,
+       V4L2_CTRL_TYPE_STRING        = 7,
 };
 
 enum v4l2_tuner_type {
@@ -252,10 +253,12 @@ struct v4l2_capability {
 #define V4L2_CAP_RDS_CAPTURE           0x00000100  /* RDS data capture */
 #define V4L2_CAP_VIDEO_OUTPUT_OVERLAY  0x00000200  /* Can do video output overlay */
 #define V4L2_CAP_HW_FREQ_SEEK          0x00000400  /* Can do hardware frequency seek  */
+#define V4L2_CAP_RDS_OUTPUT            0x00000800  /* Is an RDS encoder */
 
 #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_MODULATOR             0x00080000  /* has a modulator */
 
 #define V4L2_CAP_READWRITE              0x01000000  /* read/write systemcalls */
 #define V4L2_CAP_ASYNCIO                0x02000000  /* async I/O */
@@ -275,7 +278,9 @@ struct v4l2_pix_format {
        __u32                   priv;           /* private data, depends on pixelformat */
 };
 
-/*      Pixel format         FOURCC                        depth  Description  */
+/*      Pixel format         FOURCC                          depth  Description  */
+
+/* RGB formats */
 #define V4L2_PIX_FMT_RGB332  v4l2_fourcc('R', 'G', 'B', '1') /*  8  RGB-3-3-2     */
 #define V4L2_PIX_FMT_RGB444  v4l2_fourcc('R', '4', '4', '4') /* 16  xxxxrrrr ggggbbbb */
 #define V4L2_PIX_FMT_RGB555  v4l2_fourcc('R', 'G', 'B', 'O') /* 16  RGB-5-5-5     */
@@ -286,12 +291,20 @@ struct v4l2_pix_format {
 #define V4L2_PIX_FMT_RGB24   v4l2_fourcc('R', 'G', 'B', '3') /* 24  RGB-8-8-8     */
 #define V4L2_PIX_FMT_BGR32   v4l2_fourcc('B', 'G', 'R', '4') /* 32  BGR-8-8-8-8   */
 #define V4L2_PIX_FMT_RGB32   v4l2_fourcc('R', 'G', 'B', '4') /* 32  RGB-8-8-8-8   */
+
+/* Grey formats */
 #define V4L2_PIX_FMT_GREY    v4l2_fourcc('G', 'R', 'E', 'Y') /*  8  Greyscale     */
 #define V4L2_PIX_FMT_Y16     v4l2_fourcc('Y', '1', '6', ' ') /* 16  Greyscale     */
+
+/* Palette formats */
 #define V4L2_PIX_FMT_PAL8    v4l2_fourcc('P', 'A', 'L', '8') /*  8  8-bit palette */
+
+/* Luminance+Chrominance formats */
 #define V4L2_PIX_FMT_YVU410  v4l2_fourcc('Y', 'V', 'U', '9') /*  9  YVU 4:1:0     */
 #define V4L2_PIX_FMT_YVU420  v4l2_fourcc('Y', 'V', '1', '2') /* 12  YVU 4:2:0     */
 #define V4L2_PIX_FMT_YUYV    v4l2_fourcc('Y', 'U', 'Y', 'V') /* 16  YUV 4:2:2     */
+#define V4L2_PIX_FMT_YYUV    v4l2_fourcc('Y', 'Y', 'U', 'V') /* 16  YUV 4:2:2     */
+#define V4L2_PIX_FMT_YVYU    v4l2_fourcc('Y', 'V', 'Y', 'U') /* 16 YVU 4:2:2 */
 #define V4L2_PIX_FMT_UYVY    v4l2_fourcc('U', 'Y', 'V', 'Y') /* 16  YUV 4:2:2     */
 #define V4L2_PIX_FMT_VYUY    v4l2_fourcc('V', 'Y', 'U', 'Y') /* 16  YUV 4:2:2     */
 #define V4L2_PIX_FMT_YUV422P v4l2_fourcc('4', '2', '2', 'P') /* 16  YVU422 planar */
@@ -301,6 +314,10 @@ struct v4l2_pix_format {
 #define V4L2_PIX_FMT_YUV555  v4l2_fourcc('Y', 'U', 'V', 'O') /* 16  YUV-5-5-5     */
 #define V4L2_PIX_FMT_YUV565  v4l2_fourcc('Y', 'U', 'V', 'P') /* 16  YUV-5-6-5     */
 #define V4L2_PIX_FMT_YUV32   v4l2_fourcc('Y', 'U', 'V', '4') /* 32  YUV-8-8-8-8   */
+#define V4L2_PIX_FMT_YUV410  v4l2_fourcc('Y', 'U', 'V', '9') /*  9  YUV 4:1:0     */
+#define V4L2_PIX_FMT_YUV420  v4l2_fourcc('Y', 'U', '1', '2') /* 12  YUV 4:2:0     */
+#define V4L2_PIX_FMT_HI240   v4l2_fourcc('H', 'I', '2', '4') /*  8  8-bit color   */
+#define V4L2_PIX_FMT_HM12    v4l2_fourcc('H', 'M', '1', '2') /*  8  YUV 4:2:0 16x16 macroblocks */
 
 /* two planes -- one Y, one Cr + Cb interleaved  */
 #define V4L2_PIX_FMT_NV12    v4l2_fourcc('N', 'V', '1', '2') /* 12  Y/CbCr 4:2:0  */
@@ -308,25 +325,17 @@ struct v4l2_pix_format {
 #define V4L2_PIX_FMT_NV16    v4l2_fourcc('N', 'V', '1', '6') /* 16  Y/CbCr 4:2:2  */
 #define V4L2_PIX_FMT_NV61    v4l2_fourcc('N', 'V', '6', '1') /* 16  Y/CrCb 4:2:2  */
 
-/*  The following formats are not defined in the V4L2 specification */
-#define V4L2_PIX_FMT_YUV410  v4l2_fourcc('Y', 'U', 'V', '9') /*  9  YUV 4:1:0     */
-#define V4L2_PIX_FMT_YUV420  v4l2_fourcc('Y', 'U', '1', '2') /* 12  YUV 4:2:0     */
-#define V4L2_PIX_FMT_YYUV    v4l2_fourcc('Y', 'Y', 'U', 'V') /* 16  YUV 4:2:2     */
-#define V4L2_PIX_FMT_HI240   v4l2_fourcc('H', 'I', '2', '4') /*  8  8-bit color   */
-#define V4L2_PIX_FMT_HM12    v4l2_fourcc('H', 'M', '1', '2') /*  8  YUV 4:2:0 16x16 macroblocks */
-
-/* see http://www.siliconimaging.com/RGB%20Bayer.htm */
+/* Bayer formats - see http://www.siliconimaging.com/RGB%20Bayer.htm */
 #define V4L2_PIX_FMT_SBGGR8  v4l2_fourcc('B', 'A', '8', '1') /*  8  BGBG.. GRGR.. */
 #define V4L2_PIX_FMT_SGBRG8  v4l2_fourcc('G', 'B', 'R', 'G') /*  8  GBGB.. RGRG.. */
 #define V4L2_PIX_FMT_SGRBG8  v4l2_fourcc('G', 'R', 'B', 'G') /*  8  GRGR.. BGBG.. */
-
-/*
- * 10bit raw bayer, expanded to 16 bits
- * xxxxrrrrrrrrrrxxxxgggggggggg xxxxggggggggggxxxxbbbbbbbbbb...
- */
-#define V4L2_PIX_FMT_SGRBG10 v4l2_fourcc('B', 'A', '1', '0')
-/* 10bit raw bayer DPCM compressed to 8 bits */
+#define V4L2_PIX_FMT_SGRBG10 v4l2_fourcc('B', 'A', '1', '0') /* 10bit raw bayer */
+       /* 10bit raw bayer DPCM compressed to 8 bits */
 #define V4L2_PIX_FMT_SGRBG10DPCM8 v4l2_fourcc('B', 'D', '1', '0')
+       /*
+        * 10bit raw bayer, expanded to 16 bits
+        * xxxxrrrrrrrrrrxxxxgggggggggg xxxxggggggggggxxxxbbbbbbbbbb...
+        */
 #define V4L2_PIX_FMT_SBGGR16 v4l2_fourcc('B', 'Y', 'R', '2') /* 16  BGBG.. GRGR.. */
 
 /* compressed formats */
@@ -350,7 +359,6 @@ struct v4l2_pix_format {
 #define V4L2_PIX_FMT_MR97310A v4l2_fourcc('M', '3', '1', '0') /* compressed BGGR bayer */
 #define V4L2_PIX_FMT_SQ905C   v4l2_fourcc('9', '0', '5', 'C') /* compressed RGGB bayer */
 #define V4L2_PIX_FMT_PJPG     v4l2_fourcc('P', 'J', 'P', 'G') /* Pixart 73xx JPEG */
-#define V4L2_PIX_FMT_YVYU     v4l2_fourcc('Y', 'V', 'Y', 'U') /* 16 YVU 4:2:2 */
 #define V4L2_PIX_FMT_OV511    v4l2_fourcc('O', '5', '1', '1') /* ov511 JPEG */
 #define V4L2_PIX_FMT_OV518    v4l2_fourcc('O', '5', '1', '8') /* ov518 JPEG */
 
@@ -367,6 +375,7 @@ struct v4l2_fmtdesc {
 };
 
 #define V4L2_FMT_FLAG_COMPRESSED 0x0001
+#define V4L2_FMT_FLAG_EMULATED   0x0002
 
 #if 1
        /* Experimental Frame Size and frame rate enumeration */
@@ -788,11 +797,12 @@ struct v4l2_control {
 
 struct v4l2_ext_control {
        __u32 id;
-       __u32 reserved2[2];
+       __u32 size;
+       __u32 reserved2[1];
        union {
                __s32 value;
                __s64 value64;
-               void *reserved;
+               char *string;
        };
 } __attribute__ ((packed));
 
@@ -808,6 +818,7 @@ struct v4l2_ext_controls {
 #define V4L2_CTRL_CLASS_USER 0x00980000        /* Old-style 'user' controls */
 #define V4L2_CTRL_CLASS_MPEG 0x00990000        /* MPEG-compression controls */
 #define V4L2_CTRL_CLASS_CAMERA 0x009a0000      /* Camera class controls */
+#define V4L2_CTRL_CLASS_FM_TX 0x009b0000       /* FM Modulator control class */
 
 #define V4L2_CTRL_ID_MASK                (0x0fffffff)
 #define V4L2_CTRL_ID2CLASS(id)    ((id) & 0x0fff0000UL)
@@ -1147,6 +1158,39 @@ enum  v4l2_exposure_auto_type {
 
 #define V4L2_CID_PRIVACY                       (V4L2_CID_CAMERA_CLASS_BASE+16)
 
+/* FM Modulator class control IDs */
+#define V4L2_CID_FM_TX_CLASS_BASE              (V4L2_CTRL_CLASS_FM_TX | 0x900)
+#define V4L2_CID_FM_TX_CLASS                   (V4L2_CTRL_CLASS_FM_TX | 1)
+
+#define V4L2_CID_RDS_TX_DEVIATION              (V4L2_CID_FM_TX_CLASS_BASE + 1)
+#define V4L2_CID_RDS_TX_PI                     (V4L2_CID_FM_TX_CLASS_BASE + 2)
+#define V4L2_CID_RDS_TX_PTY                    (V4L2_CID_FM_TX_CLASS_BASE + 3)
+#define V4L2_CID_RDS_TX_PS_NAME                        (V4L2_CID_FM_TX_CLASS_BASE + 5)
+#define V4L2_CID_RDS_TX_RADIO_TEXT             (V4L2_CID_FM_TX_CLASS_BASE + 6)
+
+#define V4L2_CID_AUDIO_LIMITER_ENABLED         (V4L2_CID_FM_TX_CLASS_BASE + 64)
+#define V4L2_CID_AUDIO_LIMITER_RELEASE_TIME    (V4L2_CID_FM_TX_CLASS_BASE + 65)
+#define V4L2_CID_AUDIO_LIMITER_DEVIATION       (V4L2_CID_FM_TX_CLASS_BASE + 66)
+
+#define V4L2_CID_AUDIO_COMPRESSION_ENABLED     (V4L2_CID_FM_TX_CLASS_BASE + 80)
+#define V4L2_CID_AUDIO_COMPRESSION_GAIN                (V4L2_CID_FM_TX_CLASS_BASE + 81)
+#define V4L2_CID_AUDIO_COMPRESSION_THRESHOLD   (V4L2_CID_FM_TX_CLASS_BASE + 82)
+#define V4L2_CID_AUDIO_COMPRESSION_ATTACK_TIME (V4L2_CID_FM_TX_CLASS_BASE + 83)
+#define V4L2_CID_AUDIO_COMPRESSION_RELEASE_TIME        (V4L2_CID_FM_TX_CLASS_BASE + 84)
+
+#define V4L2_CID_PILOT_TONE_ENABLED            (V4L2_CID_FM_TX_CLASS_BASE + 96)
+#define V4L2_CID_PILOT_TONE_DEVIATION          (V4L2_CID_FM_TX_CLASS_BASE + 97)
+#define V4L2_CID_PILOT_TONE_FREQUENCY          (V4L2_CID_FM_TX_CLASS_BASE + 98)
+
+#define V4L2_CID_TUNE_PREEMPHASIS              (V4L2_CID_FM_TX_CLASS_BASE + 112)
+enum v4l2_preemphasis {
+       V4L2_PREEMPHASIS_DISABLED       = 0,
+       V4L2_PREEMPHASIS_50_uS          = 1,
+       V4L2_PREEMPHASIS_75_uS          = 2,
+};
+#define V4L2_CID_TUNE_POWER_LEVEL              (V4L2_CID_FM_TX_CLASS_BASE + 113)
+#define V4L2_CID_TUNE_ANTENNA_CAPACITOR                (V4L2_CID_FM_TX_CLASS_BASE + 114)
+
 /*
  *     T U N I N G
  */
@@ -1181,6 +1225,7 @@ struct v4l2_modulator {
 #define V4L2_TUNER_CAP_LANG2           0x0020
 #define V4L2_TUNER_CAP_SAP             0x0020
 #define V4L2_TUNER_CAP_LANG1           0x0040
+#define V4L2_TUNER_CAP_RDS             0x0080
 
 /*  Flags for the 'rxsubchans' field */
 #define V4L2_TUNER_SUB_MONO            0x0001
@@ -1188,6 +1233,7 @@ struct v4l2_modulator {
 #define V4L2_TUNER_SUB_LANG2           0x0004
 #define V4L2_TUNER_SUB_SAP             0x0004
 #define V4L2_TUNER_SUB_LANG1           0x0008
+#define V4L2_TUNER_SUB_RDS             0x0010
 
 /*  Values for the 'audmode' field */
 #define V4L2_TUNER_MODE_MONO           0x0000
@@ -1212,6 +1258,27 @@ struct v4l2_hw_freq_seek {
        __u32                 reserved[8];
 };
 
+/*
+ *     R D S
+ */
+
+struct v4l2_rds_data {
+       __u8    lsb;
+       __u8    msb;
+       __u8    block;
+} __attribute__ ((packed));
+
+#define V4L2_RDS_BLOCK_MSK      0x7
+#define V4L2_RDS_BLOCK_A        0
+#define V4L2_RDS_BLOCK_B        1
+#define V4L2_RDS_BLOCK_C        2
+#define V4L2_RDS_BLOCK_D        3
+#define V4L2_RDS_BLOCK_C_ALT    4
+#define V4L2_RDS_BLOCK_INVALID          7
+
+#define V4L2_RDS_BLOCK_CORRECTED 0x40
+#define V4L2_RDS_BLOCK_ERROR    0x80
+
 /*
  *     A U D I O
  */
index a43ebec3a7b92692f0cc970a075e2462b705e270..227c2a585e4f326a4e3355fc01f34a1eb4901b03 100644 (file)
@@ -115,4 +115,10 @@ extern rwlock_t vmlist_lock;
 extern struct vm_struct *vmlist;
 extern __init void vm_area_register_early(struct vm_struct *vm, size_t align);
 
+struct vm_struct **pcpu_get_vm_areas(const unsigned long *offsets,
+                                    const size_t *sizes, int nr_vms,
+                                    size_t align, gfp_t gfp_mask);
+
+void pcpu_free_vm_areas(struct vm_struct **vms, int nr_vms);
+
 #endif /* _LINUX_VMALLOC_H */
index d347632f1861a0ec92845eb78caa76b767cfcdc5..75cf58666ff9f4a57c71b2d9512dbacbefc41911 100644 (file)
@@ -50,7 +50,6 @@ struct writeback_control {
        unsigned encountered_congestion:1; /* An output: a queue is full */
        unsigned for_kupdate:1;         /* A kupdate writeback */
        unsigned for_reclaim:1;         /* Invoked from the page allocator */
-       unsigned for_writepages:1;      /* This is a writepages() call */
        unsigned range_cyclic:1;        /* range_start is cyclic */
        unsigned more_io:1;             /* more io to be dispatched */
        /*
@@ -69,8 +68,8 @@ struct writeback_control {
  */    
 struct bdi_writeback;
 int inode_wait(void *);
-long writeback_inodes_sb(struct super_block *);
-long sync_inodes_sb(struct super_block *);
+void writeback_inodes_sb(struct super_block *);
+void sync_inodes_sb(struct super_block *);
 void writeback_inodes_wbc(struct writeback_control *wbc);
 long wb_do_writeback(struct bdi_writeback *wb, int force_wait);
 void wakeup_flusher_threads(long nr_pages);
index 9dcb632f608324d09e234fad008d427a422d59a7..29f0e53cff94cdba8341bd0e8d77d78312c7bb0a 100644 (file)
 #define IR_TYPE_PD      2 /* Pulse distance encoded IR */
 #define IR_TYPE_OTHER  99
 
-#define IR_KEYTAB_TYPE u32
-#define IR_KEYTAB_SIZE 128  // enougth for rc5, probably need more some day ...
+#define IR_KEYTAB_TYPE u32
+#define IR_KEYTAB_SIZE 128  /* enougth for rc5, probably need more some day */
+
+struct ir_scancode {
+       u16     scancode;
+       u32     keycode;
+};
+
+struct ir_scancode_table {
+       struct ir_scancode *scan;
+       int size;
+};
 
 #define IR_KEYCODE(tab,code)   (((unsigned)code < IR_KEYTAB_SIZE) \
                                 ? tab[code] : KEY_RESERVED)
@@ -93,7 +103,7 @@ struct card_ir {
 };
 
 void ir_input_init(struct input_dev *dev, struct ir_input_state *ir,
-                  int ir_type, IR_KEYTAB_TYPE *ir_codes);
+                  int ir_type, struct ir_scancode_table *ir_codes);
 void ir_input_nokey(struct input_dev *dev, struct ir_input_state *ir);
 void ir_input_keydown(struct input_dev *dev, struct ir_input_state *ir,
                      u32 ir_key, u32 ir_raw);
@@ -107,67 +117,63 @@ void ir_rc5_timer_keyup(unsigned long data);
 
 /* Keymaps to be used by other modules */
 
-extern IR_KEYTAB_TYPE ir_codes_empty[IR_KEYTAB_SIZE];
-extern IR_KEYTAB_TYPE ir_codes_avermedia[IR_KEYTAB_SIZE];
-extern IR_KEYTAB_TYPE ir_codes_avermedia_dvbt[IR_KEYTAB_SIZE];
-extern IR_KEYTAB_TYPE ir_codes_avermedia_m135a[IR_KEYTAB_SIZE];
-extern IR_KEYTAB_TYPE ir_codes_avermedia_cardbus[IR_KEYTAB_SIZE];
-extern IR_KEYTAB_TYPE ir_codes_apac_viewcomp[IR_KEYTAB_SIZE];
-extern IR_KEYTAB_TYPE ir_codes_pixelview[IR_KEYTAB_SIZE];
-extern IR_KEYTAB_TYPE ir_codes_pixelview_new[IR_KEYTAB_SIZE];
-extern IR_KEYTAB_TYPE ir_codes_nebula[IR_KEYTAB_SIZE];
-extern IR_KEYTAB_TYPE ir_codes_dntv_live_dvb_t[IR_KEYTAB_SIZE];
-extern IR_KEYTAB_TYPE ir_codes_iodata_bctv7e[IR_KEYTAB_SIZE];
-extern IR_KEYTAB_TYPE ir_codes_adstech_dvb_t_pci[IR_KEYTAB_SIZE];
-extern IR_KEYTAB_TYPE ir_codes_msi_tvanywhere[IR_KEYTAB_SIZE];
-extern IR_KEYTAB_TYPE ir_codes_cinergy_1400[IR_KEYTAB_SIZE];
-extern IR_KEYTAB_TYPE ir_codes_avertv_303[IR_KEYTAB_SIZE];
-extern IR_KEYTAB_TYPE ir_codes_dntv_live_dvbt_pro[IR_KEYTAB_SIZE];
-extern IR_KEYTAB_TYPE ir_codes_em_terratec[IR_KEYTAB_SIZE];
-extern IR_KEYTAB_TYPE ir_codes_pinnacle_grey[IR_KEYTAB_SIZE];
-extern IR_KEYTAB_TYPE ir_codes_flyvideo[IR_KEYTAB_SIZE];
-extern IR_KEYTAB_TYPE ir_codes_flydvb[IR_KEYTAB_SIZE];
-extern IR_KEYTAB_TYPE ir_codes_cinergy[IR_KEYTAB_SIZE];
-extern IR_KEYTAB_TYPE ir_codes_eztv[IR_KEYTAB_SIZE];
-extern IR_KEYTAB_TYPE ir_codes_avermedia[IR_KEYTAB_SIZE];
-extern IR_KEYTAB_TYPE ir_codes_videomate_tv_pvr[IR_KEYTAB_SIZE];
-extern IR_KEYTAB_TYPE ir_codes_manli[IR_KEYTAB_SIZE];
-extern IR_KEYTAB_TYPE ir_codes_gotview7135[IR_KEYTAB_SIZE];
-extern IR_KEYTAB_TYPE ir_codes_purpletv[IR_KEYTAB_SIZE];
-extern IR_KEYTAB_TYPE ir_codes_pctv_sedna[IR_KEYTAB_SIZE];
-extern IR_KEYTAB_TYPE ir_codes_pv951[IR_KEYTAB_SIZE];
-extern IR_KEYTAB_TYPE ir_codes_rc5_tv[IR_KEYTAB_SIZE];
-extern IR_KEYTAB_TYPE ir_codes_winfast[IR_KEYTAB_SIZE];
-extern IR_KEYTAB_TYPE ir_codes_pinnacle_color[IR_KEYTAB_SIZE];
-extern IR_KEYTAB_TYPE ir_codes_hauppauge_new[IR_KEYTAB_SIZE];
-extern IR_KEYTAB_TYPE ir_codes_npgtech[IR_KEYTAB_SIZE];
-extern IR_KEYTAB_TYPE ir_codes_norwood[IR_KEYTAB_SIZE];
-extern IR_KEYTAB_TYPE ir_codes_proteus_2309[IR_KEYTAB_SIZE];
-extern IR_KEYTAB_TYPE ir_codes_budget_ci_old[IR_KEYTAB_SIZE];
-extern IR_KEYTAB_TYPE ir_codes_asus_pc39[IR_KEYTAB_SIZE];
-extern IR_KEYTAB_TYPE ir_codes_encore_enltv[IR_KEYTAB_SIZE];
-extern IR_KEYTAB_TYPE ir_codes_encore_enltv2[IR_KEYTAB_SIZE];
-extern IR_KEYTAB_TYPE ir_codes_tt_1500[IR_KEYTAB_SIZE];
-extern IR_KEYTAB_TYPE ir_codes_fusionhdtv_mce[IR_KEYTAB_SIZE];
-extern IR_KEYTAB_TYPE ir_codes_behold[IR_KEYTAB_SIZE];
-extern IR_KEYTAB_TYPE ir_codes_behold_columbus[IR_KEYTAB_SIZE];
-extern IR_KEYTAB_TYPE ir_codes_pinnacle_pctv_hd[IR_KEYTAB_SIZE];
-extern IR_KEYTAB_TYPE ir_codes_genius_tvgo_a11mce[IR_KEYTAB_SIZE];
-extern IR_KEYTAB_TYPE ir_codes_powercolor_real_angel[IR_KEYTAB_SIZE];
-extern IR_KEYTAB_TYPE ir_codes_avermedia_a16d[IR_KEYTAB_SIZE];
-extern IR_KEYTAB_TYPE ir_codes_encore_enltv_fm53[IR_KEYTAB_SIZE];
-extern IR_KEYTAB_TYPE ir_codes_real_audio_220_32_keys[IR_KEYTAB_SIZE];
-extern IR_KEYTAB_TYPE ir_codes_msi_tvanywhere_plus[IR_KEYTAB_SIZE];
-extern IR_KEYTAB_TYPE ir_codes_ati_tv_wonder_hd_600[IR_KEYTAB_SIZE];
-extern IR_KEYTAB_TYPE ir_codes_kworld_plus_tv_analog[IR_KEYTAB_SIZE];
-extern IR_KEYTAB_TYPE ir_codes_kaiomy[IR_KEYTAB_SIZE];
-extern IR_KEYTAB_TYPE ir_codes_dm1105_nec[IR_KEYTAB_SIZE];
-extern IR_KEYTAB_TYPE ir_codes_evga_indtube[IR_KEYTAB_SIZE];
-
+extern struct ir_scancode_table ir_codes_empty_table;
+extern struct ir_scancode_table ir_codes_avermedia_table;
+extern struct ir_scancode_table ir_codes_avermedia_dvbt_table;
+extern struct ir_scancode_table ir_codes_avermedia_m135a_table;
+extern struct ir_scancode_table ir_codes_avermedia_cardbus_table;
+extern struct ir_scancode_table ir_codes_apac_viewcomp_table;
+extern struct ir_scancode_table ir_codes_pixelview_table;
+extern struct ir_scancode_table ir_codes_pixelview_new_table;
+extern struct ir_scancode_table ir_codes_nebula_table;
+extern struct ir_scancode_table ir_codes_dntv_live_dvb_t_table;
+extern struct ir_scancode_table ir_codes_iodata_bctv7e_table;
+extern struct ir_scancode_table ir_codes_adstech_dvb_t_pci_table;
+extern struct ir_scancode_table ir_codes_msi_tvanywhere_table;
+extern struct ir_scancode_table ir_codes_cinergy_1400_table;
+extern struct ir_scancode_table ir_codes_avertv_303_table;
+extern struct ir_scancode_table ir_codes_dntv_live_dvbt_pro_table;
+extern struct ir_scancode_table ir_codes_em_terratec_table;
+extern struct ir_scancode_table ir_codes_pinnacle_grey_table;
+extern struct ir_scancode_table ir_codes_flyvideo_table;
+extern struct ir_scancode_table ir_codes_flydvb_table;
+extern struct ir_scancode_table ir_codes_cinergy_table;
+extern struct ir_scancode_table ir_codes_eztv_table;
+extern struct ir_scancode_table ir_codes_avermedia_table;
+extern struct ir_scancode_table ir_codes_videomate_tv_pvr_table;
+extern struct ir_scancode_table ir_codes_manli_table;
+extern struct ir_scancode_table ir_codes_gotview7135_table;
+extern struct ir_scancode_table ir_codes_purpletv_table;
+extern struct ir_scancode_table ir_codes_pctv_sedna_table;
+extern struct ir_scancode_table ir_codes_pv951_table;
+extern struct ir_scancode_table ir_codes_rc5_tv_table;
+extern struct ir_scancode_table ir_codes_winfast_table;
+extern struct ir_scancode_table ir_codes_pinnacle_color_table;
+extern struct ir_scancode_table ir_codes_hauppauge_new_table;
+extern struct ir_scancode_table ir_codes_npgtech_table;
+extern struct ir_scancode_table ir_codes_norwood_table;
+extern struct ir_scancode_table ir_codes_proteus_2309_table;
+extern struct ir_scancode_table ir_codes_budget_ci_old_table;
+extern struct ir_scancode_table ir_codes_asus_pc39_table;
+extern struct ir_scancode_table ir_codes_encore_enltv_table;
+extern struct ir_scancode_table ir_codes_encore_enltv2_table;
+extern struct ir_scancode_table ir_codes_tt_1500_table;
+extern struct ir_scancode_table ir_codes_fusionhdtv_mce_table;
+extern struct ir_scancode_table ir_codes_behold_table;
+extern struct ir_scancode_table ir_codes_behold_columbus_table;
+extern struct ir_scancode_table ir_codes_pinnacle_pctv_hd_table;
+extern struct ir_scancode_table ir_codes_genius_tvgo_a11mce_table;
+extern struct ir_scancode_table ir_codes_powercolor_real_angel_table;
+extern struct ir_scancode_table ir_codes_avermedia_a16d_table;
+extern struct ir_scancode_table ir_codes_encore_enltv_fm53_table;
+extern struct ir_scancode_table ir_codes_real_audio_220_32_keys_table;
+extern struct ir_scancode_table ir_codes_msi_tvanywhere_plus_table;
+extern struct ir_scancode_table ir_codes_ati_tv_wonder_hd_600_table;
+extern struct ir_scancode_table ir_codes_kworld_plus_tv_analog_table;
+extern struct ir_scancode_table ir_codes_kaiomy_table;
+extern struct ir_scancode_table ir_codes_dm1105_nec_table;
+extern struct ir_scancode_table ir_codes_evga_indtube_table;
+extern struct ir_scancode_table ir_codes_terratec_cinergy_xs_table;
+extern struct ir_scancode_table ir_codes_videomate_s350_table;
+extern struct ir_scancode_table ir_codes_gadmei_rm008z_table;
 #endif
-
-/*
- * Local variables:
- * c-basic-offset: 8
- * End:
- */
index 3ad4ed5402fb8b6782ad6b1600f8dfdfd4394ea1..aaf65e8b1a40a57697eed7f261e8778d1638fe19 100644 (file)
@@ -6,7 +6,8 @@
 struct IR_i2c;
 
 struct IR_i2c {
-       IR_KEYTAB_TYPE         *ir_codes;
+       struct ir_scancode_table *ir_codes;
+
        struct i2c_client      *c;
        struct input_dev       *input;
        struct ir_input_state  ir;
@@ -20,10 +21,27 @@ struct IR_i2c {
        int                    (*get_key)(struct IR_i2c*, u32*, u32*);
 };
 
+enum ir_kbd_get_key_fn {
+       IR_KBD_GET_KEY_CUSTOM = 0,
+       IR_KBD_GET_KEY_PIXELVIEW,
+       IR_KBD_GET_KEY_PV951,
+       IR_KBD_GET_KEY_HAUP,
+       IR_KBD_GET_KEY_KNC1,
+       IR_KBD_GET_KEY_FUSIONHDTV,
+       IR_KBD_GET_KEY_HAUP_XVR,
+       IR_KBD_GET_KEY_AVERMEDIA_CARDBUS,
+};
+
 /* Can be passed when instantiating an ir_video i2c device */
 struct IR_i2c_init_data {
-       IR_KEYTAB_TYPE         *ir_codes;
+       struct ir_scancode_table *ir_codes;
        const char             *name;
+       int                    type; /* IR_TYPE_RC5, IR_TYPE_PD, etc */
+       /*
+        * Specify either a function pointer or a value indicating one of
+        * ir_kbd_i2c's internal get_key functions
+        */
        int                    (*get_key)(struct IR_i2c*, u32*, u32*);
+       enum ir_kbd_get_key_fn internal_get_key_func;
 };
 #endif
diff --git a/include/media/radio-si4713.h b/include/media/radio-si4713.h
new file mode 100644 (file)
index 0000000..f6aae29
--- /dev/null
@@ -0,0 +1,30 @@
+/*
+ * include/media/radio-si4713.h
+ *
+ * Board related data definitions for Si4713 radio transmitter chip.
+ *
+ * Copyright (c) 2009 Nokia Corporation
+ * Contact: Eduardo Valentin <eduardo.valentin@nokia.com>
+ *
+ * This file is licensed under the terms of the GNU General Public License
+ * version 2. This program is licensed "as is" without any warranty of any
+ * kind, whether express or implied.
+ *
+ */
+
+#ifndef RADIO_SI4713_H
+#define RADIO_SI4713_H
+
+#include <linux/i2c.h>
+
+#define SI4713_NAME "radio-si4713"
+
+/*
+ * Platform dependent definition
+ */
+struct radio_si4713_platform_data {
+       int i2c_bus;
+       struct i2c_board_info *subdev_board_info;
+};
+
+#endif /* ifndef RADIO_SI4713_H*/
diff --git a/include/media/si4713.h b/include/media/si4713.h
new file mode 100644 (file)
index 0000000..99850a5
--- /dev/null
@@ -0,0 +1,49 @@
+/*
+ * include/media/si4713.h
+ *
+ * Board related data definitions for Si4713 i2c device driver.
+ *
+ * Copyright (c) 2009 Nokia Corporation
+ * Contact: Eduardo Valentin <eduardo.valentin@nokia.com>
+ *
+ * This file is licensed under the terms of the GNU General Public License
+ * version 2. This program is licensed "as is" without any warranty of any
+ * kind, whether express or implied.
+ *
+ */
+
+#ifndef SI4713_H
+#define SI4713_H
+
+/* The SI4713 I2C sensor chip has a fixed slave address of 0xc6 or 0x22. */
+#define SI4713_I2C_ADDR_BUSEN_HIGH     0x63
+#define SI4713_I2C_ADDR_BUSEN_LOW      0x11
+
+/*
+ * Platform dependent definition
+ */
+struct si4713_platform_data {
+       /* Set power state, zero is off, non-zero is on. */
+       int (*set_power)(int power);
+};
+
+/*
+ * Structure to query for Received Noise Level (RNL).
+ */
+struct si4713_rnl {
+       __u32 index;            /* modulator index */
+       __u32 frequency;        /* frequency to peform rnl measurement */
+       __s32 rnl;              /* result of measurement in dBuV */
+       __u32 reserved[4];      /* drivers and apps must init this to 0 */
+};
+
+/*
+ * This is the ioctl number to query for rnl. Users must pass a
+ * struct si4713_rnl pointer specifying desired frequency in 'frequency' field
+ * following driver capabilities (i.e V4L2_TUNER_CAP_LOW).
+ * Driver must return measured value in the same struture, filling 'rnl' field.
+ */
+#define SI4713_IOC_MEASURE_RNL _IOWR('V', BASE_VIDIOC_PRIVATE + 0, \
+                                               struct si4713_rnl)
+
+#endif /* ifndef SI4713_H*/
index cbf97f45fbec3abd6dde9da35c074de6bc20e36f..c146f2f530b0077ff16b56997c682f7f20944dbc 100644 (file)
 #define TUNER_PHILIPS_FMD1216MEX_MK3   78
 #define TUNER_PHILIPS_FM1216MK5                79
 #define TUNER_PHILIPS_FQ1216LME_MK3    80      /* Active loopthrough, no FM */
+#define TUNER_PARTSNIC_PTI_5NF05       81
 
 /* tv card specific */
 #define TDA9887_PRESENT                (1<<0)
index 5dcb36785529152e266909526ff17f673c11cd18..d411345f244bf13c4ccddfa537eb7607039961ac 100644 (file)
@@ -137,6 +137,8 @@ struct v4l2_subdev_tuner_ops {
        int (*g_frequency)(struct v4l2_subdev *sd, struct v4l2_frequency *freq);
        int (*g_tuner)(struct v4l2_subdev *sd, struct v4l2_tuner *vt);
        int (*s_tuner)(struct v4l2_subdev *sd, struct v4l2_tuner *vt);
+       int (*g_modulator)(struct v4l2_subdev *sd, struct v4l2_modulator *vm);
+       int (*s_modulator)(struct v4l2_subdev *sd, struct v4l2_modulator *vm);
        int (*s_type_addr)(struct v4l2_subdev *sd, struct tuner_setup *type);
        int (*s_config)(struct v4l2_subdev *sd, const struct v4l2_priv_tun_config *config);
        int (*s_standby)(struct v4l2_subdev *sd);
@@ -220,6 +222,9 @@ struct v4l2_subdev_video_ops {
        int (*g_fmt)(struct v4l2_subdev *sd, struct v4l2_format *fmt);
        int (*try_fmt)(struct v4l2_subdev *sd, struct v4l2_format *fmt);
        int (*s_fmt)(struct v4l2_subdev *sd, struct v4l2_format *fmt);
+       int (*cropcap)(struct v4l2_subdev *sd, struct v4l2_cropcap *cc);
+       int (*g_crop)(struct v4l2_subdev *sd, struct v4l2_crop *crop);
+       int (*s_crop)(struct v4l2_subdev *sd, struct v4l2_crop *crop);
        int (*g_parm)(struct v4l2_subdev *sd, struct v4l2_streamparm *param);
        int (*s_parm)(struct v4l2_subdev *sd, struct v4l2_streamparm *param);
        int (*enum_framesizes)(struct v4l2_subdev *sd, struct v4l2_frmsizeenum *fsize);
index 7d8b5bc741857401acf0ee81f8eaa9b98b52c1cd..8d433c4e370982e7095255c20f75eca2efdfc45f 100644 (file)
@@ -227,7 +227,6 @@ TRACE_EVENT(ext4_da_writepages,
                __field(        char,   nonblocking             )
                __field(        char,   for_kupdate             )
                __field(        char,   for_reclaim             )
-               __field(        char,   for_writepages          )
                __field(        char,   range_cyclic            )
        ),
 
@@ -241,16 +240,15 @@ TRACE_EVENT(ext4_da_writepages,
                __entry->nonblocking    = wbc->nonblocking;
                __entry->for_kupdate    = wbc->for_kupdate;
                __entry->for_reclaim    = wbc->for_reclaim;
-               __entry->for_writepages = wbc->for_writepages;
                __entry->range_cyclic   = wbc->range_cyclic;
        ),
 
-       TP_printk("dev %s ino %lu nr_t_write %ld pages_skipped %ld range_start %llu range_end %llu nonblocking %d for_kupdate %d for_reclaim %d for_writepages %d range_cyclic %d",
+       TP_printk("dev %s ino %lu nr_t_write %ld pages_skipped %ld range_start %llu range_end %llu nonblocking %d for_kupdate %d for_reclaim %d range_cyclic %d",
                  jbd2_dev_to_name(__entry->dev), __entry->ino, __entry->nr_to_write,
                  __entry->pages_skipped, __entry->range_start,
                  __entry->range_end, __entry->nonblocking,
                  __entry->for_kupdate, __entry->for_reclaim,
-                 __entry->for_writepages, __entry->range_cyclic)
+                 __entry->range_cyclic)
 );
 
 TRACE_EVENT(ext4_da_writepages_result,
index b34fd8e5edef6b50a9bedeef4dc1ff8625a76394..63904bb6ae37bf30b1e0b59fc266af7a080491cf 100644 (file)
@@ -353,7 +353,6 @@ static void __init smp_init(void)
 #define smp_init()     do { } while (0)
 #endif
 
-static inline void setup_per_cpu_areas(void) { }
 static inline void setup_nr_cpu_ids(void) { }
 static inline void smp_prepare_cpus(unsigned int maxcpus) { }
 
@@ -374,29 +373,6 @@ static void __init setup_nr_cpu_ids(void)
        nr_cpu_ids = find_last_bit(cpumask_bits(cpu_possible_mask),NR_CPUS) + 1;
 }
 
-#ifndef CONFIG_HAVE_SETUP_PER_CPU_AREA
-unsigned long __per_cpu_offset[NR_CPUS] __read_mostly;
-
-EXPORT_SYMBOL(__per_cpu_offset);
-
-static void __init setup_per_cpu_areas(void)
-{
-       unsigned long size, i;
-       char *ptr;
-       unsigned long nr_possible_cpus = num_possible_cpus();
-
-       /* Copy section for each CPU (we discard the original) */
-       size = ALIGN(PERCPU_ENOUGH_ROOM, PAGE_SIZE);
-       ptr = alloc_bootmem_pages(size * nr_possible_cpus);
-
-       for_each_possible_cpu(i) {
-               __per_cpu_offset[i] = ptr - __per_cpu_start;
-               memcpy(ptr, __per_cpu_start, __per_cpu_end - __per_cpu_start);
-               ptr += size;
-       }
-}
-#endif /* CONFIG_HAVE_SETUP_PER_CPU_AREA */
-
 /* Called by boot processor to activate the rest. */
 static void __init smp_init(void)
 {
index 8ce10043e4aca1d9d48ab9f127e6079c8634f9fd..6ba0f1ecb21230de60f6ab9fd7b2f58907b48d55 100644 (file)
@@ -401,6 +401,7 @@ int disable_nonboot_cpus(void)
                        break;
                }
        }
+
        if (!error) {
                BUG_ON(num_online_cpus() > 1);
                /* Make sure the CPUs won't be enabled by someone else */
@@ -413,6 +414,14 @@ int disable_nonboot_cpus(void)
        return error;
 }
 
+void __weak arch_enable_nonboot_cpus_begin(void)
+{
+}
+
+void __weak arch_enable_nonboot_cpus_end(void)
+{
+}
+
 void __ref enable_nonboot_cpus(void)
 {
        int cpu, error;
@@ -424,6 +433,9 @@ void __ref enable_nonboot_cpus(void)
                goto out;
 
        printk("Enabling non-boot CPUs ...\n");
+
+       arch_enable_nonboot_cpus_begin();
+
        for_each_cpu(cpu, frozen_cpus) {
                error = _cpu_up(cpu, 1);
                if (!error) {
@@ -432,6 +444,9 @@ void __ref enable_nonboot_cpus(void)
                }
                printk(KERN_WARNING "Error taking CPU%d up: %d\n", cpu, error);
        }
+
+       arch_enable_nonboot_cpus_end();
+
        cpumask_clear(frozen_cpus);
 out:
        cpu_maps_update_done();
index 22e9dcfaa3d36b3a5d2325d0049a314ff2c7d07d..654efd09f6a97cb6497d18be2d303364539ac7a9 100644 (file)
@@ -34,7 +34,7 @@ config GCOV_KERNEL
 config GCOV_PROFILE_ALL
        bool "Profile entire Kernel"
        depends on GCOV_KERNEL
-       depends on S390 || X86
+       depends on S390 || X86 || (PPC && EXPERIMENTAL)
        default n
        ---help---
        This options activates profiling for the entire kernel.
index 46580edff0cbb14da6603e6a0201d15486775ae4..05ce49ced8f6caa51501941a40d46c0fded63717 100644 (file)
@@ -369,7 +369,7 @@ EXPORT_SYMBOL_GPL(find_module);
 
 #ifdef CONFIG_SMP
 
-#ifdef CONFIG_HAVE_DYNAMIC_PER_CPU_AREA
+#ifndef CONFIG_HAVE_LEGACY_PER_CPU_AREA
 
 static void *percpu_modalloc(unsigned long size, unsigned long align,
                             const char *name)
@@ -394,7 +394,7 @@ static void percpu_modfree(void *freeme)
        free_percpu(freeme);
 }
 
-#else /* ... !CONFIG_HAVE_DYNAMIC_PER_CPU_AREA */
+#else /* ... CONFIG_HAVE_LEGACY_PER_CPU_AREA */
 
 /* Number of blocks used and allocated. */
 static unsigned int pcpu_num_used, pcpu_num_allocated;
@@ -540,7 +540,7 @@ static int percpu_modinit(void)
 }
 __initcall(percpu_modinit);
 
-#endif /* CONFIG_HAVE_DYNAMIC_PER_CPU_AREA */
+#endif /* CONFIG_HAVE_LEGACY_PER_CPU_AREA */
 
 static unsigned int find_pcpusec(Elf_Ehdr *hdr,
                                 Elf_Shdr *sechdrs,
index e0d91fdf0c3cfbb417c6fd94d38f2c5700942815..8cb94a52d1bb3c21154e8dd028eecc93e1588866 100644 (file)
@@ -106,16 +106,16 @@ hw_perf_group_sched_in(struct perf_counter *group_leader,
 
 void __weak perf_counter_print_debug(void)     { }
 
-static DEFINE_PER_CPU(int, disable_count);
+static DEFINE_PER_CPU(int, perf_disable_count);
 
 void __perf_disable(void)
 {
-       __get_cpu_var(disable_count)++;
+       __get_cpu_var(perf_disable_count)++;
 }
 
 bool __perf_enable(void)
 {
-       return !--__get_cpu_var(disable_count);
+       return !--__get_cpu_var(perf_disable_count);
 }
 
 void perf_disable(void)
@@ -4215,6 +4215,7 @@ static int perf_copy_attr(struct perf_counter_attr __user *uattr,
                        if (val)
                                goto err_size;
                }
+               size = sizeof(*attr);
        }
 
        ret = copy_from_user(attr, uattr, size);
index e27a53685ed9cb4a24d9e1b58650a32161e0a0ea..d9db3fb17573b8aaf8449ade1d168eb20f9ba4f6 100644 (file)
@@ -295,12 +295,12 @@ struct task_group root_task_group;
 /* Default task group's sched entity on each cpu */
 static DEFINE_PER_CPU(struct sched_entity, init_sched_entity);
 /* Default task group's cfs_rq on each cpu */
-static DEFINE_PER_CPU(struct cfs_rq, init_tg_cfs_rq) ____cacheline_aligned_in_smp;
+static DEFINE_PER_CPU_SHARED_ALIGNED(struct cfs_rq, init_tg_cfs_rq);
 #endif /* CONFIG_FAIR_GROUP_SCHED */
 
 #ifdef CONFIG_RT_GROUP_SCHED
 static DEFINE_PER_CPU(struct sched_rt_entity, init_sched_rt_entity);
-static DEFINE_PER_CPU(struct rt_rq, init_rt_rq) ____cacheline_aligned_in_smp;
+static DEFINE_PER_CPU_SHARED_ALIGNED(struct rt_rq, init_rt_rq);
 #endif /* CONFIG_RT_GROUP_SCHED */
 #else /* !CONFIG_USER_SCHED */
 #define root_task_group init_task_group
index 94188b8ecc33ea2bc7a232cd0ca362aa15f753fb..8e218500ab14b7ff0a91810b5bc34abbd64e2a7b 100644 (file)
@@ -176,6 +176,11 @@ void generic_smp_call_function_interrupt(void)
        struct call_function_data *data;
        int cpu = get_cpu();
 
+       /*
+        * Shouldn't receive this interrupt on a cpu that is not yet online.
+        */
+       WARN_ON_ONCE(!cpu_online(cpu));
+
        /*
         * Ensure entry is visible on call_function_queue after we have
         * entered the IPI. See comment in smp_call_function_many.
@@ -230,6 +235,11 @@ void generic_smp_call_function_single_interrupt(void)
        unsigned int data_flags;
        LIST_HEAD(list);
 
+       /*
+        * Shouldn't receive this interrupt on a cpu that is not yet online.
+        */
+       WARN_ON_ONCE(!cpu_online(smp_processor_id()));
+
        spin_lock(&q->lock);
        list_replace_init(&q->list, &list);
        spin_unlock(&q->lock);
@@ -285,8 +295,14 @@ int smp_call_function_single(int cpu, void (*func) (void *info), void *info,
         */
        this_cpu = get_cpu();
 
-       /* Can deadlock when called with interrupts disabled */
-       WARN_ON_ONCE(irqs_disabled() && !oops_in_progress);
+       /*
+        * Can deadlock when called with interrupts disabled.
+        * We allow cpu's that are not yet online though, as no one else can
+        * send smp call function interrupt to this cpu and as such deadlocks
+        * can't happen.
+        */
+       WARN_ON_ONCE(cpu_online(this_cpu) && irqs_disabled()
+                    && !oops_in_progress);
 
        if (cpu == this_cpu) {
                local_irq_save(flags);
@@ -329,8 +345,14 @@ void __smp_call_function_single(int cpu, struct call_single_data *data,
 {
        csd_lock(data);
 
-       /* Can deadlock when called with interrupts disabled */
-       WARN_ON_ONCE(wait && irqs_disabled() && !oops_in_progress);
+       /*
+        * Can deadlock when called with interrupts disabled.
+        * We allow cpu's that are not yet online though, as no one else can
+        * send smp call function interrupt to this cpu and as such deadlocks
+        * can't happen.
+        */
+       WARN_ON_ONCE(cpu_online(smp_processor_id()) && wait && irqs_disabled()
+                    && !oops_in_progress);
 
        generic_exec_single(cpu, data, wait);
 }
@@ -365,8 +387,14 @@ void smp_call_function_many(const struct cpumask *mask,
        unsigned long flags;
        int cpu, next_cpu, this_cpu = smp_processor_id();
 
-       /* Can deadlock when called with interrupts disabled */
-       WARN_ON_ONCE(irqs_disabled() && !oops_in_progress);
+       /*
+        * Can deadlock when called with interrupts disabled.
+        * We allow cpu's that are not yet online though, as no one else can
+        * send smp call function interrupt to this cpu and as such deadlocks
+        * can't happen.
+        */
+       WARN_ON_ONCE(cpu_online(this_cpu) && irqs_disabled()
+                    && !oops_in_progress);
 
        /* So, what's a CPU they want? Ignoring this one. */
        cpu = cpumask_first_and(mask, cpu_online_mask);
index 78b1ed230177246349d10ba83615b99f3adcbde3..97e2c4d2e9ebdfeed72e8518a34e0e25f6b045d4 100644 (file)
@@ -1432,7 +1432,7 @@ static __init void event_trace_self_tests(void)
 
 #ifdef CONFIG_FUNCTION_TRACER
 
-static DEFINE_PER_CPU(atomic_t, test_event_disable);
+static DEFINE_PER_CPU(atomic_t, ftrace_test_event_disable);
 
 static void
 function_test_events_call(unsigned long ip, unsigned long parent_ip)
@@ -1449,7 +1449,7 @@ function_test_events_call(unsigned long ip, unsigned long parent_ip)
        pc = preempt_count();
        resched = ftrace_preempt_disable();
        cpu = raw_smp_processor_id();
-       disabled = atomic_inc_return(&per_cpu(test_event_disable, cpu));
+       disabled = atomic_inc_return(&per_cpu(ftrace_test_event_disable, cpu));
 
        if (disabled != 1)
                goto out;
@@ -1468,7 +1468,7 @@ function_test_events_call(unsigned long ip, unsigned long parent_ip)
        trace_nowake_buffer_unlock_commit(buffer, event, flags, pc);
 
  out:
-       atomic_dec(&per_cpu(test_event_disable, cpu));
+       atomic_dec(&per_cpu(ftrace_test_event_disable, cpu));
        ftrace_preempt_enable(resched);
 }
 
index 7dbd5d9c29a46cf7c9b9d3db1497e3b878711018..d57b12f59c8c3f0686eca5cbd416e5378177da8b 100644 (file)
@@ -338,7 +338,7 @@ config SLUB_STATS
 
 config DEBUG_KMEMLEAK
        bool "Kernel memory leak detector"
-       depends on DEBUG_KERNEL && EXPERIMENTAL && (X86 || ARM) && \
+       depends on DEBUG_KERNEL && EXPERIMENTAL && (X86 || ARM || PPC) && \
                !MEMORY_HOTPLUG
        select DEBUG_FS if SYSFS
        select STACKTRACE if STACKTRACE_SUPPORT
@@ -805,6 +805,21 @@ config DEBUG_BLOCK_EXT_DEVT
 
          Say N if you are unsure.
 
+config DEBUG_FORCE_WEAK_PER_CPU
+       bool "Force weak per-cpu definitions"
+       depends on DEBUG_KERNEL
+       help
+         s390 and alpha require percpu variables in modules to be
+         defined weak to work around addressing range issue which
+         puts the following two restrictions on percpu variable
+         definitions.
+
+         1. percpu symbols must be unique whether static or not
+         2. percpu variables can't be defined inside a function
+
+         To ensure that generic code follows the above rules, this
+         option forces all percpu variables to be defined as weak.
+
 config LKDTM
        tristate "Linux Kernel Dump Test Tool Module"
        depends on DEBUG_KERNEL
index 1a8e8a97812817f12460dbc880ce8fd4c53cf1cf..d10255973a9fc8b79df675c684a6532da26694a8 100644 (file)
@@ -7,7 +7,7 @@
  * Adapted for booting Linux by Hannu Savolainen 1993
  * based on gzip-1.0.3 
  *
- * Nicolas Pitre <nico@cam.org>, 1999/04/14 :
+ * Nicolas Pitre <nico@fluxnic.net>, 1999/04/14 :
  *   Little mods for all variable to reside either into rodata or bss segments
  *   by marking constant variables with 'const' and initializing all the others
  *   at run-time only.  This allows for the kernel uncompressor to run
index fe5f674d7a7d571a1f456d2df3d5a31bb965db2e..3aa519f52e18141e48cdf18db2c76e708df13dae 100644 (file)
@@ -153,7 +153,7 @@ config MEMORY_HOTREMOVE
 #
 config PAGEFLAGS_EXTENDED
        def_bool y
-       depends on 64BIT || SPARSEMEM_VMEMMAP || !NUMA || !SPARSEMEM
+       depends on 64BIT || SPARSEMEM_VMEMMAP || !SPARSEMEM
 
 # Heavily threaded applications may benefit from splitting the mm-wide
 # page_table_lock, so that faults on different parts of the user address
index 147a7a7873c49e3314fcf2cb411c2dbe50a4f7ca..ea4b18bd396080acf19beb1cfcada5b3aa4fcc25 100644 (file)
@@ -33,7 +33,7 @@ obj-$(CONFIG_FAILSLAB) += failslab.o
 obj-$(CONFIG_MEMORY_HOTPLUG) += memory_hotplug.o
 obj-$(CONFIG_FS_XIP) += filemap_xip.o
 obj-$(CONFIG_MIGRATION) += migrate.o
-ifdef CONFIG_HAVE_DYNAMIC_PER_CPU_AREA
+ifndef CONFIG_HAVE_LEGACY_PER_CPU_AREA
 obj-$(CONFIG_SMP) += percpu.o
 else
 obj-$(CONFIG_SMP) += allocpercpu.o
index dfdee6a47359eb9f529733091b6553091a80eebc..df34ceae0c678569446930eaf5ceb982a496f8b9 100644 (file)
@@ -5,6 +5,8 @@
  */
 #include <linux/mm.h>
 #include <linux/module.h>
+#include <linux/bootmem.h>
+#include <asm/sections.h>
 
 #ifndef cache_line_size
 #define cache_line_size()      L1_CACHE_BYTES
@@ -147,3 +149,29 @@ void free_percpu(void *__pdata)
        kfree(__percpu_disguise(__pdata));
 }
 EXPORT_SYMBOL_GPL(free_percpu);
+
+/*
+ * Generic percpu area setup.
+ */
+#ifndef CONFIG_HAVE_SETUP_PER_CPU_AREA
+unsigned long __per_cpu_offset[NR_CPUS] __read_mostly;
+
+EXPORT_SYMBOL(__per_cpu_offset);
+
+void __init setup_per_cpu_areas(void)
+{
+       unsigned long size, i;
+       char *ptr;
+       unsigned long nr_possible_cpus = num_possible_cpus();
+
+       /* Copy section for each CPU (we discard the original) */
+       size = ALIGN(PERCPU_ENOUGH_ROOM, PAGE_SIZE);
+       ptr = alloc_bootmem_pages(size * nr_possible_cpus);
+
+       for_each_possible_cpu(i) {
+               __per_cpu_offset[i] = ptr - __per_cpu_start;
+               memcpy(ptr, __per_cpu_start, __per_cpu_end - __per_cpu_start);
+               ptr += size;
+       }
+}
+#endif /* CONFIG_HAVE_SETUP_PER_CPU_AREA */
index d3ca0dac1111ed4f22cba933acf535a85f43b3aa..3d3accb1f8001dc58ade1436df6295415eda00c6 100644 (file)
@@ -26,6 +26,12 @@ struct backing_dev_info default_backing_dev_info = {
 EXPORT_SYMBOL_GPL(default_backing_dev_info);
 
 static struct class *bdi_class;
+
+/*
+ * bdi_lock protects updates to bdi_list and bdi_pending_list, as well as
+ * reader side protection for bdi_pending_list. bdi_list has RCU reader side
+ * locking.
+ */
 DEFINE_SPINLOCK(bdi_lock);
 LIST_HEAD(bdi_list);
 LIST_HEAD(bdi_pending_list);
@@ -284,9 +290,9 @@ static int bdi_start_fn(void *ptr)
        /*
         * Add us to the active bdi_list
         */
-       spin_lock(&bdi_lock);
-       list_add(&bdi->bdi_list, &bdi_list);
-       spin_unlock(&bdi_lock);
+       spin_lock_bh(&bdi_lock);
+       list_add_rcu(&bdi->bdi_list, &bdi_list);
+       spin_unlock_bh(&bdi_lock);
 
        bdi_task_init(bdi, wb);
 
@@ -389,7 +395,7 @@ static int bdi_forker_task(void *ptr)
                if (wb_has_dirty_io(me) || !list_empty(&me->bdi->work_list))
                        wb_do_writeback(me, 0);
 
-               spin_lock(&bdi_lock);
+               spin_lock_bh(&bdi_lock);
 
                /*
                 * Check if any existing bdi's have dirty data without
@@ -410,7 +416,7 @@ static int bdi_forker_task(void *ptr)
                if (list_empty(&bdi_pending_list)) {
                        unsigned long wait;
 
-                       spin_unlock(&bdi_lock);
+                       spin_unlock_bh(&bdi_lock);
                        wait = msecs_to_jiffies(dirty_writeback_interval * 10);
                        schedule_timeout(wait);
                        try_to_freeze();
@@ -426,7 +432,7 @@ static int bdi_forker_task(void *ptr)
                bdi = list_entry(bdi_pending_list.next, struct backing_dev_info,
                                 bdi_list);
                list_del_init(&bdi->bdi_list);
-               spin_unlock(&bdi_lock);
+               spin_unlock_bh(&bdi_lock);
 
                wb = &bdi->wb;
                wb->task = kthread_run(bdi_start_fn, wb, "flush-%s",
@@ -445,9 +451,9 @@ static int bdi_forker_task(void *ptr)
                         * a chance to flush other bdi's to free
                         * memory.
                         */
-                       spin_lock(&bdi_lock);
+                       spin_lock_bh(&bdi_lock);
                        list_add_tail(&bdi->bdi_list, &bdi_pending_list);
-                       spin_unlock(&bdi_lock);
+                       spin_unlock_bh(&bdi_lock);
 
                        bdi_flush_io(bdi);
                }
@@ -456,6 +462,24 @@ static int bdi_forker_task(void *ptr)
        return 0;
 }
 
+static void bdi_add_to_pending(struct rcu_head *head)
+{
+       struct backing_dev_info *bdi;
+
+       bdi = container_of(head, struct backing_dev_info, rcu_head);
+       INIT_LIST_HEAD(&bdi->bdi_list);
+
+       spin_lock(&bdi_lock);
+       list_add_tail(&bdi->bdi_list, &bdi_pending_list);
+       spin_unlock(&bdi_lock);
+
+       /*
+        * We are now on the pending list, wake up bdi_forker_task()
+        * to finish the job and add us back to the active bdi_list
+        */
+       wake_up_process(default_backing_dev_info.wb.task);
+}
+
 /*
  * Add the default flusher task that gets created for any bdi
  * that has dirty data pending writeout
@@ -478,16 +502,29 @@ void static bdi_add_default_flusher_task(struct backing_dev_info *bdi)
         * waiting for previous additions to finish.
         */
        if (!test_and_set_bit(BDI_pending, &bdi->state)) {
-               list_move_tail(&bdi->bdi_list, &bdi_pending_list);
+               list_del_rcu(&bdi->bdi_list);
 
                /*
-                * We are now on the pending list, wake up bdi_forker_task()
-                * to finish the job and add us back to the active bdi_list
+                * We must wait for the current RCU period to end before
+                * moving to the pending list. So schedule that operation
+                * from an RCU callback.
                 */
-               wake_up_process(default_backing_dev_info.wb.task);
+               call_rcu(&bdi->rcu_head, bdi_add_to_pending);
        }
 }
 
+/*
+ * Remove bdi from bdi_list, and ensure that it is no longer visible
+ */
+static void bdi_remove_from_list(struct backing_dev_info *bdi)
+{
+       spin_lock_bh(&bdi_lock);
+       list_del_rcu(&bdi->bdi_list);
+       spin_unlock_bh(&bdi_lock);
+
+       synchronize_rcu();
+}
+
 int bdi_register(struct backing_dev_info *bdi, struct device *parent,
                const char *fmt, ...)
 {
@@ -506,9 +543,9 @@ int bdi_register(struct backing_dev_info *bdi, struct device *parent,
                goto exit;
        }
 
-       spin_lock(&bdi_lock);
-       list_add_tail(&bdi->bdi_list, &bdi_list);
-       spin_unlock(&bdi_lock);
+       spin_lock_bh(&bdi_lock);
+       list_add_tail_rcu(&bdi->bdi_list, &bdi_list);
+       spin_unlock_bh(&bdi_lock);
 
        bdi->dev = dev;
 
@@ -526,9 +563,7 @@ int bdi_register(struct backing_dev_info *bdi, struct device *parent,
                        wb->task = NULL;
                        ret = -ENOMEM;
 
-                       spin_lock(&bdi_lock);
-                       list_del(&bdi->bdi_list);
-                       spin_unlock(&bdi_lock);
+                       bdi_remove_from_list(bdi);
                        goto exit;
                }
        }
@@ -565,9 +600,7 @@ static void bdi_wb_shutdown(struct backing_dev_info *bdi)
        /*
         * Make sure nobody finds us on the bdi_list anymore
         */
-       spin_lock(&bdi_lock);
-       list_del(&bdi->bdi_list);
-       spin_unlock(&bdi_lock);
+       bdi_remove_from_list(bdi);
 
        /*
         * Finally, kill the kernel threads. We don't need to be RCU
@@ -599,6 +632,7 @@ int bdi_init(struct backing_dev_info *bdi)
        bdi->max_ratio = 100;
        bdi->max_prop_frac = PROP_FRAC_BASE;
        spin_lock_init(&bdi->wb_lock);
+       INIT_RCU_HEAD(&bdi->rcu_head);
        INIT_LIST_HEAD(&bdi->bdi_list);
        INIT_LIST_HEAD(&bdi->wb_list);
        INIT_LIST_HEAD(&bdi->work_list);
@@ -634,7 +668,19 @@ void bdi_destroy(struct backing_dev_info *bdi)
 {
        int i;
 
-       WARN_ON(bdi_has_dirty_io(bdi));
+       /*
+        * Splice our entries to the default_backing_dev_info, if this
+        * bdi disappears
+        */
+       if (bdi_has_dirty_io(bdi)) {
+               struct bdi_writeback *dst = &default_backing_dev_info.wb;
+
+               spin_lock(&inode_lock);
+               list_splice(&bdi->wb.b_dirty, &dst->b_dirty);
+               list_splice(&bdi->wb.b_io, &dst->b_io);
+               list_splice(&bdi->wb.b_more_io, &dst->b_more_io);
+               spin_unlock(&inode_lock);
+       }
 
        bdi_unregister(bdi);
 
index d5292fc6f52385f61343f4fcda8288b0c0e6a2c3..177a5169bbde178323974f027940957a9b4fa4a9 100644 (file)
@@ -36,7 +36,7 @@ struct test_node {
 };
 
 static LIST_HEAD(test_list);
-static DEFINE_PER_CPU(void *, test_pointer);
+static DEFINE_PER_CPU(void *, kmemleak_test_pointer);
 
 /*
  * Some very simple testing. This function needs to be extended for
@@ -86,9 +86,9 @@ static int __init kmemleak_test_init(void)
        }
 
        for_each_possible_cpu(i) {
-               per_cpu(test_pointer, i) = kmalloc(129, GFP_KERNEL);
+               per_cpu(kmemleak_test_pointer, i) = kmalloc(129, GFP_KERNEL);
                pr_info("kmemleak: kmalloc(129) = %p\n",
-                       per_cpu(test_pointer, i));
+                       per_cpu(kmemleak_test_pointer, i));
        }
 
        return 0;
index 25e7770309b871e42dbaf7ccedf0132b265eacc2..1eea4fa0d410d59603d283d3c3cbf86bbf25d19d 100644 (file)
@@ -315,7 +315,7 @@ int bdi_set_min_ratio(struct backing_dev_info *bdi, unsigned int min_ratio)
 {
        int ret = 0;
 
-       spin_lock(&bdi_lock);
+       spin_lock_bh(&bdi_lock);
        if (min_ratio > bdi->max_ratio) {
                ret = -EINVAL;
        } else {
@@ -327,7 +327,7 @@ int bdi_set_min_ratio(struct backing_dev_info *bdi, unsigned int min_ratio)
                        ret = -EINVAL;
                }
        }
-       spin_unlock(&bdi_lock);
+       spin_unlock_bh(&bdi_lock);
 
        return ret;
 }
@@ -339,14 +339,14 @@ int bdi_set_max_ratio(struct backing_dev_info *bdi, unsigned max_ratio)
        if (max_ratio > 100)
                return -EINVAL;
 
-       spin_lock(&bdi_lock);
+       spin_lock_bh(&bdi_lock);
        if (bdi->min_ratio > max_ratio) {
                ret = -EINVAL;
        } else {
                bdi->max_ratio = max_ratio;
                bdi->max_prop_frac = (PROP_FRAC_BASE * max_ratio) / 100;
        }
-       spin_unlock(&bdi_lock);
+       spin_unlock_bh(&bdi_lock);
 
        return ret;
 }
@@ -582,16 +582,8 @@ static void balance_dirty_pages(struct address_space *mapping)
        if ((laptop_mode && pages_written) ||
            (!laptop_mode && ((nr_writeback = global_page_state(NR_FILE_DIRTY)
                                          + global_page_state(NR_UNSTABLE_NFS))
-                                         > background_thresh))) {
-               struct writeback_control wbc = {
-                       .bdi            = bdi,
-                       .sync_mode      = WB_SYNC_NONE,
-                       .nr_to_write    = nr_writeback,
-               };
-
-
-               bdi_start_writeback(&wbc);
-       }
+                                         > background_thresh)))
+               bdi_start_writeback(bdi, nr_writeback);
 }
 
 void set_page_dirty_balance(struct page *page, int page_mkwrite)
@@ -604,6 +596,8 @@ void set_page_dirty_balance(struct page *page, int page_mkwrite)
        }
 }
 
+static DEFINE_PER_CPU(unsigned long, bdp_ratelimits) = 0;
+
 /**
  * balance_dirty_pages_ratelimited_nr - balance dirty memory state
  * @mapping: address_space which was dirtied
@@ -621,7 +615,6 @@ void set_page_dirty_balance(struct page *page, int page_mkwrite)
 void balance_dirty_pages_ratelimited_nr(struct address_space *mapping,
                                        unsigned long nr_pages_dirtied)
 {
-       static DEFINE_PER_CPU(unsigned long, ratelimits) = 0;
        unsigned long ratelimit;
        unsigned long *p;
 
@@ -634,7 +627,7 @@ void balance_dirty_pages_ratelimited_nr(struct address_space *mapping,
         * tasks in balance_dirty_pages(). Period.
         */
        preempt_disable();
-       p =  &__get_cpu_var(ratelimits);
+       p =  &__get_cpu_var(bdp_ratelimits);
        *p += nr_pages_dirtied;
        if (unlikely(*p >= ratelimit)) {
                *p = 0;
@@ -1019,12 +1012,10 @@ int do_writepages(struct address_space *mapping, struct writeback_control *wbc)
 
        if (wbc->nr_to_write <= 0)
                return 0;
-       wbc->for_writepages = 1;
        if (mapping->a_ops->writepages)
                ret = mapping->a_ops->writepages(mapping, wbc);
        else
                ret = generic_writepages(mapping, wbc);
-       wbc->for_writepages = 0;
        return ret;
 }
 
index 3311c8919f375fa062faad78b2439176f436301a..43d8cacfdaa5e4f0e1e3ba0b5e8275570e948292 100644 (file)
@@ -8,12 +8,13 @@
  *
  * This is percpu allocator which can handle both static and dynamic
  * areas.  Percpu areas are allocated in chunks in vmalloc area.  Each
- * chunk is consisted of nr_cpu_ids units and the first chunk is used
- * for static percpu variables in the kernel image (special boot time
- * alloc/init handling necessary as these areas need to be brought up
- * before allocation services are running).  Unit grows as necessary
- * and all units grow or shrink in unison.  When a chunk is filled up,
- * another chunk is allocated.  ie. in vmalloc area
+ * chunk is consisted of boot-time determined number of units and the
+ * first chunk is used for static percpu variables in the kernel image
+ * (special boot time alloc/init handling necessary as these areas
+ * need to be brought up before allocation services are running).
+ * Unit grows as necessary and all units grow or shrink in unison.
+ * When a chunk is filled up, another chunk is allocated.  ie. in
+ * vmalloc area
  *
  *  c0                           c1                         c2
  *  -------------------          -------------------        ------------
  *
  * Allocation is done in offset-size areas of single unit space.  Ie,
  * an area of 512 bytes at 6k in c1 occupies 512 bytes at 6k of c1:u0,
- * c1:u1, c1:u2 and c1:u3.  Percpu access can be done by configuring
- * percpu base registers pcpu_unit_size apart.
+ * c1:u1, c1:u2 and c1:u3.  On UMA, units corresponds directly to
+ * cpus.  On NUMA, the mapping can be non-linear and even sparse.
+ * Percpu access can be done by configuring percpu base registers
+ * according to cpu to unit mapping and pcpu_unit_size.
  *
- * There are usually many small percpu allocations many of them as
- * small as 4 bytes.  The allocator organizes chunks into lists
+ * There are usually many small percpu allocations many of them being
+ * as small as 4 bytes.  The allocator organizes chunks into lists
  * according to free size and tries to allocate from the fullest one.
  * Each chunk keeps the maximum contiguous area size hint which is
  * guaranteed to be eqaul to or larger than the maximum contiguous
@@ -43,7 +46,7 @@
  *
  * To use this allocator, arch code should do the followings.
  *
- * - define CONFIG_HAVE_DYNAMIC_PER_CPU_AREA
+ * - drop CONFIG_HAVE_LEGACY_PER_CPU_AREA
  *
  * - define __addr_to_pcpu_ptr() and __pcpu_ptr_to_addr() to translate
  *   regular address to percpu pointer and back if they need to be
@@ -55,7 +58,9 @@
 
 #include <linux/bitmap.h>
 #include <linux/bootmem.h>
+#include <linux/err.h>
 #include <linux/list.h>
+#include <linux/log2.h>
 #include <linux/mm.h>
 #include <linux/module.h>
 #include <linux/mutex.h>
@@ -89,25 +94,38 @@ struct pcpu_chunk {
        struct list_head        list;           /* linked to pcpu_slot lists */
        int                     free_size;      /* free bytes in the chunk */
        int                     contig_hint;    /* max contiguous size hint */
-       struct vm_struct        *vm;            /* mapped vmalloc region */
+       void                    *base_addr;     /* base address of this chunk */
        int                     map_used;       /* # of map entries used */
        int                     map_alloc;      /* # of map entries allocated */
        int                     *map;           /* allocation map */
+       struct vm_struct        **vms;          /* mapped vmalloc regions */
        bool                    immutable;      /* no [de]population allowed */
-       struct page             **page;         /* points to page array */
-       struct page             *page_ar[];     /* #cpus * UNIT_PAGES */
+       unsigned long           populated[];    /* populated bitmap */
 };
 
 static int pcpu_unit_pages __read_mostly;
 static int pcpu_unit_size __read_mostly;
-static int pcpu_chunk_size __read_mostly;
+static int pcpu_nr_units __read_mostly;
+static int pcpu_atom_size __read_mostly;
 static int pcpu_nr_slots __read_mostly;
 static size_t pcpu_chunk_struct_size __read_mostly;
 
+/* cpus with the lowest and highest unit numbers */
+static unsigned int pcpu_first_unit_cpu __read_mostly;
+static unsigned int pcpu_last_unit_cpu __read_mostly;
+
 /* the address of the first chunk which starts with the kernel static area */
 void *pcpu_base_addr __read_mostly;
 EXPORT_SYMBOL_GPL(pcpu_base_addr);
 
+static const int *pcpu_unit_map __read_mostly;         /* cpu -> unit */
+const unsigned long *pcpu_unit_offsets __read_mostly;  /* cpu -> unit offset */
+
+/* group information, used for vm allocation */
+static int pcpu_nr_groups __read_mostly;
+static const unsigned long *pcpu_group_offsets __read_mostly;
+static const size_t *pcpu_group_sizes __read_mostly;
+
 /*
  * The first chunk which always exists.  Note that unlike other
  * chunks, this one can be allocated and mapped in several different
@@ -129,9 +147,9 @@ static int pcpu_reserved_chunk_limit;
  * Synchronization rules.
  *
  * There are two locks - pcpu_alloc_mutex and pcpu_lock.  The former
- * protects allocation/reclaim paths, chunks and chunk->page arrays.
- * The latter is a spinlock and protects the index data structures -
- * chunk slots, chunks and area maps in chunks.
+ * protects allocation/reclaim paths, chunks, populated bitmap and
+ * vmalloc mapping.  The latter is a spinlock and protects the index
+ * data structures - chunk slots, chunks and area maps in chunks.
  *
  * During allocation, pcpu_alloc_mutex is kept locked all the time and
  * pcpu_lock is grabbed and released as necessary.  All actual memory
@@ -178,31 +196,23 @@ static int pcpu_chunk_slot(const struct pcpu_chunk *chunk)
 
 static int pcpu_page_idx(unsigned int cpu, int page_idx)
 {
-       return cpu * pcpu_unit_pages + page_idx;
-}
-
-static struct page **pcpu_chunk_pagep(struct pcpu_chunk *chunk,
-                                     unsigned int cpu, int page_idx)
-{
-       return &chunk->page[pcpu_page_idx(cpu, page_idx)];
+       return pcpu_unit_map[cpu] * pcpu_unit_pages + page_idx;
 }
 
 static unsigned long pcpu_chunk_addr(struct pcpu_chunk *chunk,
                                     unsigned int cpu, int page_idx)
 {
-       return (unsigned long)chunk->vm->addr +
-               (pcpu_page_idx(cpu, page_idx) << PAGE_SHIFT);
+       return (unsigned long)chunk->base_addr + pcpu_unit_offsets[cpu] +
+               (page_idx << PAGE_SHIFT);
 }
 
-static bool pcpu_chunk_page_occupied(struct pcpu_chunk *chunk,
-                                    int page_idx)
+static struct page *pcpu_chunk_page(struct pcpu_chunk *chunk,
+                                   unsigned int cpu, int page_idx)
 {
-       /*
-        * Any possible cpu id can be used here, so there's no need to
-        * worry about preemption or cpu hotplug.
-        */
-       return *pcpu_chunk_pagep(chunk, raw_smp_processor_id(),
-                                page_idx) != NULL;
+       /* must not be used on pre-mapped chunk */
+       WARN_ON(chunk->immutable);
+
+       return vmalloc_to_page((void *)pcpu_chunk_addr(chunk, cpu, page_idx));
 }
 
 /* set the pointer to a chunk in a page struct */
@@ -217,6 +227,34 @@ static struct pcpu_chunk *pcpu_get_page_chunk(struct page *page)
        return (struct pcpu_chunk *)page->index;
 }
 
+static void pcpu_next_unpop(struct pcpu_chunk *chunk, int *rs, int *re, int end)
+{
+       *rs = find_next_zero_bit(chunk->populated, end, *rs);
+       *re = find_next_bit(chunk->populated, end, *rs + 1);
+}
+
+static void pcpu_next_pop(struct pcpu_chunk *chunk, int *rs, int *re, int end)
+{
+       *rs = find_next_bit(chunk->populated, end, *rs);
+       *re = find_next_zero_bit(chunk->populated, end, *rs + 1);
+}
+
+/*
+ * (Un)populated page region iterators.  Iterate over (un)populated
+ * page regions betwen @start and @end in @chunk.  @rs and @re should
+ * be integer variables and will be set to start and end page index of
+ * the current region.
+ */
+#define pcpu_for_each_unpop_region(chunk, rs, re, start, end)              \
+       for ((rs) = (start), pcpu_next_unpop((chunk), &(rs), &(re), (end)); \
+            (rs) < (re);                                                   \
+            (rs) = (re) + 1, pcpu_next_unpop((chunk), &(rs), &(re), (end)))
+
+#define pcpu_for_each_pop_region(chunk, rs, re, start, end)                \
+       for ((rs) = (start), pcpu_next_pop((chunk), &(rs), &(re), (end));   \
+            (rs) < (re);                                                   \
+            (rs) = (re) + 1, pcpu_next_pop((chunk), &(rs), &(re), (end)))
+
 /**
  * pcpu_mem_alloc - allocate memory
  * @size: bytes to allocate
@@ -292,10 +330,10 @@ static void pcpu_chunk_relocate(struct pcpu_chunk *chunk, int oslot)
  */
 static struct pcpu_chunk *pcpu_chunk_addr_search(void *addr)
 {
-       void *first_start = pcpu_first_chunk->vm->addr;
+       void *first_start = pcpu_first_chunk->base_addr;
 
        /* is it in the first chunk? */
-       if (addr >= first_start && addr < first_start + pcpu_chunk_size) {
+       if (addr >= first_start && addr < first_start + pcpu_unit_size) {
                /* is it in the reserved area? */
                if (addr < first_start + pcpu_reserved_chunk_limit)
                        return pcpu_reserved_chunk;
@@ -309,7 +347,7 @@ static struct pcpu_chunk *pcpu_chunk_addr_search(void *addr)
         * space.  Note that any possible cpu id can be used here, so
         * there's no need to worry about preemption or cpu hotplug.
         */
-       addr += raw_smp_processor_id() * pcpu_unit_size;
+       addr += pcpu_unit_offsets[raw_smp_processor_id()];
        return pcpu_get_page_chunk(vmalloc_to_page(addr));
 }
 
@@ -558,125 +596,327 @@ static void pcpu_free_area(struct pcpu_chunk *chunk, int freeme)
 }
 
 /**
- * pcpu_unmap - unmap pages out of a pcpu_chunk
+ * pcpu_get_pages_and_bitmap - get temp pages array and bitmap
  * @chunk: chunk of interest
- * @page_start: page index of the first page to unmap
- * @page_end: page index of the last page to unmap + 1
- * @flush_tlb: whether to flush tlb or not
+ * @bitmapp: output parameter for bitmap
+ * @may_alloc: may allocate the array
  *
- * For each cpu, unmap pages [@page_start,@page_end) out of @chunk.
- * If @flush is true, vcache is flushed before unmapping and tlb
- * after.
+ * Returns pointer to array of pointers to struct page and bitmap,
+ * both of which can be indexed with pcpu_page_idx().  The returned
+ * array is cleared to zero and *@bitmapp is copied from
+ * @chunk->populated.  Note that there is only one array and bitmap
+ * and access exclusion is the caller's responsibility.
+ *
+ * CONTEXT:
+ * pcpu_alloc_mutex and does GFP_KERNEL allocation if @may_alloc.
+ * Otherwise, don't care.
+ *
+ * RETURNS:
+ * Pointer to temp pages array on success, NULL on failure.
  */
-static void pcpu_unmap(struct pcpu_chunk *chunk, int page_start, int page_end,
-                      bool flush_tlb)
+static struct page **pcpu_get_pages_and_bitmap(struct pcpu_chunk *chunk,
+                                              unsigned long **bitmapp,
+                                              bool may_alloc)
 {
-       unsigned int last = nr_cpu_ids - 1;
-       unsigned int cpu;
+       static struct page **pages;
+       static unsigned long *bitmap;
+       size_t pages_size = pcpu_nr_units * pcpu_unit_pages * sizeof(pages[0]);
+       size_t bitmap_size = BITS_TO_LONGS(pcpu_unit_pages) *
+                            sizeof(unsigned long);
+
+       if (!pages || !bitmap) {
+               if (may_alloc && !pages)
+                       pages = pcpu_mem_alloc(pages_size);
+               if (may_alloc && !bitmap)
+                       bitmap = pcpu_mem_alloc(bitmap_size);
+               if (!pages || !bitmap)
+                       return NULL;
+       }
 
-       /* unmap must not be done on immutable chunk */
-       WARN_ON(chunk->immutable);
+       memset(pages, 0, pages_size);
+       bitmap_copy(bitmap, chunk->populated, pcpu_unit_pages);
 
-       /*
-        * Each flushing trial can be very expensive, issue flush on
-        * the whole region at once rather than doing it for each cpu.
-        * This could be an overkill but is more scalable.
-        */
-       flush_cache_vunmap(pcpu_chunk_addr(chunk, 0, page_start),
-                          pcpu_chunk_addr(chunk, last, page_end));
+       *bitmapp = bitmap;
+       return pages;
+}
 
-       for_each_possible_cpu(cpu)
-               unmap_kernel_range_noflush(
-                               pcpu_chunk_addr(chunk, cpu, page_start),
-                               (page_end - page_start) << PAGE_SHIFT);
-
-       /* ditto as flush_cache_vunmap() */
-       if (flush_tlb)
-               flush_tlb_kernel_range(pcpu_chunk_addr(chunk, 0, page_start),
-                                      pcpu_chunk_addr(chunk, last, page_end));
+/**
+ * pcpu_free_pages - free pages which were allocated for @chunk
+ * @chunk: chunk pages were allocated for
+ * @pages: array of pages to be freed, indexed by pcpu_page_idx()
+ * @populated: populated bitmap
+ * @page_start: page index of the first page to be freed
+ * @page_end: page index of the last page to be freed + 1
+ *
+ * Free pages [@page_start and @page_end) in @pages for all units.
+ * The pages were allocated for @chunk.
+ */
+static void pcpu_free_pages(struct pcpu_chunk *chunk,
+                           struct page **pages, unsigned long *populated,
+                           int page_start, int page_end)
+{
+       unsigned int cpu;
+       int i;
+
+       for_each_possible_cpu(cpu) {
+               for (i = page_start; i < page_end; i++) {
+                       struct page *page = pages[pcpu_page_idx(cpu, i)];
+
+                       if (page)
+                               __free_page(page);
+               }
+       }
 }
 
 /**
- * pcpu_depopulate_chunk - depopulate and unmap an area of a pcpu_chunk
- * @chunk: chunk to depopulate
- * @off: offset to the area to depopulate
- * @size: size of the area to depopulate in bytes
- * @flush: whether to flush cache and tlb or not
- *
- * For each cpu, depopulate and unmap pages [@page_start,@page_end)
- * from @chunk.  If @flush is true, vcache is flushed before unmapping
- * and tlb after.
- *
- * CONTEXT:
- * pcpu_alloc_mutex.
+ * pcpu_alloc_pages - allocates pages for @chunk
+ * @chunk: target chunk
+ * @pages: array to put the allocated pages into, indexed by pcpu_page_idx()
+ * @populated: populated bitmap
+ * @page_start: page index of the first page to be allocated
+ * @page_end: page index of the last page to be allocated + 1
+ *
+ * Allocate pages [@page_start,@page_end) into @pages for all units.
+ * The allocation is for @chunk.  Percpu core doesn't care about the
+ * content of @pages and will pass it verbatim to pcpu_map_pages().
  */
-static void pcpu_depopulate_chunk(struct pcpu_chunk *chunk, int off, int size,
-                                 bool flush)
+static int pcpu_alloc_pages(struct pcpu_chunk *chunk,
+                           struct page **pages, unsigned long *populated,
+                           int page_start, int page_end)
 {
-       int page_start = PFN_DOWN(off);
-       int page_end = PFN_UP(off + size);
-       int unmap_start = -1;
-       int uninitialized_var(unmap_end);
+       const gfp_t gfp = GFP_KERNEL | __GFP_HIGHMEM | __GFP_COLD;
        unsigned int cpu;
        int i;
 
-       for (i = page_start; i < page_end; i++) {
-               for_each_possible_cpu(cpu) {
-                       struct page **pagep = pcpu_chunk_pagep(chunk, cpu, i);
+       for_each_possible_cpu(cpu) {
+               for (i = page_start; i < page_end; i++) {
+                       struct page **pagep = &pages[pcpu_page_idx(cpu, i)];
+
+                       *pagep = alloc_pages_node(cpu_to_node(cpu), gfp, 0);
+                       if (!*pagep) {
+                               pcpu_free_pages(chunk, pages, populated,
+                                               page_start, page_end);
+                               return -ENOMEM;
+                       }
+               }
+       }
+       return 0;
+}
 
-                       if (!*pagep)
-                               continue;
+/**
+ * pcpu_pre_unmap_flush - flush cache prior to unmapping
+ * @chunk: chunk the regions to be flushed belongs to
+ * @page_start: page index of the first page to be flushed
+ * @page_end: page index of the last page to be flushed + 1
+ *
+ * Pages in [@page_start,@page_end) of @chunk are about to be
+ * unmapped.  Flush cache.  As each flushing trial can be very
+ * expensive, issue flush on the whole region at once rather than
+ * doing it for each cpu.  This could be an overkill but is more
+ * scalable.
+ */
+static void pcpu_pre_unmap_flush(struct pcpu_chunk *chunk,
+                                int page_start, int page_end)
+{
+       flush_cache_vunmap(
+               pcpu_chunk_addr(chunk, pcpu_first_unit_cpu, page_start),
+               pcpu_chunk_addr(chunk, pcpu_last_unit_cpu, page_end));
+}
+
+static void __pcpu_unmap_pages(unsigned long addr, int nr_pages)
+{
+       unmap_kernel_range_noflush(addr, nr_pages << PAGE_SHIFT);
+}
 
-                       __free_page(*pagep);
+/**
+ * pcpu_unmap_pages - unmap pages out of a pcpu_chunk
+ * @chunk: chunk of interest
+ * @pages: pages array which can be used to pass information to free
+ * @populated: populated bitmap
+ * @page_start: page index of the first page to unmap
+ * @page_end: page index of the last page to unmap + 1
+ *
+ * For each cpu, unmap pages [@page_start,@page_end) out of @chunk.
+ * Corresponding elements in @pages were cleared by the caller and can
+ * be used to carry information to pcpu_free_pages() which will be
+ * called after all unmaps are finished.  The caller should call
+ * proper pre/post flush functions.
+ */
+static void pcpu_unmap_pages(struct pcpu_chunk *chunk,
+                            struct page **pages, unsigned long *populated,
+                            int page_start, int page_end)
+{
+       unsigned int cpu;
+       int i;
 
-                       /*
-                        * If it's partial depopulation, it might get
-                        * populated or depopulated again.  Mark the
-                        * page gone.
-                        */
-                       *pagep = NULL;
+       for_each_possible_cpu(cpu) {
+               for (i = page_start; i < page_end; i++) {
+                       struct page *page;
 
-                       unmap_start = unmap_start < 0 ? i : unmap_start;
-                       unmap_end = i + 1;
+                       page = pcpu_chunk_page(chunk, cpu, i);
+                       WARN_ON(!page);
+                       pages[pcpu_page_idx(cpu, i)] = page;
                }
+               __pcpu_unmap_pages(pcpu_chunk_addr(chunk, cpu, page_start),
+                                  page_end - page_start);
        }
 
-       if (unmap_start >= 0)
-               pcpu_unmap(chunk, unmap_start, unmap_end, flush);
+       for (i = page_start; i < page_end; i++)
+               __clear_bit(i, populated);
+}
+
+/**
+ * pcpu_post_unmap_tlb_flush - flush TLB after unmapping
+ * @chunk: pcpu_chunk the regions to be flushed belong to
+ * @page_start: page index of the first page to be flushed
+ * @page_end: page index of the last page to be flushed + 1
+ *
+ * Pages [@page_start,@page_end) of @chunk have been unmapped.  Flush
+ * TLB for the regions.  This can be skipped if the area is to be
+ * returned to vmalloc as vmalloc will handle TLB flushing lazily.
+ *
+ * As with pcpu_pre_unmap_flush(), TLB flushing also is done at once
+ * for the whole region.
+ */
+static void pcpu_post_unmap_tlb_flush(struct pcpu_chunk *chunk,
+                                     int page_start, int page_end)
+{
+       flush_tlb_kernel_range(
+               pcpu_chunk_addr(chunk, pcpu_first_unit_cpu, page_start),
+               pcpu_chunk_addr(chunk, pcpu_last_unit_cpu, page_end));
+}
+
+static int __pcpu_map_pages(unsigned long addr, struct page **pages,
+                           int nr_pages)
+{
+       return map_kernel_range_noflush(addr, nr_pages << PAGE_SHIFT,
+                                       PAGE_KERNEL, pages);
 }
 
 /**
- * pcpu_map - map pages into a pcpu_chunk
+ * pcpu_map_pages - map pages into a pcpu_chunk
  * @chunk: chunk of interest
+ * @pages: pages array containing pages to be mapped
+ * @populated: populated bitmap
  * @page_start: page index of the first page to map
  * @page_end: page index of the last page to map + 1
  *
- * For each cpu, map pages [@page_start,@page_end) into @chunk.
- * vcache is flushed afterwards.
+ * For each cpu, map pages [@page_start,@page_end) into @chunk.  The
+ * caller is responsible for calling pcpu_post_map_flush() after all
+ * mappings are complete.
+ *
+ * This function is responsible for setting corresponding bits in
+ * @chunk->populated bitmap and whatever is necessary for reverse
+ * lookup (addr -> chunk).
  */
-static int pcpu_map(struct pcpu_chunk *chunk, int page_start, int page_end)
+static int pcpu_map_pages(struct pcpu_chunk *chunk,
+                         struct page **pages, unsigned long *populated,
+                         int page_start, int page_end)
 {
-       unsigned int last = nr_cpu_ids - 1;
-       unsigned int cpu;
-       int err;
-
-       /* map must not be done on immutable chunk */
-       WARN_ON(chunk->immutable);
+       unsigned int cpu, tcpu;
+       int i, err;
 
        for_each_possible_cpu(cpu) {
-               err = map_kernel_range_noflush(
-                               pcpu_chunk_addr(chunk, cpu, page_start),
-                               (page_end - page_start) << PAGE_SHIFT,
-                               PAGE_KERNEL,
-                               pcpu_chunk_pagep(chunk, cpu, page_start));
+               err = __pcpu_map_pages(pcpu_chunk_addr(chunk, cpu, page_start),
+                                      &pages[pcpu_page_idx(cpu, page_start)],
+                                      page_end - page_start);
                if (err < 0)
-                       return err;
+                       goto err;
+       }
+
+       /* mapping successful, link chunk and mark populated */
+       for (i = page_start; i < page_end; i++) {
+               for_each_possible_cpu(cpu)
+                       pcpu_set_page_chunk(pages[pcpu_page_idx(cpu, i)],
+                                           chunk);
+               __set_bit(i, populated);
        }
 
-       /* flush at once, please read comments in pcpu_unmap() */
-       flush_cache_vmap(pcpu_chunk_addr(chunk, 0, page_start),
-                        pcpu_chunk_addr(chunk, last, page_end));
        return 0;
+
+err:
+       for_each_possible_cpu(tcpu) {
+               if (tcpu == cpu)
+                       break;
+               __pcpu_unmap_pages(pcpu_chunk_addr(chunk, tcpu, page_start),
+                                  page_end - page_start);
+       }
+       return err;
+}
+
+/**
+ * pcpu_post_map_flush - flush cache after mapping
+ * @chunk: pcpu_chunk the regions to be flushed belong to
+ * @page_start: page index of the first page to be flushed
+ * @page_end: page index of the last page to be flushed + 1
+ *
+ * Pages [@page_start,@page_end) of @chunk have been mapped.  Flush
+ * cache.
+ *
+ * As with pcpu_pre_unmap_flush(), TLB flushing also is done at once
+ * for the whole region.
+ */
+static void pcpu_post_map_flush(struct pcpu_chunk *chunk,
+                               int page_start, int page_end)
+{
+       flush_cache_vmap(
+               pcpu_chunk_addr(chunk, pcpu_first_unit_cpu, page_start),
+               pcpu_chunk_addr(chunk, pcpu_last_unit_cpu, page_end));
+}
+
+/**
+ * pcpu_depopulate_chunk - depopulate and unmap an area of a pcpu_chunk
+ * @chunk: chunk to depopulate
+ * @off: offset to the area to depopulate
+ * @size: size of the area to depopulate in bytes
+ * @flush: whether to flush cache and tlb or not
+ *
+ * For each cpu, depopulate and unmap pages [@page_start,@page_end)
+ * from @chunk.  If @flush is true, vcache is flushed before unmapping
+ * and tlb after.
+ *
+ * CONTEXT:
+ * pcpu_alloc_mutex.
+ */
+static void pcpu_depopulate_chunk(struct pcpu_chunk *chunk, int off, int size)
+{
+       int page_start = PFN_DOWN(off);
+       int page_end = PFN_UP(off + size);
+       struct page **pages;
+       unsigned long *populated;
+       int rs, re;
+
+       /* quick path, check whether it's empty already */
+       pcpu_for_each_unpop_region(chunk, rs, re, page_start, page_end) {
+               if (rs == page_start && re == page_end)
+                       return;
+               break;
+       }
+
+       /* immutable chunks can't be depopulated */
+       WARN_ON(chunk->immutable);
+
+       /*
+        * If control reaches here, there must have been at least one
+        * successful population attempt so the temp pages array must
+        * be available now.
+        */
+       pages = pcpu_get_pages_and_bitmap(chunk, &populated, false);
+       BUG_ON(!pages);
+
+       /* unmap and free */
+       pcpu_pre_unmap_flush(chunk, page_start, page_end);
+
+       pcpu_for_each_pop_region(chunk, rs, re, page_start, page_end)
+               pcpu_unmap_pages(chunk, pages, populated, rs, re);
+
+       /* no need to flush tlb, vmalloc will handle it lazily */
+
+       pcpu_for_each_pop_region(chunk, rs, re, page_start, page_end)
+               pcpu_free_pages(chunk, pages, populated, rs, re);
+
+       /* commit new bitmap */
+       bitmap_copy(chunk->populated, populated, pcpu_unit_pages);
 }
 
 /**
@@ -693,58 +933,68 @@ static int pcpu_map(struct pcpu_chunk *chunk, int page_start, int page_end)
  */
 static int pcpu_populate_chunk(struct pcpu_chunk *chunk, int off, int size)
 {
-       const gfp_t alloc_mask = GFP_KERNEL | __GFP_HIGHMEM | __GFP_COLD;
        int page_start = PFN_DOWN(off);
        int page_end = PFN_UP(off + size);
-       int map_start = -1;
-       int uninitialized_var(map_end);
+       int free_end = page_start, unmap_end = page_start;
+       struct page **pages;
+       unsigned long *populated;
        unsigned int cpu;
-       int i;
+       int rs, re, rc;
 
-       for (i = page_start; i < page_end; i++) {
-               if (pcpu_chunk_page_occupied(chunk, i)) {
-                       if (map_start >= 0) {
-                               if (pcpu_map(chunk, map_start, map_end))
-                                       goto err;
-                               map_start = -1;
-                       }
-                       continue;
-               }
+       /* quick path, check whether all pages are already there */
+       pcpu_for_each_pop_region(chunk, rs, re, page_start, page_end) {
+               if (rs == page_start && re == page_end)
+                       goto clear;
+               break;
+       }
 
-               map_start = map_start < 0 ? i : map_start;
-               map_end = i + 1;
+       /* need to allocate and map pages, this chunk can't be immutable */
+       WARN_ON(chunk->immutable);
 
-               for_each_possible_cpu(cpu) {
-                       struct page **pagep = pcpu_chunk_pagep(chunk, cpu, i);
+       pages = pcpu_get_pages_and_bitmap(chunk, &populated, true);
+       if (!pages)
+               return -ENOMEM;
 
-                       *pagep = alloc_pages_node(cpu_to_node(cpu),
-                                                 alloc_mask, 0);
-                       if (!*pagep)
-                               goto err;
-                       pcpu_set_page_chunk(*pagep, chunk);
-               }
+       /* alloc and map */
+       pcpu_for_each_unpop_region(chunk, rs, re, page_start, page_end) {
+               rc = pcpu_alloc_pages(chunk, pages, populated, rs, re);
+               if (rc)
+                       goto err_free;
+               free_end = re;
        }
 
-       if (map_start >= 0 && pcpu_map(chunk, map_start, map_end))
-               goto err;
+       pcpu_for_each_unpop_region(chunk, rs, re, page_start, page_end) {
+               rc = pcpu_map_pages(chunk, pages, populated, rs, re);
+               if (rc)
+                       goto err_unmap;
+               unmap_end = re;
+       }
+       pcpu_post_map_flush(chunk, page_start, page_end);
 
+       /* commit new bitmap */
+       bitmap_copy(chunk->populated, populated, pcpu_unit_pages);
+clear:
        for_each_possible_cpu(cpu)
-               memset(chunk->vm->addr + cpu * pcpu_unit_size + off, 0,
-                      size);
-
+               memset((void *)pcpu_chunk_addr(chunk, cpu, 0) + off, 0, size);
        return 0;
-err:
-       /* likely under heavy memory pressure, give memory back */
-       pcpu_depopulate_chunk(chunk, off, size, true);
-       return -ENOMEM;
+
+err_unmap:
+       pcpu_pre_unmap_flush(chunk, page_start, unmap_end);
+       pcpu_for_each_unpop_region(chunk, rs, re, page_start, unmap_end)
+               pcpu_unmap_pages(chunk, pages, populated, rs, re);
+       pcpu_post_unmap_tlb_flush(chunk, page_start, unmap_end);
+err_free:
+       pcpu_for_each_unpop_region(chunk, rs, re, page_start, free_end)
+               pcpu_free_pages(chunk, pages, populated, rs, re);
+       return rc;
 }
 
 static void free_pcpu_chunk(struct pcpu_chunk *chunk)
 {
        if (!chunk)
                return;
-       if (chunk->vm)
-               free_vm_area(chunk->vm);
+       if (chunk->vms)
+               pcpu_free_vm_areas(chunk->vms, pcpu_nr_groups);
        pcpu_mem_free(chunk->map, chunk->map_alloc * sizeof(chunk->map[0]));
        kfree(chunk);
 }
@@ -760,10 +1010,11 @@ static struct pcpu_chunk *alloc_pcpu_chunk(void)
        chunk->map = pcpu_mem_alloc(PCPU_DFL_MAP_ALLOC * sizeof(chunk->map[0]));
        chunk->map_alloc = PCPU_DFL_MAP_ALLOC;
        chunk->map[chunk->map_used++] = pcpu_unit_size;
-       chunk->page = chunk->page_ar;
 
-       chunk->vm = get_vm_area(pcpu_chunk_size, VM_ALLOC);
-       if (!chunk->vm) {
+       chunk->vms = pcpu_get_vm_areas(pcpu_group_offsets, pcpu_group_sizes,
+                                      pcpu_nr_groups, pcpu_atom_size,
+                                      GFP_KERNEL);
+       if (!chunk->vms) {
                free_pcpu_chunk(chunk);
                return NULL;
        }
@@ -771,6 +1022,7 @@ static struct pcpu_chunk *alloc_pcpu_chunk(void)
        INIT_LIST_HEAD(&chunk->list);
        chunk->free_size = pcpu_unit_size;
        chunk->contig_hint = pcpu_unit_size;
+       chunk->base_addr = chunk->vms[0]->addr - pcpu_group_offsets[0];
 
        return chunk;
 }
@@ -860,7 +1112,8 @@ area_found:
 
        mutex_unlock(&pcpu_alloc_mutex);
 
-       return __addr_to_pcpu_ptr(chunk->vm->addr + off);
+       /* return address relative to base address */
+       return __addr_to_pcpu_ptr(chunk->base_addr + off);
 
 fail_unlock:
        spin_unlock_irq(&pcpu_lock);
@@ -938,12 +1191,13 @@ static void pcpu_reclaim(struct work_struct *work)
        }
 
        spin_unlock_irq(&pcpu_lock);
-       mutex_unlock(&pcpu_alloc_mutex);
 
        list_for_each_entry_safe(chunk, next, &todo, list) {
-               pcpu_depopulate_chunk(chunk, 0, pcpu_unit_size, false);
+               pcpu_depopulate_chunk(chunk, 0, pcpu_unit_size);
                free_pcpu_chunk(chunk);
        }
+
+       mutex_unlock(&pcpu_alloc_mutex);
 }
 
 /**
@@ -968,7 +1222,7 @@ void free_percpu(void *ptr)
        spin_lock_irqsave(&pcpu_lock, flags);
 
        chunk = pcpu_chunk_addr_search(addr);
-       off = addr - chunk->vm->addr;
+       off = addr - chunk->base_addr;
 
        pcpu_free_area(chunk, off);
 
@@ -987,30 +1241,295 @@ void free_percpu(void *ptr)
 }
 EXPORT_SYMBOL_GPL(free_percpu);
 
+static inline size_t pcpu_calc_fc_sizes(size_t static_size,
+                                       size_t reserved_size,
+                                       ssize_t *dyn_sizep)
+{
+       size_t size_sum;
+
+       size_sum = PFN_ALIGN(static_size + reserved_size +
+                            (*dyn_sizep >= 0 ? *dyn_sizep : 0));
+       if (*dyn_sizep != 0)
+               *dyn_sizep = size_sum - static_size - reserved_size;
+
+       return size_sum;
+}
+
 /**
- * pcpu_setup_first_chunk - initialize the first percpu chunk
- * @get_page_fn: callback to fetch page pointer
- * @static_size: the size of static percpu area in bytes
+ * pcpu_alloc_alloc_info - allocate percpu allocation info
+ * @nr_groups: the number of groups
+ * @nr_units: the number of units
+ *
+ * Allocate ai which is large enough for @nr_groups groups containing
+ * @nr_units units.  The returned ai's groups[0].cpu_map points to the
+ * cpu_map array which is long enough for @nr_units and filled with
+ * NR_CPUS.  It's the caller's responsibility to initialize cpu_map
+ * pointer of other groups.
+ *
+ * RETURNS:
+ * Pointer to the allocated pcpu_alloc_info on success, NULL on
+ * failure.
+ */
+struct pcpu_alloc_info * __init pcpu_alloc_alloc_info(int nr_groups,
+                                                     int nr_units)
+{
+       struct pcpu_alloc_info *ai;
+       size_t base_size, ai_size;
+       void *ptr;
+       int unit;
+
+       base_size = ALIGN(sizeof(*ai) + nr_groups * sizeof(ai->groups[0]),
+                         __alignof__(ai->groups[0].cpu_map[0]));
+       ai_size = base_size + nr_units * sizeof(ai->groups[0].cpu_map[0]);
+
+       ptr = alloc_bootmem_nopanic(PFN_ALIGN(ai_size));
+       if (!ptr)
+               return NULL;
+       ai = ptr;
+       ptr += base_size;
+
+       ai->groups[0].cpu_map = ptr;
+
+       for (unit = 0; unit < nr_units; unit++)
+               ai->groups[0].cpu_map[unit] = NR_CPUS;
+
+       ai->nr_groups = nr_groups;
+       ai->__ai_size = PFN_ALIGN(ai_size);
+
+       return ai;
+}
+
+/**
+ * pcpu_free_alloc_info - free percpu allocation info
+ * @ai: pcpu_alloc_info to free
+ *
+ * Free @ai which was allocated by pcpu_alloc_alloc_info().
+ */
+void __init pcpu_free_alloc_info(struct pcpu_alloc_info *ai)
+{
+       free_bootmem(__pa(ai), ai->__ai_size);
+}
+
+/**
+ * pcpu_build_alloc_info - build alloc_info considering distances between CPUs
  * @reserved_size: the size of reserved percpu area in bytes
  * @dyn_size: free size for dynamic allocation in bytes, -1 for auto
- * @unit_size: unit size in bytes, must be multiple of PAGE_SIZE, -1 for auto
- * @base_addr: mapped address, NULL for auto
- * @populate_pte_fn: callback to allocate pagetable, NULL if unnecessary
+ * @atom_size: allocation atom size
+ * @cpu_distance_fn: callback to determine distance between cpus, optional
+ *
+ * This function determines grouping of units, their mappings to cpus
+ * and other parameters considering needed percpu size, allocation
+ * atom size and distances between CPUs.
+ *
+ * Groups are always mutliples of atom size and CPUs which are of
+ * LOCAL_DISTANCE both ways are grouped together and share space for
+ * units in the same group.  The returned configuration is guaranteed
+ * to have CPUs on different nodes on different groups and >=75% usage
+ * of allocated virtual address space.
+ *
+ * RETURNS:
+ * On success, pointer to the new allocation_info is returned.  On
+ * failure, ERR_PTR value is returned.
+ */
+struct pcpu_alloc_info * __init pcpu_build_alloc_info(
+                               size_t reserved_size, ssize_t dyn_size,
+                               size_t atom_size,
+                               pcpu_fc_cpu_distance_fn_t cpu_distance_fn)
+{
+       static int group_map[NR_CPUS] __initdata;
+       static int group_cnt[NR_CPUS] __initdata;
+       const size_t static_size = __per_cpu_end - __per_cpu_start;
+       int group_cnt_max = 0, nr_groups = 1, nr_units = 0;
+       size_t size_sum, min_unit_size, alloc_size;
+       int upa, max_upa, uninitialized_var(best_upa);  /* units_per_alloc */
+       int last_allocs, group, unit;
+       unsigned int cpu, tcpu;
+       struct pcpu_alloc_info *ai;
+       unsigned int *cpu_map;
+
+       /*
+        * Determine min_unit_size, alloc_size and max_upa such that
+        * alloc_size is multiple of atom_size and is the smallest
+        * which can accomodate 4k aligned segments which are equal to
+        * or larger than min_unit_size.
+        */
+       size_sum = pcpu_calc_fc_sizes(static_size, reserved_size, &dyn_size);
+       min_unit_size = max_t(size_t, size_sum, PCPU_MIN_UNIT_SIZE);
+
+       alloc_size = roundup(min_unit_size, atom_size);
+       upa = alloc_size / min_unit_size;
+       while (alloc_size % upa || ((alloc_size / upa) & ~PAGE_MASK))
+               upa--;
+       max_upa = upa;
+
+       /* group cpus according to their proximity */
+       for_each_possible_cpu(cpu) {
+               group = 0;
+       next_group:
+               for_each_possible_cpu(tcpu) {
+                       if (cpu == tcpu)
+                               break;
+                       if (group_map[tcpu] == group && cpu_distance_fn &&
+                           (cpu_distance_fn(cpu, tcpu) > LOCAL_DISTANCE ||
+                            cpu_distance_fn(tcpu, cpu) > LOCAL_DISTANCE)) {
+                               group++;
+                               nr_groups = max(nr_groups, group + 1);
+                               goto next_group;
+                       }
+               }
+               group_map[cpu] = group;
+               group_cnt[group]++;
+               group_cnt_max = max(group_cnt_max, group_cnt[group]);
+       }
+
+       /*
+        * Expand unit size until address space usage goes over 75%
+        * and then as much as possible without using more address
+        * space.
+        */
+       last_allocs = INT_MAX;
+       for (upa = max_upa; upa; upa--) {
+               int allocs = 0, wasted = 0;
+
+               if (alloc_size % upa || ((alloc_size / upa) & ~PAGE_MASK))
+                       continue;
+
+               for (group = 0; group < nr_groups; group++) {
+                       int this_allocs = DIV_ROUND_UP(group_cnt[group], upa);
+                       allocs += this_allocs;
+                       wasted += this_allocs * upa - group_cnt[group];
+               }
+
+               /*
+                * Don't accept if wastage is over 25%.  The
+                * greater-than comparison ensures upa==1 always
+                * passes the following check.
+                */
+               if (wasted > num_possible_cpus() / 3)
+                       continue;
+
+               /* and then don't consume more memory */
+               if (allocs > last_allocs)
+                       break;
+               last_allocs = allocs;
+               best_upa = upa;
+       }
+       upa = best_upa;
+
+       /* allocate and fill alloc_info */
+       for (group = 0; group < nr_groups; group++)
+               nr_units += roundup(group_cnt[group], upa);
+
+       ai = pcpu_alloc_alloc_info(nr_groups, nr_units);
+       if (!ai)
+               return ERR_PTR(-ENOMEM);
+       cpu_map = ai->groups[0].cpu_map;
+
+       for (group = 0; group < nr_groups; group++) {
+               ai->groups[group].cpu_map = cpu_map;
+               cpu_map += roundup(group_cnt[group], upa);
+       }
+
+       ai->static_size = static_size;
+       ai->reserved_size = reserved_size;
+       ai->dyn_size = dyn_size;
+       ai->unit_size = alloc_size / upa;
+       ai->atom_size = atom_size;
+       ai->alloc_size = alloc_size;
+
+       for (group = 0, unit = 0; group_cnt[group]; group++) {
+               struct pcpu_group_info *gi = &ai->groups[group];
+
+               /*
+                * Initialize base_offset as if all groups are located
+                * back-to-back.  The caller should update this to
+                * reflect actual allocation.
+                */
+               gi->base_offset = unit * ai->unit_size;
+
+               for_each_possible_cpu(cpu)
+                       if (group_map[cpu] == group)
+                               gi->cpu_map[gi->nr_units++] = cpu;
+               gi->nr_units = roundup(gi->nr_units, upa);
+               unit += gi->nr_units;
+       }
+       BUG_ON(unit != nr_units);
+
+       return ai;
+}
+
+/**
+ * pcpu_dump_alloc_info - print out information about pcpu_alloc_info
+ * @lvl: loglevel
+ * @ai: allocation info to dump
+ *
+ * Print out information about @ai using loglevel @lvl.
+ */
+static void pcpu_dump_alloc_info(const char *lvl,
+                                const struct pcpu_alloc_info *ai)
+{
+       int group_width = 1, cpu_width = 1, width;
+       char empty_str[] = "--------";
+       int alloc = 0, alloc_end = 0;
+       int group, v;
+       int upa, apl;   /* units per alloc, allocs per line */
+
+       v = ai->nr_groups;
+       while (v /= 10)
+               group_width++;
+
+       v = num_possible_cpus();
+       while (v /= 10)
+               cpu_width++;
+       empty_str[min_t(int, cpu_width, sizeof(empty_str) - 1)] = '\0';
+
+       upa = ai->alloc_size / ai->unit_size;
+       width = upa * (cpu_width + 1) + group_width + 3;
+       apl = rounddown_pow_of_two(max(60 / width, 1));
+
+       printk("%spcpu-alloc: s%zu r%zu d%zu u%zu alloc=%zu*%zu",
+              lvl, ai->static_size, ai->reserved_size, ai->dyn_size,
+              ai->unit_size, ai->alloc_size / ai->atom_size, ai->atom_size);
+
+       for (group = 0; group < ai->nr_groups; group++) {
+               const struct pcpu_group_info *gi = &ai->groups[group];
+               int unit = 0, unit_end = 0;
+
+               BUG_ON(gi->nr_units % upa);
+               for (alloc_end += gi->nr_units / upa;
+                    alloc < alloc_end; alloc++) {
+                       if (!(alloc % apl)) {
+                               printk("\n");
+                               printk("%spcpu-alloc: ", lvl);
+                       }
+                       printk("[%0*d] ", group_width, group);
+
+                       for (unit_end += upa; unit < unit_end; unit++)
+                               if (gi->cpu_map[unit] != NR_CPUS)
+                                       printk("%0*d ", cpu_width,
+                                              gi->cpu_map[unit]);
+                               else
+                                       printk("%s ", empty_str);
+               }
+       }
+       printk("\n");
+}
+
+/**
+ * pcpu_setup_first_chunk - initialize the first percpu chunk
+ * @ai: pcpu_alloc_info describing how to percpu area is shaped
+ * @base_addr: mapped address
  *
  * Initialize the first percpu chunk which contains the kernel static
  * perpcu area.  This function is to be called from arch percpu area
- * setup path.  The first two parameters are mandatory.  The rest are
- * optional.
- *
- * @get_page_fn() should return pointer to percpu page given cpu
- * number and page number.  It should at least return enough pages to
- * cover the static area.  The returned pages for static area should
- * have been initialized with valid data.  If @unit_size is specified,
- * it can also return pages after the static area.  NULL return
- * indicates end of pages for the cpu.  Note that @get_page_fn() must
- * return the same number of pages for all cpus.
- *
- * @reserved_size, if non-zero, specifies the amount of bytes to
+ * setup path.
+ *
+ * @ai contains all information necessary to initialize the first
+ * chunk and prime the dynamic percpu allocator.
+ *
+ * @ai->static_size is the size of static percpu area.
+ *
+ * @ai->reserved_size, if non-zero, specifies the amount of bytes to
  * reserve after the static area in the first chunk.  This reserves
  * the first chunk such that it's available only through reserved
  * percpu allocation.  This is primarily used to serve module percpu
@@ -1018,22 +1537,29 @@ EXPORT_SYMBOL_GPL(free_percpu);
  * limited offset range for symbol relocations to guarantee module
  * percpu symbols fall inside the relocatable range.
  *
- * @dyn_size, if non-negative, determines the number of bytes
- * available for dynamic allocation in the first chunk.  Specifying
- * non-negative value makes percpu leave alone the area beyond
- * @static_size + @reserved_size + @dyn_size.
+ * @ai->dyn_size determines the number of bytes available for dynamic
+ * allocation in the first chunk.  The area between @ai->static_size +
+ * @ai->reserved_size + @ai->dyn_size and @ai->unit_size is unused.
  *
- * @unit_size, if non-negative, specifies unit size and must be
- * aligned to PAGE_SIZE and equal to or larger than @static_size +
- * @reserved_size + if non-negative, @dyn_size.
+ * @ai->unit_size specifies unit size and must be aligned to PAGE_SIZE
+ * and equal to or larger than @ai->static_size + @ai->reserved_size +
+ * @ai->dyn_size.
  *
- * Non-null @base_addr means that the caller already allocated virtual
- * region for the first chunk and mapped it.  percpu must not mess
- * with the chunk.  Note that @base_addr with 0 @unit_size or non-NULL
- * @populate_pte_fn doesn't make any sense.
+ * @ai->atom_size is the allocation atom size and used as alignment
+ * for vm areas.
  *
- * @populate_pte_fn is used to populate the pagetable.  NULL means the
- * caller already populated the pagetable.
+ * @ai->alloc_size is the allocation size and always multiple of
+ * @ai->atom_size.  This is larger than @ai->atom_size if
+ * @ai->unit_size is larger than @ai->atom_size.
+ *
+ * @ai->nr_groups and @ai->groups describe virtual memory layout of
+ * percpu areas.  Units which should be colocated are put into the
+ * same group.  Dynamic VM areas will be allocated according to these
+ * groupings.  If @ai->nr_groups is zero, a single group containing
+ * all units is assumed.
+ *
+ * The caller should have mapped the first chunk at @base_addr and
+ * copied static data to each unit.
  *
  * If the first chunk ends up with both reserved and dynamic areas, it
  * is served by two chunks - one to serve the core static and reserved
@@ -1043,49 +1569,83 @@ EXPORT_SYMBOL_GPL(free_percpu);
  * and available for dynamic allocation like any other chunks.
  *
  * RETURNS:
- * The determined pcpu_unit_size which can be used to initialize
- * percpu access.
+ * 0 on success, -errno on failure.
  */
-size_t __init pcpu_setup_first_chunk(pcpu_get_page_fn_t get_page_fn,
-                                    size_t static_size, size_t reserved_size,
-                                    ssize_t dyn_size, ssize_t unit_size,
-                                    void *base_addr,
-                                    pcpu_populate_pte_fn_t populate_pte_fn)
+int __init pcpu_setup_first_chunk(const struct pcpu_alloc_info *ai,
+                                 void *base_addr)
 {
-       static struct vm_struct first_vm;
        static int smap[2], dmap[2];
-       size_t size_sum = static_size + reserved_size +
-                         (dyn_size >= 0 ? dyn_size : 0);
+       size_t dyn_size = ai->dyn_size;
+       size_t size_sum = ai->static_size + ai->reserved_size + dyn_size;
        struct pcpu_chunk *schunk, *dchunk = NULL;
+       unsigned long *group_offsets;
+       size_t *group_sizes;
+       unsigned long *unit_off;
        unsigned int cpu;
-       int nr_pages;
-       int err, i;
+       int *unit_map;
+       int group, unit, i;
 
-       /* santiy checks */
+       /* sanity checks */
        BUILD_BUG_ON(ARRAY_SIZE(smap) >= PCPU_DFL_MAP_ALLOC ||
                     ARRAY_SIZE(dmap) >= PCPU_DFL_MAP_ALLOC);
-       BUG_ON(!static_size);
-       if (unit_size >= 0) {
-               BUG_ON(unit_size < size_sum);
-               BUG_ON(unit_size & ~PAGE_MASK);
-               BUG_ON(unit_size < PCPU_MIN_UNIT_SIZE);
-       } else
-               BUG_ON(base_addr);
-       BUG_ON(base_addr && populate_pte_fn);
-
-       if (unit_size >= 0)
-               pcpu_unit_pages = unit_size >> PAGE_SHIFT;
-       else
-               pcpu_unit_pages = max_t(int, PCPU_MIN_UNIT_SIZE >> PAGE_SHIFT,
-                                       PFN_UP(size_sum));
+       BUG_ON(ai->nr_groups <= 0);
+       BUG_ON(!ai->static_size);
+       BUG_ON(!base_addr);
+       BUG_ON(ai->unit_size < size_sum);
+       BUG_ON(ai->unit_size & ~PAGE_MASK);
+       BUG_ON(ai->unit_size < PCPU_MIN_UNIT_SIZE);
+
+       pcpu_dump_alloc_info(KERN_DEBUG, ai);
+
+       /* process group information and build config tables accordingly */
+       group_offsets = alloc_bootmem(ai->nr_groups * sizeof(group_offsets[0]));
+       group_sizes = alloc_bootmem(ai->nr_groups * sizeof(group_sizes[0]));
+       unit_map = alloc_bootmem(nr_cpu_ids * sizeof(unit_map[0]));
+       unit_off = alloc_bootmem(nr_cpu_ids * sizeof(unit_off[0]));
+
+       for (cpu = 0; cpu < nr_cpu_ids; cpu++)
+               unit_map[cpu] = NR_CPUS;
+       pcpu_first_unit_cpu = NR_CPUS;
+
+       for (group = 0, unit = 0; group < ai->nr_groups; group++, unit += i) {
+               const struct pcpu_group_info *gi = &ai->groups[group];
+
+               group_offsets[group] = gi->base_offset;
+               group_sizes[group] = gi->nr_units * ai->unit_size;
+
+               for (i = 0; i < gi->nr_units; i++) {
+                       cpu = gi->cpu_map[i];
+                       if (cpu == NR_CPUS)
+                               continue;
 
-       pcpu_unit_size = pcpu_unit_pages << PAGE_SHIFT;
-       pcpu_chunk_size = nr_cpu_ids * pcpu_unit_size;
-       pcpu_chunk_struct_size = sizeof(struct pcpu_chunk)
-               + nr_cpu_ids * pcpu_unit_pages * sizeof(struct page *);
+                       BUG_ON(cpu > nr_cpu_ids || !cpu_possible(cpu));
+                       BUG_ON(unit_map[cpu] != NR_CPUS);
 
-       if (dyn_size < 0)
-               dyn_size = pcpu_unit_size - static_size - reserved_size;
+                       unit_map[cpu] = unit + i;
+                       unit_off[cpu] = gi->base_offset + i * ai->unit_size;
+
+                       if (pcpu_first_unit_cpu == NR_CPUS)
+                               pcpu_first_unit_cpu = cpu;
+               }
+       }
+       pcpu_last_unit_cpu = cpu;
+       pcpu_nr_units = unit;
+
+       for_each_possible_cpu(cpu)
+               BUG_ON(unit_map[cpu] == NR_CPUS);
+
+       pcpu_nr_groups = ai->nr_groups;
+       pcpu_group_offsets = group_offsets;
+       pcpu_group_sizes = group_sizes;
+       pcpu_unit_map = unit_map;
+       pcpu_unit_offsets = unit_off;
+
+       /* determine basic parameters */
+       pcpu_unit_pages = ai->unit_size >> PAGE_SHIFT;
+       pcpu_unit_size = pcpu_unit_pages << PAGE_SHIFT;
+       pcpu_atom_size = ai->atom_size;
+       pcpu_chunk_struct_size = sizeof(struct pcpu_chunk) +
+               BITS_TO_LONGS(pcpu_unit_pages) * sizeof(unsigned long);
 
        /*
         * Allocate chunk slots.  The additional last slot is for
@@ -1105,189 +1665,351 @@ size_t __init pcpu_setup_first_chunk(pcpu_get_page_fn_t get_page_fn,
         */
        schunk = alloc_bootmem(pcpu_chunk_struct_size);
        INIT_LIST_HEAD(&schunk->list);
-       schunk->vm = &first_vm;
+       schunk->base_addr = base_addr;
        schunk->map = smap;
        schunk->map_alloc = ARRAY_SIZE(smap);
-       schunk->page = schunk->page_ar;
+       schunk->immutable = true;
+       bitmap_fill(schunk->populated, pcpu_unit_pages);
 
-       if (reserved_size) {
-               schunk->free_size = reserved_size;
+       if (ai->reserved_size) {
+               schunk->free_size = ai->reserved_size;
                pcpu_reserved_chunk = schunk;
-               pcpu_reserved_chunk_limit = static_size + reserved_size;
+               pcpu_reserved_chunk_limit = ai->static_size + ai->reserved_size;
        } else {
                schunk->free_size = dyn_size;
                dyn_size = 0;                   /* dynamic area covered */
        }
        schunk->contig_hint = schunk->free_size;
 
-       schunk->map[schunk->map_used++] = -static_size;
+       schunk->map[schunk->map_used++] = -ai->static_size;
        if (schunk->free_size)
                schunk->map[schunk->map_used++] = schunk->free_size;
 
        /* init dynamic chunk if necessary */
        if (dyn_size) {
-               dchunk = alloc_bootmem(sizeof(struct pcpu_chunk));
+               dchunk = alloc_bootmem(pcpu_chunk_struct_size);
                INIT_LIST_HEAD(&dchunk->list);
-               dchunk->vm = &first_vm;
+               dchunk->base_addr = base_addr;
                dchunk->map = dmap;
                dchunk->map_alloc = ARRAY_SIZE(dmap);
-               dchunk->page = schunk->page_ar; /* share page map with schunk */
+               dchunk->immutable = true;
+               bitmap_fill(dchunk->populated, pcpu_unit_pages);
 
                dchunk->contig_hint = dchunk->free_size = dyn_size;
                dchunk->map[dchunk->map_used++] = -pcpu_reserved_chunk_limit;
                dchunk->map[dchunk->map_used++] = dchunk->free_size;
        }
 
-       /* allocate vm address */
-       first_vm.flags = VM_ALLOC;
-       first_vm.size = pcpu_chunk_size;
-
-       if (!base_addr)
-               vm_area_register_early(&first_vm, PAGE_SIZE);
-       else {
-               /*
-                * Pages already mapped.  No need to remap into
-                * vmalloc area.  In this case the first chunks can't
-                * be mapped or unmapped by percpu and are marked
-                * immutable.
-                */
-               first_vm.addr = base_addr;
-               schunk->immutable = true;
-               if (dchunk)
-                       dchunk->immutable = true;
-       }
-
-       /* assign pages */
-       nr_pages = -1;
-       for_each_possible_cpu(cpu) {
-               for (i = 0; i < pcpu_unit_pages; i++) {
-                       struct page *page = get_page_fn(cpu, i);
-
-                       if (!page)
-                               break;
-                       *pcpu_chunk_pagep(schunk, cpu, i) = page;
-               }
-
-               BUG_ON(i < PFN_UP(static_size));
-
-               if (nr_pages < 0)
-                       nr_pages = i;
-               else
-                       BUG_ON(nr_pages != i);
-       }
-
-       /* map them */
-       if (populate_pte_fn) {
-               for_each_possible_cpu(cpu)
-                       for (i = 0; i < nr_pages; i++)
-                               populate_pte_fn(pcpu_chunk_addr(schunk,
-                                                               cpu, i));
-
-               err = pcpu_map(schunk, 0, nr_pages);
-               if (err)
-                       panic("failed to setup static percpu area, err=%d\n",
-                             err);
-       }
-
        /* link the first chunk in */
        pcpu_first_chunk = dchunk ?: schunk;
        pcpu_chunk_relocate(pcpu_first_chunk, -1);
 
        /* we're done */
-       pcpu_base_addr = (void *)pcpu_chunk_addr(schunk, 0, 0);
-       return pcpu_unit_size;
+       pcpu_base_addr = base_addr;
+       return 0;
 }
 
-/*
- * Embedding first chunk setup helper.
- */
-static void *pcpue_ptr __initdata;
-static size_t pcpue_size __initdata;
-static size_t pcpue_unit_size __initdata;
+const char *pcpu_fc_names[PCPU_FC_NR] __initdata = {
+       [PCPU_FC_AUTO]  = "auto",
+       [PCPU_FC_EMBED] = "embed",
+       [PCPU_FC_PAGE]  = "page",
+};
 
-static struct page * __init pcpue_get_page(unsigned int cpu, int pageno)
-{
-       size_t off = (size_t)pageno << PAGE_SHIFT;
+enum pcpu_fc pcpu_chosen_fc __initdata = PCPU_FC_AUTO;
 
-       if (off >= pcpue_size)
-               return NULL;
+static int __init percpu_alloc_setup(char *str)
+{
+       if (0)
+               /* nada */;
+#ifdef CONFIG_NEED_PER_CPU_EMBED_FIRST_CHUNK
+       else if (!strcmp(str, "embed"))
+               pcpu_chosen_fc = PCPU_FC_EMBED;
+#endif
+#ifdef CONFIG_NEED_PER_CPU_PAGE_FIRST_CHUNK
+       else if (!strcmp(str, "page"))
+               pcpu_chosen_fc = PCPU_FC_PAGE;
+#endif
+       else
+               pr_warning("PERCPU: unknown allocator %s specified\n", str);
 
-       return virt_to_page(pcpue_ptr + cpu * pcpue_unit_size + off);
+       return 0;
 }
+early_param("percpu_alloc", percpu_alloc_setup);
 
+#if defined(CONFIG_NEED_PER_CPU_EMBED_FIRST_CHUNK) || \
+       !defined(CONFIG_HAVE_SETUP_PER_CPU_AREA)
 /**
  * pcpu_embed_first_chunk - embed the first percpu chunk into bootmem
- * @static_size: the size of static percpu area in bytes
  * @reserved_size: the size of reserved percpu area in bytes
  * @dyn_size: free size for dynamic allocation in bytes, -1 for auto
- * @unit_size: unit size in bytes, must be multiple of PAGE_SIZE, -1 for auto
+ * @atom_size: allocation atom size
+ * @cpu_distance_fn: callback to determine distance between cpus, optional
+ * @alloc_fn: function to allocate percpu page
+ * @free_fn: funtion to free percpu page
  *
  * This is a helper to ease setting up embedded first percpu chunk and
  * can be called where pcpu_setup_first_chunk() is expected.
  *
  * If this function is used to setup the first chunk, it is allocated
- * as a contiguous area using bootmem allocator and used as-is without
- * being mapped into vmalloc area.  This enables the first chunk to
- * piggy back on the linear physical mapping which often uses larger
- * page size.
+ * by calling @alloc_fn and used as-is without being mapped into
+ * vmalloc area.  Allocations are always whole multiples of @atom_size
+ * aligned to @atom_size.
+ *
+ * This enables the first chunk to piggy back on the linear physical
+ * mapping which often uses larger page size.  Please note that this
+ * can result in very sparse cpu->unit mapping on NUMA machines thus
+ * requiring large vmalloc address space.  Don't use this allocator if
+ * vmalloc space is not orders of magnitude larger than distances
+ * between node memory addresses (ie. 32bit NUMA machines).
  *
  * When @dyn_size is positive, dynamic area might be larger than
- * specified to fill page alignment.  Also, when @dyn_size is auto,
- * @dyn_size does not fill the whole first chunk but only what's
- * necessary for page alignment after static and reserved areas.
+ * specified to fill page alignment.  When @dyn_size is auto,
+ * @dyn_size is just big enough to fill page alignment after static
+ * and reserved areas.
  *
  * If the needed size is smaller than the minimum or specified unit
- * size, the leftover is returned to the bootmem allocator.
+ * size, the leftover is returned using @free_fn.
  *
  * RETURNS:
- * The determined pcpu_unit_size which can be used to initialize
- * percpu access on success, -errno on failure.
+ * 0 on success, -errno on failure.
  */
-ssize_t __init pcpu_embed_first_chunk(size_t static_size, size_t reserved_size,
-                                     ssize_t dyn_size, ssize_t unit_size)
+int __init pcpu_embed_first_chunk(size_t reserved_size, ssize_t dyn_size,
+                                 size_t atom_size,
+                                 pcpu_fc_cpu_distance_fn_t cpu_distance_fn,
+                                 pcpu_fc_alloc_fn_t alloc_fn,
+                                 pcpu_fc_free_fn_t free_fn)
 {
-       size_t chunk_size;
-       unsigned int cpu;
+       void *base = (void *)ULONG_MAX;
+       void **areas = NULL;
+       struct pcpu_alloc_info *ai;
+       size_t size_sum, areas_size;
+       int group, i, rc;
+
+       ai = pcpu_build_alloc_info(reserved_size, dyn_size, atom_size,
+                                  cpu_distance_fn);
+       if (IS_ERR(ai))
+               return PTR_ERR(ai);
+
+       size_sum = ai->static_size + ai->reserved_size + ai->dyn_size;
+       areas_size = PFN_ALIGN(ai->nr_groups * sizeof(void *));
+
+       areas = alloc_bootmem_nopanic(areas_size);
+       if (!areas) {
+               rc = -ENOMEM;
+               goto out_free;
+       }
 
-       /* determine parameters and allocate */
-       pcpue_size = PFN_ALIGN(static_size + reserved_size +
-                              (dyn_size >= 0 ? dyn_size : 0));
-       if (dyn_size != 0)
-               dyn_size = pcpue_size - static_size - reserved_size;
-
-       if (unit_size >= 0) {
-               BUG_ON(unit_size < pcpue_size);
-               pcpue_unit_size = unit_size;
-       } else
-               pcpue_unit_size = max_t(size_t, pcpue_size, PCPU_MIN_UNIT_SIZE);
-
-       chunk_size = pcpue_unit_size * nr_cpu_ids;
-
-       pcpue_ptr = __alloc_bootmem_nopanic(chunk_size, PAGE_SIZE,
-                                           __pa(MAX_DMA_ADDRESS));
-       if (!pcpue_ptr) {
-               pr_warning("PERCPU: failed to allocate %zu bytes for "
-                          "embedding\n", chunk_size);
-               return -ENOMEM;
+       /* allocate, copy and determine base address */
+       for (group = 0; group < ai->nr_groups; group++) {
+               struct pcpu_group_info *gi = &ai->groups[group];
+               unsigned int cpu = NR_CPUS;
+               void *ptr;
+
+               for (i = 0; i < gi->nr_units && cpu == NR_CPUS; i++)
+                       cpu = gi->cpu_map[i];
+               BUG_ON(cpu == NR_CPUS);
+
+               /* allocate space for the whole group */
+               ptr = alloc_fn(cpu, gi->nr_units * ai->unit_size, atom_size);
+               if (!ptr) {
+                       rc = -ENOMEM;
+                       goto out_free_areas;
+               }
+               areas[group] = ptr;
+
+               base = min(ptr, base);
+
+               for (i = 0; i < gi->nr_units; i++, ptr += ai->unit_size) {
+                       if (gi->cpu_map[i] == NR_CPUS) {
+                               /* unused unit, free whole */
+                               free_fn(ptr, ai->unit_size);
+                               continue;
+                       }
+                       /* copy and return the unused part */
+                       memcpy(ptr, __per_cpu_load, ai->static_size);
+                       free_fn(ptr + size_sum, ai->unit_size - size_sum);
+               }
        }
 
-       /* return the leftover and copy */
-       for (cpu = 0; cpu < nr_cpu_ids; cpu++) {
-               void *ptr = pcpue_ptr + cpu * pcpue_unit_size;
+       /* base address is now known, determine group base offsets */
+       for (group = 0; group < ai->nr_groups; group++)
+               ai->groups[group].base_offset = areas[group] - base;
+
+       pr_info("PERCPU: Embedded %zu pages/cpu @%p s%zu r%zu d%zu u%zu\n",
+               PFN_DOWN(size_sum), base, ai->static_size, ai->reserved_size,
+               ai->dyn_size, ai->unit_size);
+
+       rc = pcpu_setup_first_chunk(ai, base);
+       goto out_free;
+
+out_free_areas:
+       for (group = 0; group < ai->nr_groups; group++)
+               free_fn(areas[group],
+                       ai->groups[group].nr_units * ai->unit_size);
+out_free:
+       pcpu_free_alloc_info(ai);
+       if (areas)
+               free_bootmem(__pa(areas), areas_size);
+       return rc;
+}
+#endif /* CONFIG_NEED_PER_CPU_EMBED_FIRST_CHUNK ||
+         !CONFIG_HAVE_SETUP_PER_CPU_AREA */
+
+#ifdef CONFIG_NEED_PER_CPU_PAGE_FIRST_CHUNK
+/**
+ * pcpu_page_first_chunk - map the first chunk using PAGE_SIZE pages
+ * @reserved_size: the size of reserved percpu area in bytes
+ * @alloc_fn: function to allocate percpu page, always called with PAGE_SIZE
+ * @free_fn: funtion to free percpu page, always called with PAGE_SIZE
+ * @populate_pte_fn: function to populate pte
+ *
+ * This is a helper to ease setting up page-remapped first percpu
+ * chunk and can be called where pcpu_setup_first_chunk() is expected.
+ *
+ * This is the basic allocator.  Static percpu area is allocated
+ * page-by-page into vmalloc area.
+ *
+ * RETURNS:
+ * 0 on success, -errno on failure.
+ */
+int __init pcpu_page_first_chunk(size_t reserved_size,
+                                pcpu_fc_alloc_fn_t alloc_fn,
+                                pcpu_fc_free_fn_t free_fn,
+                                pcpu_fc_populate_pte_fn_t populate_pte_fn)
+{
+       static struct vm_struct vm;
+       struct pcpu_alloc_info *ai;
+       char psize_str[16];
+       int unit_pages;
+       size_t pages_size;
+       struct page **pages;
+       int unit, i, j, rc;
+
+       snprintf(psize_str, sizeof(psize_str), "%luK", PAGE_SIZE >> 10);
+
+       ai = pcpu_build_alloc_info(reserved_size, -1, PAGE_SIZE, NULL);
+       if (IS_ERR(ai))
+               return PTR_ERR(ai);
+       BUG_ON(ai->nr_groups != 1);
+       BUG_ON(ai->groups[0].nr_units != num_possible_cpus());
+
+       unit_pages = ai->unit_size >> PAGE_SHIFT;
+
+       /* unaligned allocations can't be freed, round up to page size */
+       pages_size = PFN_ALIGN(unit_pages * num_possible_cpus() *
+                              sizeof(pages[0]));
+       pages = alloc_bootmem(pages_size);
+
+       /* allocate pages */
+       j = 0;
+       for (unit = 0; unit < num_possible_cpus(); unit++)
+               for (i = 0; i < unit_pages; i++) {
+                       unsigned int cpu = ai->groups[0].cpu_map[unit];
+                       void *ptr;
+
+                       ptr = alloc_fn(cpu, PAGE_SIZE, PAGE_SIZE);
+                       if (!ptr) {
+                               pr_warning("PERCPU: failed to allocate %s page "
+                                          "for cpu%u\n", psize_str, cpu);
+                               goto enomem;
+                       }
+                       pages[j++] = virt_to_page(ptr);
+               }
+
+       /* allocate vm area, map the pages and copy static data */
+       vm.flags = VM_ALLOC;
+       vm.size = num_possible_cpus() * ai->unit_size;
+       vm_area_register_early(&vm, PAGE_SIZE);
+
+       for (unit = 0; unit < num_possible_cpus(); unit++) {
+               unsigned long unit_addr =
+                       (unsigned long)vm.addr + unit * ai->unit_size;
+
+               for (i = 0; i < unit_pages; i++)
+                       populate_pte_fn(unit_addr + (i << PAGE_SHIFT));
+
+               /* pte already populated, the following shouldn't fail */
+               rc = __pcpu_map_pages(unit_addr, &pages[unit * unit_pages],
+                                     unit_pages);
+               if (rc < 0)
+                       panic("failed to map percpu area, err=%d\n", rc);
 
-               if (cpu_possible(cpu)) {
-                       free_bootmem(__pa(ptr + pcpue_size),
-                                    pcpue_unit_size - pcpue_size);
-                       memcpy(ptr, __per_cpu_load, static_size);
-               } else
-                       free_bootmem(__pa(ptr), pcpue_unit_size);
+               /*
+                * FIXME: Archs with virtual cache should flush local
+                * cache for the linear mapping here - something
+                * equivalent to flush_cache_vmap() on the local cpu.
+                * flush_cache_vmap() can't be used as most supporting
+                * data structures are not set up yet.
+                */
+
+               /* copy static data */
+               memcpy((void *)unit_addr, __per_cpu_load, ai->static_size);
        }
 
        /* we're ready, commit */
-       pr_info("PERCPU: Embedded %zu pages at %p, static data %zu bytes\n",
-               pcpue_size >> PAGE_SHIFT, pcpue_ptr, static_size);
+       pr_info("PERCPU: %d %s pages/cpu @%p s%zu r%zu d%zu\n",
+               unit_pages, psize_str, vm.addr, ai->static_size,
+               ai->reserved_size, ai->dyn_size);
+
+       rc = pcpu_setup_first_chunk(ai, vm.addr);
+       goto out_free_ar;
+
+enomem:
+       while (--j >= 0)
+               free_fn(page_address(pages[j]), PAGE_SIZE);
+       rc = -ENOMEM;
+out_free_ar:
+       free_bootmem(__pa(pages), pages_size);
+       pcpu_free_alloc_info(ai);
+       return rc;
+}
+#endif /* CONFIG_NEED_PER_CPU_PAGE_FIRST_CHUNK */
+
+/*
+ * Generic percpu area setup.
+ *
+ * The embedding helper is used because its behavior closely resembles
+ * the original non-dynamic generic percpu area setup.  This is
+ * important because many archs have addressing restrictions and might
+ * fail if the percpu area is located far away from the previous
+ * location.  As an added bonus, in non-NUMA cases, embedding is
+ * generally a good idea TLB-wise because percpu area can piggy back
+ * on the physical linear memory mapping which uses large page
+ * mappings on applicable archs.
+ */
+#ifndef CONFIG_HAVE_SETUP_PER_CPU_AREA
+unsigned long __per_cpu_offset[NR_CPUS] __read_mostly;
+EXPORT_SYMBOL(__per_cpu_offset);
+
+static void * __init pcpu_dfl_fc_alloc(unsigned int cpu, size_t size,
+                                      size_t align)
+{
+       return __alloc_bootmem_nopanic(size, align, __pa(MAX_DMA_ADDRESS));
+}
 
-       return pcpu_setup_first_chunk(pcpue_get_page, static_size,
-                                     reserved_size, dyn_size,
-                                     pcpue_unit_size, pcpue_ptr, NULL);
+static void __init pcpu_dfl_fc_free(void *ptr, size_t size)
+{
+       free_bootmem(__pa(ptr), size);
+}
+
+void __init setup_per_cpu_areas(void)
+{
+       unsigned long delta;
+       unsigned int cpu;
+       int rc;
+
+       /*
+        * Always reserve area for module percpu variables.  That's
+        * what the legacy allocator did.
+        */
+       rc = pcpu_embed_first_chunk(PERCPU_MODULE_RESERVE,
+                                   PERCPU_DYNAMIC_RESERVE, PAGE_SIZE, NULL,
+                                   pcpu_dfl_fc_alloc, pcpu_dfl_fc_free);
+       if (rc < 0)
+               panic("Failed to initialized percpu areas.");
+
+       delta = (unsigned long)pcpu_base_addr - (unsigned long)__per_cpu_start;
+       for_each_possible_cpu(cpu)
+               __per_cpu_offset[cpu] = delta + pcpu_unit_offsets[cpu];
 }
+#endif /* CONFIG_HAVE_SETUP_PER_CPU_AREA */
index e66d07d1b4ff424b108c0bd111e2092f217aede0..6eedf7e473d1e89f09fcc5814e342bee01540ce4 100644 (file)
@@ -19,7 +19,7 @@
 #include <linux/module.h>
 #include <linux/quicklist.h>
 
-DEFINE_PER_CPU(struct quicklist, quicklist)[CONFIG_NR_QUICK];
+DEFINE_PER_CPU(struct quicklist [CONFIG_NR_QUICK], quicklist);
 
 #define FRACTION_OF_NODE_MEM   16
 
index 417ed843b251850eb71e3cd2e78835f7272b6aa8..0a216aae227e8b3ca7daa5ab8140a2a804784181 100644 (file)
--- a/mm/slub.c
+++ b/mm/slub.c
@@ -1071,6 +1071,8 @@ static inline unsigned long kmem_cache_flags(unsigned long objsize,
 }
 #define slub_debug 0
 
+#define disable_higher_order_debug 0
+
 static inline unsigned long slabs_node(struct kmem_cache *s, int node)
                                                        { return 0; }
 static inline unsigned long node_nr_slabs(struct kmem_cache_node *n)
@@ -2111,8 +2113,8 @@ init_kmem_cache_node(struct kmem_cache_node *n, struct kmem_cache *s)
  */
 #define NR_KMEM_CACHE_CPU 100
 
-static DEFINE_PER_CPU(struct kmem_cache_cpu,
-                               kmem_cache_cpu)[NR_KMEM_CACHE_CPU];
+static DEFINE_PER_CPU(struct kmem_cache_cpu [NR_KMEM_CACHE_CPU],
+                     kmem_cache_cpu);
 
 static DEFINE_PER_CPU(struct kmem_cache_cpu *, kmem_cache_cpu_free);
 static DECLARE_BITMAP(kmem_cach_cpu_free_init_once, CONFIG_NR_CPUS);
index f8189a4b3e135e4c4158bb80082a49434fcb54af..204b8243d8abb11cb9abd2f37dd8864ad0a346aa 100644 (file)
@@ -265,6 +265,7 @@ struct vmap_area {
 static DEFINE_SPINLOCK(vmap_area_lock);
 static struct rb_root vmap_area_root = RB_ROOT;
 static LIST_HEAD(vmap_area_list);
+static unsigned long vmap_area_pcpu_hole;
 
 static struct vmap_area *__find_vmap_area(unsigned long addr)
 {
@@ -431,6 +432,15 @@ static void __free_vmap_area(struct vmap_area *va)
        RB_CLEAR_NODE(&va->rb_node);
        list_del_rcu(&va->list);
 
+       /*
+        * Track the highest possible candidate for pcpu area
+        * allocation.  Areas outside of vmalloc area can be returned
+        * here too, consider only end addresses which fall inside
+        * vmalloc area proper.
+        */
+       if (va->va_end > VMALLOC_START && va->va_end <= VMALLOC_END)
+               vmap_area_pcpu_hole = max(vmap_area_pcpu_hole, va->va_end);
+
        call_rcu(&va->rcu_head, rcu_free_va);
 }
 
@@ -1038,6 +1048,9 @@ void __init vmalloc_init(void)
                va->va_end = va->va_start + tmp->size;
                __insert_vmap_area(va);
        }
+
+       vmap_area_pcpu_hole = VMALLOC_END;
+
        vmap_initialized = true;
 }
 
@@ -1122,13 +1135,34 @@ EXPORT_SYMBOL_GPL(map_vm_area);
 DEFINE_RWLOCK(vmlist_lock);
 struct vm_struct *vmlist;
 
+static void insert_vmalloc_vm(struct vm_struct *vm, struct vmap_area *va,
+                             unsigned long flags, void *caller)
+{
+       struct vm_struct *tmp, **p;
+
+       vm->flags = flags;
+       vm->addr = (void *)va->va_start;
+       vm->size = va->va_end - va->va_start;
+       vm->caller = caller;
+       va->private = vm;
+       va->flags |= VM_VM_AREA;
+
+       write_lock(&vmlist_lock);
+       for (p = &vmlist; (tmp = *p) != NULL; p = &tmp->next) {
+               if (tmp->addr >= vm->addr)
+                       break;
+       }
+       vm->next = *p;
+       *p = vm;
+       write_unlock(&vmlist_lock);
+}
+
 static struct vm_struct *__get_vm_area_node(unsigned long size,
                unsigned long flags, unsigned long start, unsigned long end,
                int node, gfp_t gfp_mask, void *caller)
 {
        static struct vmap_area *va;
        struct vm_struct *area;
-       struct vm_struct *tmp, **p;
        unsigned long align = 1;
 
        BUG_ON(in_interrupt());
@@ -1147,7 +1181,7 @@ static struct vm_struct *__get_vm_area_node(unsigned long size,
        if (unlikely(!size))
                return NULL;
 
-       area = kmalloc_node(sizeof(*area), gfp_mask & GFP_RECLAIM_MASK, node);
+       area = kzalloc_node(sizeof(*area), gfp_mask & GFP_RECLAIM_MASK, node);
        if (unlikely(!area))
                return NULL;
 
@@ -1162,25 +1196,7 @@ static struct vm_struct *__get_vm_area_node(unsigned long size,
                return NULL;
        }
 
-       area->flags = flags;
-       area->addr = (void *)va->va_start;
-       area->size = size;
-       area->pages = NULL;
-       area->nr_pages = 0;
-       area->phys_addr = 0;
-       area->caller = caller;
-       va->private = area;
-       va->flags |= VM_VM_AREA;
-
-       write_lock(&vmlist_lock);
-       for (p = &vmlist; (tmp = *p) != NULL; p = &tmp->next) {
-               if (tmp->addr >= area->addr)
-                       break;
-       }
-       area->next = *p;
-       *p = area;
-       write_unlock(&vmlist_lock);
-
+       insert_vmalloc_vm(area, va, flags, caller);
        return area;
 }
 
@@ -1818,6 +1834,286 @@ void free_vm_area(struct vm_struct *area)
 }
 EXPORT_SYMBOL_GPL(free_vm_area);
 
+static struct vmap_area *node_to_va(struct rb_node *n)
+{
+       return n ? rb_entry(n, struct vmap_area, rb_node) : NULL;
+}
+
+/**
+ * pvm_find_next_prev - find the next and prev vmap_area surrounding @end
+ * @end: target address
+ * @pnext: out arg for the next vmap_area
+ * @pprev: out arg for the previous vmap_area
+ *
+ * Returns: %true if either or both of next and prev are found,
+ *         %false if no vmap_area exists
+ *
+ * Find vmap_areas end addresses of which enclose @end.  ie. if not
+ * NULL, *pnext->va_end > @end and *pprev->va_end <= @end.
+ */
+static bool pvm_find_next_prev(unsigned long end,
+                              struct vmap_area **pnext,
+                              struct vmap_area **pprev)
+{
+       struct rb_node *n = vmap_area_root.rb_node;
+       struct vmap_area *va = NULL;
+
+       while (n) {
+               va = rb_entry(n, struct vmap_area, rb_node);
+               if (end < va->va_end)
+                       n = n->rb_left;
+               else if (end > va->va_end)
+                       n = n->rb_right;
+               else
+                       break;
+       }
+
+       if (!va)
+               return false;
+
+       if (va->va_end > end) {
+               *pnext = va;
+               *pprev = node_to_va(rb_prev(&(*pnext)->rb_node));
+       } else {
+               *pprev = va;
+               *pnext = node_to_va(rb_next(&(*pprev)->rb_node));
+       }
+       return true;
+}
+
+/**
+ * pvm_determine_end - find the highest aligned address between two vmap_areas
+ * @pnext: in/out arg for the next vmap_area
+ * @pprev: in/out arg for the previous vmap_area
+ * @align: alignment
+ *
+ * Returns: determined end address
+ *
+ * Find the highest aligned address between *@pnext and *@pprev below
+ * VMALLOC_END.  *@pnext and *@pprev are adjusted so that the aligned
+ * down address is between the end addresses of the two vmap_areas.
+ *
+ * Please note that the address returned by this function may fall
+ * inside *@pnext vmap_area.  The caller is responsible for checking
+ * that.
+ */
+static unsigned long pvm_determine_end(struct vmap_area **pnext,
+                                      struct vmap_area **pprev,
+                                      unsigned long align)
+{
+       const unsigned long vmalloc_end = VMALLOC_END & ~(align - 1);
+       unsigned long addr;
+
+       if (*pnext)
+               addr = min((*pnext)->va_start & ~(align - 1), vmalloc_end);
+       else
+               addr = vmalloc_end;
+
+       while (*pprev && (*pprev)->va_end > addr) {
+               *pnext = *pprev;
+               *pprev = node_to_va(rb_prev(&(*pnext)->rb_node));
+       }
+
+       return addr;
+}
+
+/**
+ * pcpu_get_vm_areas - allocate vmalloc areas for percpu allocator
+ * @offsets: array containing offset of each area
+ * @sizes: array containing size of each area
+ * @nr_vms: the number of areas to allocate
+ * @align: alignment, all entries in @offsets and @sizes must be aligned to this
+ * @gfp_mask: allocation mask
+ *
+ * Returns: kmalloc'd vm_struct pointer array pointing to allocated
+ *         vm_structs on success, %NULL on failure
+ *
+ * Percpu allocator wants to use congruent vm areas so that it can
+ * maintain the offsets among percpu areas.  This function allocates
+ * congruent vmalloc areas for it.  These areas tend to be scattered
+ * pretty far, distance between two areas easily going up to
+ * gigabytes.  To avoid interacting with regular vmallocs, these areas
+ * are allocated from top.
+ *
+ * Despite its complicated look, this allocator is rather simple.  It
+ * does everything top-down and scans areas from the end looking for
+ * matching slot.  While scanning, if any of the areas overlaps with
+ * existing vmap_area, the base address is pulled down to fit the
+ * area.  Scanning is repeated till all the areas fit and then all
+ * necessary data structres are inserted and the result is returned.
+ */
+struct vm_struct **pcpu_get_vm_areas(const unsigned long *offsets,
+                                    const size_t *sizes, int nr_vms,
+                                    size_t align, gfp_t gfp_mask)
+{
+       const unsigned long vmalloc_start = ALIGN(VMALLOC_START, align);
+       const unsigned long vmalloc_end = VMALLOC_END & ~(align - 1);
+       struct vmap_area **vas, *prev, *next;
+       struct vm_struct **vms;
+       int area, area2, last_area, term_area;
+       unsigned long base, start, end, last_end;
+       bool purged = false;
+
+       gfp_mask &= GFP_RECLAIM_MASK;
+
+       /* verify parameters and allocate data structures */
+       BUG_ON(align & ~PAGE_MASK || !is_power_of_2(align));
+       for (last_area = 0, area = 0; area < nr_vms; area++) {
+               start = offsets[area];
+               end = start + sizes[area];
+
+               /* is everything aligned properly? */
+               BUG_ON(!IS_ALIGNED(offsets[area], align));
+               BUG_ON(!IS_ALIGNED(sizes[area], align));
+
+               /* detect the area with the highest address */
+               if (start > offsets[last_area])
+                       last_area = area;
+
+               for (area2 = 0; area2 < nr_vms; area2++) {
+                       unsigned long start2 = offsets[area2];
+                       unsigned long end2 = start2 + sizes[area2];
+
+                       if (area2 == area)
+                               continue;
+
+                       BUG_ON(start2 >= start && start2 < end);
+                       BUG_ON(end2 <= end && end2 > start);
+               }
+       }
+       last_end = offsets[last_area] + sizes[last_area];
+
+       if (vmalloc_end - vmalloc_start < last_end) {
+               WARN_ON(true);
+               return NULL;
+       }
+
+       vms = kzalloc(sizeof(vms[0]) * nr_vms, gfp_mask);
+       vas = kzalloc(sizeof(vas[0]) * nr_vms, gfp_mask);
+       if (!vas || !vms)
+               goto err_free;
+
+       for (area = 0; area < nr_vms; area++) {
+               vas[area] = kzalloc(sizeof(struct vmap_area), gfp_mask);
+               vms[area] = kzalloc(sizeof(struct vm_struct), gfp_mask);
+               if (!vas[area] || !vms[area])
+                       goto err_free;
+       }
+retry:
+       spin_lock(&vmap_area_lock);
+
+       /* start scanning - we scan from the top, begin with the last area */
+       area = term_area = last_area;
+       start = offsets[area];
+       end = start + sizes[area];
+
+       if (!pvm_find_next_prev(vmap_area_pcpu_hole, &next, &prev)) {
+               base = vmalloc_end - last_end;
+               goto found;
+       }
+       base = pvm_determine_end(&next, &prev, align) - end;
+
+       while (true) {
+               BUG_ON(next && next->va_end <= base + end);
+               BUG_ON(prev && prev->va_end > base + end);
+
+               /*
+                * base might have underflowed, add last_end before
+                * comparing.
+                */
+               if (base + last_end < vmalloc_start + last_end) {
+                       spin_unlock(&vmap_area_lock);
+                       if (!purged) {
+                               purge_vmap_area_lazy();
+                               purged = true;
+                               goto retry;
+                       }
+                       goto err_free;
+               }
+
+               /*
+                * If next overlaps, move base downwards so that it's
+                * right below next and then recheck.
+                */
+               if (next && next->va_start < base + end) {
+                       base = pvm_determine_end(&next, &prev, align) - end;
+                       term_area = area;
+                       continue;
+               }
+
+               /*
+                * If prev overlaps, shift down next and prev and move
+                * base so that it's right below new next and then
+                * recheck.
+                */
+               if (prev && prev->va_end > base + start)  {
+                       next = prev;
+                       prev = node_to_va(rb_prev(&next->rb_node));
+                       base = pvm_determine_end(&next, &prev, align) - end;
+                       term_area = area;
+                       continue;
+               }
+
+               /*
+                * This area fits, move on to the previous one.  If
+                * the previous one is the terminal one, we're done.
+                */
+               area = (area + nr_vms - 1) % nr_vms;
+               if (area == term_area)
+                       break;
+               start = offsets[area];
+               end = start + sizes[area];
+               pvm_find_next_prev(base + end, &next, &prev);
+       }
+found:
+       /* we've found a fitting base, insert all va's */
+       for (area = 0; area < nr_vms; area++) {
+               struct vmap_area *va = vas[area];
+
+               va->va_start = base + offsets[area];
+               va->va_end = va->va_start + sizes[area];
+               __insert_vmap_area(va);
+       }
+
+       vmap_area_pcpu_hole = base + offsets[last_area];
+
+       spin_unlock(&vmap_area_lock);
+
+       /* insert all vm's */
+       for (area = 0; area < nr_vms; area++)
+               insert_vmalloc_vm(vms[area], vas[area], VM_ALLOC,
+                                 pcpu_get_vm_areas);
+
+       kfree(vas);
+       return vms;
+
+err_free:
+       for (area = 0; area < nr_vms; area++) {
+               if (vas)
+                       kfree(vas[area]);
+               if (vms)
+                       kfree(vms[area]);
+       }
+       kfree(vas);
+       kfree(vms);
+       return NULL;
+}
+
+/**
+ * pcpu_free_vm_areas - free vmalloc areas for percpu allocator
+ * @vms: vm_struct pointer array returned by pcpu_get_vm_areas()
+ * @nr_vms: the number of allocated areas
+ *
+ * Free vm_structs and the array allocated by pcpu_get_vm_areas().
+ */
+void pcpu_free_vm_areas(struct vm_struct **vms, int nr_vms)
+{
+       int i;
+
+       for (i = 0; i < nr_vms; i++)
+               free_vm_area(vms[i]);
+       kfree(vms);
+}
 
 #ifdef CONFIG_PROC_FS
 static void *s_start(struct seq_file *m, loff_t *pos)
index cd2b97f1b6e12a46ef57fd967051ca30da0ea00a..a6e0e077ac33481c9e19eb129a17f45a812929b0 100644 (file)
@@ -37,12 +37,13 @@ __initcall(init_syncookies);
 #define COOKIEBITS 24  /* Upper bits store count */
 #define COOKIEMASK (((__u32)1 << COOKIEBITS) - 1)
 
-static DEFINE_PER_CPU(__u32, cookie_scratch)[16 + 5 + SHA_WORKSPACE_WORDS];
+static DEFINE_PER_CPU(__u32 [16 + 5 + SHA_WORKSPACE_WORDS],
+                     ipv4_cookie_scratch);
 
 static u32 cookie_hash(__be32 saddr, __be32 daddr, __be16 sport, __be16 dport,
                       u32 count, int c)
 {
-       __u32 *tmp = __get_cpu_var(cookie_scratch);
+       __u32 *tmp = __get_cpu_var(ipv4_cookie_scratch);
 
        memcpy(tmp + 4, syncookie_secret[c], sizeof(syncookie_secret[c]));
        tmp[0] = (__force u32)saddr;
index 8c2513982b616d35d28d7c9df36ef1b440d57f66..6b6ae913b5d415bcf801a1ed0f21422d04b7f8a4 100644 (file)
@@ -74,12 +74,13 @@ static inline struct sock *get_cookie_sock(struct sock *sk, struct sk_buff *skb,
        return child;
 }
 
-static DEFINE_PER_CPU(__u32, cookie_scratch)[16 + 5 + SHA_WORKSPACE_WORDS];
+static DEFINE_PER_CPU(__u32 [16 + 5 + SHA_WORKSPACE_WORDS],
+                     ipv6_cookie_scratch);
 
 static u32 cookie_hash(struct in6_addr *saddr, struct in6_addr *daddr,
                       __be16 sport, __be16 dport, u32 count, int c)
 {
-       __u32 *tmp = __get_cpu_var(cookie_scratch);
+       __u32 *tmp = __get_cpu_var(ipv6_cookie_scratch);
 
        /*
         * we have 320 bits of information to hash, copy in the remaining
index 8d8488306fe4979374dad7ac05fbc4b8b1e3a67c..d2c904dd6fbcb9e1eeb275f84cc062a273bb98ec 100644 (file)
@@ -37,7 +37,7 @@
 #include "rds.h"
 #include "ib.h"
 
-DEFINE_PER_CPU(struct rds_ib_statistics, rds_ib_stats) ____cacheline_aligned;
+DEFINE_PER_CPU_SHARED_ALIGNED(struct rds_ib_statistics, rds_ib_stats);
 
 static const char *const rds_ib_stat_names[] = {
        "ib_connect_raced",
index d33ea790484ef24a43588543770e191429fa0c83..5fe67f6a1d8060f8312abf785a5631a68bec6d44 100644 (file)
@@ -37,7 +37,7 @@
 #include "rds.h"
 #include "iw.h"
 
-DEFINE_PER_CPU(struct rds_iw_statistics, rds_iw_stats) ____cacheline_aligned;
+DEFINE_PER_CPU_SHARED_ALIGNED(struct rds_iw_statistics, rds_iw_stats);
 
 static const char *const rds_iw_stat_names[] = {
        "iw_connect_raced",
index 55c21efdb62e09210784176b38dd369d4f7c856b..36790122dfd4c3cb869960ddb2141cd235973e16 100644 (file)
@@ -39,7 +39,7 @@ struct rds_page_remainder {
        unsigned long   r_offset;
 };
 
-DEFINE_PER_CPU(struct rds_page_remainder, rds_page_remainders) ____cacheline_aligned;
+DEFINE_PER_CPU_SHARED_ALIGNED(struct rds_page_remainder, rds_page_remainders);
 
 /*
  * returns 0 on success or -errno on failure.
diff --git a/scripts/module-common.lds b/scripts/module-common.lds
new file mode 100644 (file)
index 0000000..47a1f9a
--- /dev/null
@@ -0,0 +1,8 @@
+/*
+ * Common module linker script, always used when linking a module.
+ * Archs are free to supply their own linker scripts.  ld will
+ * combine them automatically.
+ */
+SECTIONS {
+       /DISCARD/ : { *(.discard) }
+}
index 4c865345caa01700451dd5aa7f8e290a2389690a..fb363cd81cf6db10753c69a3726c31143c3823b2 100644 (file)
@@ -113,6 +113,36 @@ config SECURITY_ROOTPLUG
 
          If you are unsure how to answer this question, answer N.
 
+config INTEL_TXT
+       bool "Enable Intel(R) Trusted Execution Technology (Intel(R) TXT)"
+       depends on HAVE_INTEL_TXT
+       help
+         This option enables support for booting the kernel with the
+         Trusted Boot (tboot) module. This will utilize
+         Intel(R) Trusted Execution Technology to perform a measured launch
+         of the kernel. If the system does not support Intel(R) TXT, this
+         will have no effect.
+
+         Intel TXT will provide higher assurance of system configuration and
+         initial state as well as data reset protection.  This is used to
+         create a robust initial kernel measurement and verification, which
+         helps to ensure that kernel security mechanisms are functioning
+         correctly. This level of protection requires a root of trust outside
+         of the kernel itself.
+
+         Intel TXT also helps solve real end user concerns about having
+         confidence that their hardware is running the VMM or kernel that
+         it was configured with, especially since they may be responsible for
+         providing such assurances to VMs and services running on it.
+
+         See <http://www.intel.com/technology/security/> for more information
+         about Intel(R) TXT.
+         See <http://tboot.sourceforge.net> for more information about tboot.
+         See Documentation/intel_txt.txt for a description of how to enable
+         Intel TXT support in a kernel boot.
+
+         If you are unsure as to whether this is required, answer N.
+
 config LSM_MMAP_MIN_ADDR
        int "Low address space for LSM to protect from user allocation"
        depends on SECURITY && SECURITY_SELINUX